Qt之QHeaderView自定义排序(终极版)
2016-03-02 20:14
465 查看
简述
本节主要解决自定义排序衍生的第二个问题-将整形显示为字符串,而排序依然正常。下面我们介绍三种方案:
委托绘制
用户数据
辅助列
很多人也许会有疑虑,平时都用delegate来绘制各种按钮、图标、图形等操作,它还能排序?当然,它本身是不会排序的,但他的高级用法之一就是-辅助排序。
简述
委托绘制
效果
QStyledItemDelegate
眼见不一定为实
用户数据
QAbstractTableModel
QSortFilterProxyModel
辅助列
效果
QAbstractTableModel
QSortFilterProxyModel
隐藏辅助列
总结
委托绘制
效果
QStyledItemDelegate
我们可以通过设置显示的文本,然后调用QStyle的drawControl来进行ViewItem的绘制。绘制之后,数据源中的数据依然是qint64的,而我们看到的是绘制之后的文本-QString类型,这样QSortFilterProxyModel默认排序(根据源数据排序)就可以满足我们的要求了。void SortDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem viewOption(option); initStyleOption(&viewOption, index); if (option.state.testFlag(QStyle::State_HasFocus)) viewOption.state = viewOption.state ^ QStyle::State_HasFocus; // 进行大小转换 if (index.column() == FILE_SIZE_COLUMN) { qint64 bytes = index.data().toLongLong(); viewOption.text = bytesToGBMBKB(bytes) ; QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &viewOption, painter, viewOption.widget); } else { QStyledItemDelegate::paint(painter, viewOption, index); } }
眼见不一定为实
通过效果图我们也可以很明显的看出来,其实内部的数据并不是界面显示的字符串,而是原始的qint64类型的数据。pTableView->setMouseTracking(true); connect(pTableView, SIGNAL(entered(QModelIndex)), this, SLOT(showToolTip(QModelIndex))); void MainWindow::showToolTip(const QModelIndex &index) { if (!index.isValid()) return; int nColumn = index.column(); if ((nColumn == FILE_SIZE_COLUMN)) QToolTip::showText(QCursor::pos(), index.data().toString()); }
用户数据
QAbstractTableModel
显示在界面的数据为DisplayRole中的数据,我们可以看到已经通过bytesToGBMBKB转化为字符串,这时我们可以通过设置UserRole添加用户数据将源数据存储起来。// 表格项数据 QVariant TableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); int nRow = index.row(); int nColumn = index.column(); FileRecord record = m_recordList.at(nRow); switch (role) { case Qt::TextColorRole: return QColor(Qt::white); case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::DisplayRole: { if (nColumn == FILE_NAME_COLUMN) { return record.strFileName; } else if (nColumn == DATE_TIME_COLUMN) { return record.dateTime; } else if (nColumn == FILE_SIZE_COLUMN) { return bytesToGBMBKB(record.nSize); } return ""; } case Qt::UserRole: { // 新增代码 if (nColumn == FILE_SIZE_COLUMN) return record.nSize; } default: return QVariant(); } return QVariant(); }
QSortFilterProxyModel
根据用户源数据进行排序。bool SortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const { if (!source_left.isValid() || !source_right.isValid()) return false; if ((source_left.column() == FILE_SIZE_COLUMN) && (source_right.column() == FILE_SIZE_COLUMN)) { // 这里我们所取得数据是用户源数据 QVariant leftData = sourceModel()->data(source_left, Qt::UserRole); QVariant rightData = sourceModel()->data(source_right, Qt::UserRole); if (leftData.canConvert<qint64>() && rightData.canConvert<qint64>()) { return leftData.toLongLong() < rightData.toLongLong(); } } return QSortFilterProxyModel::lessThan(source_left, source_right); }
辅助列
效果
QAbstractTableModel
设置辅助数据#define FILE_NAME_COLUMN 0 // 文件名 #define DATE_TIME_COLUMN 1 // 修改日期 #define FILE_SIZE_COLUMN 2 // 文件大小 #define FILE_SIZE_HIDDEN_COLUMN 3 // 文件大小隐藏列,显示为字节 // 列数 int TableModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 4; } // 设置表格项数据 bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) return false; int nColumn = index.column(); FileRecord record = m_recordList.at(index.row()); switch (role) { case Qt::DisplayRole: { if (nColumn == FILE_NAME_COLUMN) { record.strFileName = value.toString(); } else if (nColumn == DATE_TIME_COLUMN) { record.dateTime = value.toDateTime(); } // 新增代码 else if ((nColumn == FILE_SIZE_COLUMN) || (nColumn == FILE_SIZE_HIDDEN_COLUMN)) { record.nSize = value.toLongLong(); } m_recordList.replace(index.row(), record); emit dataChanged(index, index); // 新增代码 if ((nColumn == FILE_SIZE_COLUMN) || (nColumn == FILE_SIZE_HIDDEN_COLUMN)) { int nSizeColumn = (nColumn == FILE_SIZE_COLUMN) ? FILE_SIZE_HIDDEN_COLUMN : FILE_SIZE_COLUMN; QModelIndex sizeIndex = this->index(index.row(), nSizeColumn); emit dataChanged(sizeIndex, sizeIndex); } return true; } default: return false; } return false; } // 表格项数据 QVariant TableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); int nRow = index.row(); int nColumn = index.column(); FileRecord record = m_recordList.at(nRow); switch (role) { case Qt::TextColorRole: return QColor(Qt::white); case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::DisplayRole: { if (nColumn == FILE_NAME_COLUMN) { return record.strFileName; } else if (nColumn == DATE_TIME_COLUMN) { return record.dateTime; } else if (nColumn == FILE_SIZE_COLUMN) { return bytesToGBMBKB(record.nSize); } // 新增代码 else if (nColumn == FILE_SIZE_HIDDEN_COLUMN) { return record.nSize; } return ""; } default: return QVariant(); } return QVariant(); } // 表头数据 QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const { switch (role) { case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::DisplayRole: { if (orientation == Qt::Horizontal) { if (section == FILE_NAME_COLUMN) return QStringLiteral("名称"); if (section == DATE_TIME_COLUMN) return QStringLiteral("修改日期"); if (section == FILE_SIZE_COLUMN) return QStringLiteral("大小"); // 新增代码 if (section == FILE_SIZE_HIDDEN_COLUMN) return QStringLiteral("大小(字节)"); } } default: return QVariant(); } return QVariant(); }
QSortFilterProxyModel
这里对第三列进行排序,因为第三列的数据是字符串(当然,也可以反转换),所以使用的辅助列数据,获取字节大小后进行对比。bool SortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const { if (!source_left.isValid() || !source_right.isValid()) return false; if ((source_left.column() == FILE_SIZE_COLUMN) && (source_right.column() == FILE_SIZE_COLUMN)) { // 获取辅助列索引 QModelIndex sizeLeftIndex = sourceModel()->index(source_left.row(), FILE_SIZE_HIDDEN_COLUMN); QModelIndex sizeRightIndex = sourceModel()->index(source_right.row(), FILE_SIZE_HIDDEN_COLUMN); QVariant leftData = sourceModel()->data(sizeLeftIndex); QVariant rightData = sourceModel()->data(sizeRightIndex); if (leftData.canConvert<qint64>() && rightData.canConvert<qint64>()) { return leftData.toLongLong() < rightData.toLongLong(); } } return QSortFilterProxyModel::lessThan(source_left, source_right); }
隐藏辅助列
一般来说,辅助列(数据)只对我们处理数据有帮助,而不直接显示在界面上,所以我们可以将其隐藏pTableView->setColumnHidden(FILE_SIZE_HIDDEN_COLUMN, true);总结
小小一个排序居然也有这么多门道,真是条条大路通罗马,通过这几节的分享,想必大家对排序有了更深入的了解,更多的知识请参考官方文档。相关文章推荐
- QT学习 第一章:基本对话框
- 使用Shiboken为C++和Qt库创建Python绑定
- Qt 5.6更新至RC版,最终版本近在咫尺
- Qt定时器和随机数详解
- Qt实现图片移动实例(图文教程)
- C语言中qsort函数用法实例小结
- Qt for Android开发实例教程
- QModelIndex/Role/Model介紹<二>
- 基于PyQt5的快速开发框架QFramer
- OSX下安装PyQt
- ok6410开发板移植DirectFB手记
- 【笔记】给Qt内嵌一个Chrome吧
- 【算法】最短路径之A*搜索
- qt入门必备
- 在 Qt4 中使用 C++11
- Hello Word ~ v0.2.2 背单词软件发布 -- By WHYPRO
- ubuntu下opencv和qt的安装配置
- linux下opengl的安装(with qt)
- qt 学习小节
- QT编译时Cannot find -lGL