博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Qt之QHeaderView自定义排序(终极版)
阅读量:6225 次
发布时间:2019-06-21

本文共 7585 字,大约阅读时间需要 25 分钟。

简述

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

下面我们介绍三种方案:

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

很多人也许会有疑虑,平时都用delegate来绘制各种按钮、图标、图形等操作,它还能排序?当然,它本身是不会排序的,但他的高级用法之一就是-辅助排序。

委托绘制

效果

这里写图片描述

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() < 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
() && rightData.canConvert
()) { return leftData.toLongLong() < rightData.toLongLong(); } } return QSortFilterProxyModel::lessThan(source_left, source_right);}

隐藏辅助列

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

总结

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

你可能感兴趣的文章
PMP考试的过与只是
查看>>
java 监控 收集资料3(收集中)
查看>>
实例演示如何使用AgileEAS.NET SOA平台工作流进行业务流程自定义
查看>>
Spring Cloud Alibaba迁移指南(二):零代码替换 Eureka
查看>>
聊聊BOM的那些事
查看>>
Apache Pulsar中的地域复制,第1篇:概念和功能
查看>>
getRealPath()和getContextPath()的区别
查看>>
Hadoop MapReduce编程 API入门系列之wordcount版本2(六)
查看>>
一个页面标题和过滤输出的解决方案(上)
查看>>
解决windows使用rsync同步到Linux权限问题
查看>>
python pip install 出现 OSError: [Errno 1] Operation not permitted
查看>>
【九度OJ1367】|【剑指offer24】二叉搜索树的后序遍历序列
查看>>
android4.4以上透明状态栏简单设置
查看>>
双十一流量洪峰 支撑阿里核心业务的云数据库揭秘
查看>>
oracle12C 重做日志
查看>>
数据结构与算法4
查看>>
Metasploit 之 modules 与plugins 区别
查看>>
mysql的常用函数
查看>>
完善的复数类(二十五)
查看>>
java书籍列表
查看>>