热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Qt之QHeaderView自定义排序(终极版)

简述本节主要解决自定义排序衍生的第二个问题-将整形显示为字符串,而排序依然正常。下面我们介绍三种方案:委托绘制用户数据辅助列很多人也许会有疑虑ÿ

简述

本节主要解决自定义排序衍生的第二个问题-将整形显示为字符串,而排序依然正常。

下面我们介绍三种方案:

  1. 委托绘制
  2. 用户数据
  3. 辅助列

很多人也许会有疑虑,平时都用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() && rightData.canConvert()){return leftData.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() && rightData.canConvert()){return leftData.toLongLong() return QSortFilterProxyModel::lessThan(source_left, source_right);
}

隐藏辅助列

一般来说,辅助列(数据)只对我们处理数据有帮助,而不直接显示在界面上,所以我们可以将其隐藏pTableView->setColumnHidden(FILE_SIZE_HIDDEN_COLUMN, true);

总结

小小一个排序居然也有这么多门道,真是条条大路通罗马,通过这几节的分享,想必大家对排序有了更深入的了解,更多的知识请参考官方文档。


转:https://www.cnblogs.com/itrena/p/5938373.html



推荐阅读
author-avatar
雨雾1989_153
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有