本文共 7585 字,大约阅读时间需要 25 分钟。
本节主要解决自定义排序衍生的第二个问题-将整形显示为字符串,而排序依然正常。
下面我们介绍三种方案:
很多人也许会有疑虑,平时都用delegate来绘制各种按钮、图标、图形等操作,它还能排序?当然,它本身是不会排序的,但他的高级用法之一就是-辅助排序。
我们可以通过设置显示的文本,然后调用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());}
显示在界面的数据为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();}
根据用户源数据进行排序。
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() && rightData.canConvert ()) { return leftData.toLongLong() < rightData.toLongLong(); } } return QSortFilterProxyModel::lessThan(source_left, source_right);}
设置辅助数据
#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();}
这里对第三列进行排序,因为第三列的数据是字符串(当然,也可以反转换),所以使用的辅助列数据,获取字节大小后进行对比。
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() && rightData.canConvert ()) { return leftData.toLongLong() < rightData.toLongLong(); } } return QSortFilterProxyModel::lessThan(source_left, source_right);}
一般来说,辅助列(数据)只对我们处理数据有帮助,而不直接显示在界面上,所以我们可以将其隐藏pTableView->setColumnHidden(FILE_SIZE_HIDDEN_COLUMN, true);
小小一个排序居然也有这么多门道,真是条条大路通罗马,通过这几节的分享,想必大家对排序有了更深入的了解,更多的知识请参考官方文档。