Qt之QHeaderView自定义排序(终极版)
简述
本节主要解决自定义排序衍生的第二个问题-将整形显示为字符串,而排序依然正常。
下面我们介绍三种方案:
- 委托绘制
- 用户数据
- 辅助列
很多人也许会有疑虑,平时都用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<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之QHeaderView自定义排序(终极版)的更多相关文章
- Qt之QHeaderView自定义排序(获取正确的QModelIndex)
简述 前几节中分享过关于自定义排序的功能,貌似我们之前的内容已经可以很好地解决排序问题了,但是,会由此引发一些很难发现的问题...比如:获取QModelIndex索引错误. 下面,我们先来实现一个整行 ...
- Qt之QHeaderView自定义排序(QSortFilterProxyModel)
简述 对以上节的排序,我们衍伸了两点: 把一个字符串前面的数据按照字符串比较,而后面的数据按照整形比较. 将整形显示为字符串,而排序依然正常呢. 为了分别描述,这里我们先解决问题1. 简述 效果 处理 ...
- Android Studio 快捷键(包含自定义)终极版
[F] [F] F2 在错误代码之间切换 F3 往前定位(Shift + F3:往后定位 )有问题 F4\Ctrl+鼠标点击\Ctrl+B 转到定义,查看类继承关系 F5 但不调试进入函数内部. ...
- 终极版Servlet——我只能提示您路过别错过
终极版Servlet 前言:这两天看了SSM框架,本来是想往后继续学的,脑门一转又回来了,不能就这么不声不响的走了,看了这么多天的Servlet,再写最后一篇做个告别吧,这篇起名为终极版,是我现在所能 ...
- Python应用——自定义排序全套方案
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天的这篇文章和大家聊聊Python当中的排序,和很多高级语言一样,Python封装了成熟的排序函数.我们只需要调用内部的sort函数,就可 ...
- Java集合框架实现自定义排序
Java集合框架针对不同的数据结构提供了多种排序的方法,虽然很多时候我们可以自己实现排序,比如数组等,但是灵活的使用JDK提供的排序方法,可以提高开发效率,而且通常JDK的实现要比自己造的轮子性能更优 ...
- DataTable自定义排序
使用JQ DataTable 的时候,希望某列数据可以进行自定义排序,操作如下:(以中文排序和百分比排序为例) 1:定义排序类型: //百分率排序 jQuery.fn.dataTableExt.oSo ...
- 干货之UICollectionViewFlowLayout自定义排序和拖拽手势
使用UICollectionView,需要使用UICollectionViewLayout控制UICollectionViewCell布局,虽然UICollectionViewLayout提供了高度自 ...
- DataGridView 绑定List集合后实现自定义排序
这里只贴主要代码,dataList是已添加数据的全局变量,绑定数据源 datagridview1.DataSource = dataList,以下是核心代码. 实现点击列表头实现自定义排序 priva ...
随机推荐
- 服务接口API限流 Rate Limit
一.场景描述 很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统. 也就是面对大流量时,如何进行流量控制? 服务接口的流量 ...
- acdream1116 Gao the string!(hash二分 or 后缀数组)
问题套了一个斐波那契数,归根结底就是要求对于所有后缀s[i...n-1],所有前缀在其中出现的总次数.我一开始做的时候想了好久,后来看了别人的解法才恍然大悟.对于一个后缀来说 s[i...n-1]来说 ...
- HDU 2602 Bone Collector (简单01背包)
Bone Collector http://acm.hdu.edu.cn/showproblem.php?pid=2602 Problem Description Many years ago , i ...
- 有用的一些web网站
1.http://www.aseoe.com/api-download/download.html 爱思资源网
- HADOOP NAMENODE对Image和edits的处理
1.SNN CheckPoint的处理流程 配置中配置做CheckPoint的两个条件,一个是文件大小editlog大于多大就做,另一个是时间维度,多长时间做一次. (1)SNN首先检查是否需要进行c ...
- Java-马士兵设计模式学习笔记-观察者模式-AWT简单例子
1.AWT简单例子 TestFrame.java import java.awt.Button; import java.awt.Frame; import java.awt.event.Action ...
- 更新SDK后ADT版本低不支持
在android_sdk_windows/tools/lib下的plugin.prop文件里被变更为 # begin plugin.prop plugin.version=21.1.0 # end p ...
- 本博客不再更新,欢迎访问本人托管在GitHub上的博客:www.wshunli.com
本博客不再更新. 欢迎访问本人托管在GitHub上的博客:www.wshunli.com
- Help Jimmy--poj1661(dp)
题目链接:http://poj.org/problem?id=1661 下图是左边的,右边的同理: #include<stdio.h> #include<string.h> # ...
- 《MySQL悲观锁总结和实践》乐观锁
mysql乐观锁总结和实践 博客分类: MyBatis 数据库 mysql数据库乐观锁悲观锁 上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景 ...