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 ...
随机推荐
- smarty模板技术
一.什么是smarty?smarty是一个使用php写出来的模板php模板引擎,它提供了逻辑与外在内容的分离,简单的讲,目的就是要使用php程序员同美工分离,使用的程序员改变程序的逻辑内容不会影响到美 ...
- BZOJ 2038
基础不牢:补莫队算法: 莫队算法入门题: 2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 26 ...
- setTimeout(f, 0)的应用&利用Deferred实现队列运行
任务:从mongodb中导出csv数据,输出内容如下userid username usergender points points表: { "userid" : 1022, &q ...
- vim使用指北 ---- Global Replacement
一般替换 s/old/new --- 替换当前行的第一个匹配项 s/old/new/g ---- 替换当前行所有的匹配项 number1,number2-s/old/new/g ---- 替换从 ...
- vi/vim使用指北 ---- Beyond the Basic
更多的组合命令 [number]-[command]-[test object] number: 数字 comand: c,d,y (修改,删除,复制) test object: 移动光标的命 ...
- JSP 页面传参和接受参数
<%@ page language="java" contentType="text/html; charset=GBK" pageEncoding=&q ...
- 行列有序矩阵求第k大元素
问题来源:http://www.careercup.com/question?id=6335704 问题描述: Given a N*N Matrix. All rows are sorted, and ...
- ios图片拉伸两种方法
UIImage *image = [UIImage imageNamed:@"qq"]; 第一种: // 左端盖宽度 NSInteger leftCapWidth = image. ...
- Ado.Net要知道的东西
什么是ADO.NET? ADO.NET就是一组类库,这组类库可以让我们通过程序的方式访问数据库,就像System.IO下的类用类操作文件一样,System.Data.这组类是用来操作数据库(不光是MS ...
- ExtJs布局之BOX
<!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...