简述

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

下面我们介绍三种方案:

  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<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自定义排序(终极版)的更多相关文章

  1. Qt之QHeaderView自定义排序(获取正确的QModelIndex)

    简述 前几节中分享过关于自定义排序的功能,貌似我们之前的内容已经可以很好地解决排序问题了,但是,会由此引发一些很难发现的问题...比如:获取QModelIndex索引错误. 下面,我们先来实现一个整行 ...

  2. Qt之QHeaderView自定义排序(QSortFilterProxyModel)

    简述 对以上节的排序,我们衍伸了两点: 把一个字符串前面的数据按照字符串比较,而后面的数据按照整形比较. 将整形显示为字符串,而排序依然正常呢. 为了分别描述,这里我们先解决问题1. 简述 效果 处理 ...

  3. Android Studio 快捷键(包含自定义)终极版

      [F] [F] F2 在错误代码之间切换 F3 往前定位(Shift + F3:往后定位 )有问题 F4\Ctrl+鼠标点击\Ctrl+B 转到定义,查看类继承关系 F5 但不调试进入函数内部. ...

  4. 终极版Servlet——我只能提示您路过别错过

    终极版Servlet 前言:这两天看了SSM框架,本来是想往后继续学的,脑门一转又回来了,不能就这么不声不响的走了,看了这么多天的Servlet,再写最后一篇做个告别吧,这篇起名为终极版,是我现在所能 ...

  5. Python应用——自定义排序全套方案

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天的这篇文章和大家聊聊Python当中的排序,和很多高级语言一样,Python封装了成熟的排序函数.我们只需要调用内部的sort函数,就可 ...

  6. Java集合框架实现自定义排序

    Java集合框架针对不同的数据结构提供了多种排序的方法,虽然很多时候我们可以自己实现排序,比如数组等,但是灵活的使用JDK提供的排序方法,可以提高开发效率,而且通常JDK的实现要比自己造的轮子性能更优 ...

  7. DataTable自定义排序

    使用JQ DataTable 的时候,希望某列数据可以进行自定义排序,操作如下:(以中文排序和百分比排序为例) 1:定义排序类型: //百分率排序 jQuery.fn.dataTableExt.oSo ...

  8. 干货之UICollectionViewFlowLayout自定义排序和拖拽手势

    使用UICollectionView,需要使用UICollectionViewLayout控制UICollectionViewCell布局,虽然UICollectionViewLayout提供了高度自 ...

  9. DataGridView 绑定List集合后实现自定义排序

    这里只贴主要代码,dataList是已添加数据的全局变量,绑定数据源 datagridview1.DataSource = dataList,以下是核心代码. 实现点击列表头实现自定义排序 priva ...

随机推荐

  1. sublime 配置C++

    1. 安装C语言编译器MinGW,并把MinGW安装目录下的bin目录添加到环境变量PATH里.详细方法参照MinGW安装和使用 2. 在SublimeText安装目录下的Data\Packages\ ...

  2. YARN应用程序的开发步骤

    开发基于YARN的应用程序需要开发客户端程序和AppMaster程序: 我们基于程序自带的例子来实现提交application 到YARN的ResourceManger. Distributed Sh ...

  3. JAVA非空条件三元运算符

    //非空情况处理: // Integer holidayPrice = order.get("holidayPrice")!=null?Integer.valueOf(String ...

  4. flashdevelop 开发技巧

    FlashDevelop用来编写AS3代码,Flash CS5用来编辑程序所需要的资源(图片,声音-),Flash CS5自带有Flex SDK,在目录 C:\Program Files\Adobe\ ...

  5. Java开发WebService的几种方法--转载

    webservice的应用已经越来越广泛了,下面介绍几种在Java体系中开发webservice的方式,相当于做个记录. 1.Axis2 Axis是apache下一个开源的webservice开发组件 ...

  6. iOS导航栏-关闭半透明

    self.navigationController.navigationBar.translucent = NO;

  7. 思考 ”前端开发人员都在关注的 GitHub 资源“

    点这里 原文: 资源 免费的计算机编程类中文书籍 免费编程书籍 计算机科学论文 codeparkshare Python初学者书籍.视频.资料.社区推荐 Python资料汇总 app应用推荐 码农周刊 ...

  8. POJ 1656

    #include<iostream>//chengdacaizi 08 .11. 12 #include<string> using namespace std; ][]={} ...

  9. ExtJs之Ext.isEmpty

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  10. [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望

    发布日期:2009.05.22 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文开始,将以& ...