Qt之 QTableWidget 列排序

1、常规的QTableWidget的排序接口

void QTableView::setSortingEnabled(bool enable)  // 允许点击表头进行排序
void QTableWidget::sortItems(int column, Qt::SortOrder order = Qt::AscendingOrder)  // 排序接口
table->setSortingEnabled(true);  	// 运行排序
table->sortItems(0);				// 对 0 列排序, 默认升序

2、含有数字字符的字符串排序

常规的排序是以QString序进行排序,也就是u16序,如下图:

对于混杂有数字的字符串排序如上图,就不太符合人的认知。

对于混合有数字的排序,需要重写 QTableWidgetItem的比较函数 operator<():

bool QTableWidgetItem::operator<(const QTableWidgetItem &other) const

所以自定义排序则需要扩展QTableWidgetItem,自定义字符串排序算法很好写,但是不需要。因为Qt自身提供了一个十分方便的类 :QCollator

virtual bool operator<(const QTableWidgetItem& other) const override
    QCollator collator;
    collator.setNumericMode(true);
    auto ret = collator.compare(this->text(), other.text());
    if (ret < 0)
        return true;
        return false;

3、保存原始序

在构造item的时候,顺便保存行号为原始序

item = new ATableWidgetItem;
item->setData(ATableWidgetItem::OriginSort,0);  // 保存原始序

使用一个 flag 来控制排序

virtual bool operator<(const QTableWidgetItem& other) const override
    if (sortToOrigin) {
        return this->data(OriginSort).toInt() < other.data(OriginSort).toInt();
    } else {
        QCollator collator;
        collator.setNumericMode(true);
        auto ret = collator.compare(this->text(), other.text());
        if (ret < 0)
            return true;
            return false;

完整Demo

#include <QDebug>
#include <QLocale>
#include <QRandomGenerator>
#include <QtWidgets>
#define qout qDebug() << __FILE__ << __LINE__
#define qrand QRandomGenerator::global()
QStringList testStr = { "hello" };
 * @brief 扩展 QTableWidgetItem 类, 重写 operator<() 函数
class ATableWidgetItem : public QTableWidgetItem {
public:
    using QTableWidgetItem::QTableWidgetItem; // 继承构造
    enum {
        OriginSort = Qt::UserRole + 1
public:
    virtual bool operator<(const QTableWidgetItem& other) const override
        if (sortToOrigin) {
            return this->data(OriginSort).toInt() < other.data(OriginSort).toInt();
        } else {
            QCollator collator;
            collator.setNumericMode(true);
            auto ret = collator.compare(this->text(), other.text());
            if (ret < 0)
                return true;
                return false;
    static bool sortToOrigin; // 声明原始序标志
bool ATableWidgetItem::sortToOrigin = false; // 定义原始序标志
int main(int argc, char* argv[])
    QApplication a(argc, argv);
    QWidget w;
    auto HBox = new QHBoxLayout(&w);
    auto table = new QTableWidget;
    HBox->addWidget(table);
    auto btn = new QPushButton("显示表格原始序");
    HBox->addWidget(btn);
    auto row = 5, col = 3;
    table->setRowCount(row);
    table->setColumnCount(col);
    for (int i = 0; i < row; ++i) {
        for (int j = 0; j < col; ++j) {
            auto* item = table->item(i, j);
            if (!item) {
                item = new ATableWidgetItem;
                //                item = new QTableWidgetItem;
                table->setItem(i, j, item);
                if (j == 0)
                    item->setData(ATableWidgetItem::OriginSort, i);
            auto txt = testStr[qrand->bounded(testStr.length())]
                + "_"
                + QString::number(qrand->bounded(20)) + "_world";
            item->setText(txt);
    table->setSortingEnabled(true);
    QObject::connect(btn, &QPushButton::clicked, [&] {
        ATableWidgetItem::sortToOrigin = true;
        table->sortItems(0);
        table->horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder);
        ATableWidgetItem::sortToOrigin = false;
    });
    w.resize(500, 300);
    w.show();
    return a.exec();
重写QTableWidgetItem的
1.重写:bool QTableWidgetItem::operator<(const QTableWidgetItem& other) const		
2.点击表头进行排序:connect(ui.tableWidget->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(slotHeaderClicked(int)));
3.使用sortByCo.
                                    4. ui->tableWidget->setSortingEnabled(true)  设置表格自动排序。1. ui->tableWidget->setSortingEnabled(false) 设置不排序。该现象属于 Qt QTableWidget 自身问题;
                                    1QTablewidget自动排序
Qtablewidget自带的有排序函数,点击表头可以进行某一行/进行大小排序,但该函数仅限于静态表格数据,如果是定时刷新的表格数据,下一次刷新后就会恢复之前的非排序状态,如果想点击一次后,后面实时刷新的数据也按排序效果,那么需要重新写排序函数。
2.我是数据在QMAP中,对Qmap进行了排序,这样点击一次后,后面就可以一直按照大小排序了,而且是多同时联动排序。
                                    在上述示例代码中,首先创建了一个 QTableWidget 对象,并设置了数和行数。然后使用 setSortIndicator() 函数设置了默认的排序指示器的状态,这里设置第一为升序排序。在 QtQTableWidget 中,默认情况下,是不可排序的。但是你可以通过设置 QHeaderView 的 setSortIndicator() 函数来实现排序功能。通过以上步骤,你可以使 QTableWidget排序。请注意,这只会在用户点击表头时触发排序,而不是在代码中自动触发排序。
                                    在开发过程中,我们需要通过点击表头来对QTableView或QTreeView等一系高级视图进行排序操作,以下是进行排序的步骤。首先创建了一个QStandardItemModel对象或者继承QAbstractTableModel类作为数据模型,并设置了一些数据。然后创建一个QTableView对象,并将数据模型设置为其模型。接下来,创建一个QSortFilterProxyModel对象,并将QStandardItemModel对象设置为其源模型。然后设置QTableView开启排序功能。
ui->tableView->sortByColumn(0,Qt::AscendingOrder);  
但只对 QTableView 进行设置还不能生效,需要借助QAbstractItemModel 类的 sort 接口(需要重写 sort 接口进行排序),或者借助QSortFilterProxy...
                                    QT Creator中,QTableWidget的使用非常频繁,很多场合都需要使用表格并按照一定的需求进行排序。表格中的数据类型可以是数字,字符,汉字,日期,时间等。本文简单给出介绍对QTablewidget进行汉字和QDatetime类型进行排序的方式,主要使用qSort函数,且不涉及重写QTablewidgetItem类。
                                    本文介绍了QT中的几种常用的排序函数,包括qSort,qStableSort,qPartialSort,qHeapSort,qLowerBound和qUpperBound,它们可以对QT中的一些容器类中的元素进行排序或者查找。qSort函数是一个通用的排序函数,它使用快速排序算法,可以对任何可随机访问的序进行排序。它的优点是,它的平均时间复杂度是O(nlogn),空间复杂度是O(logn),效率较高。它的缺点是,它的最坏情况下的时间复杂度是O(n^2),效率较低。
                                    QTableWidget排序功能
(1)、注意默认是按照文本方式来排序的,对于想要数据排序的设置如下:
方法一:设置QTableWidgetItem的setData方法,第一个参数是Qt::EditRole,
	int value = 20;
	QTableWidgetItem *item = new QTableWidgetItem;
	//这样设置,排序是按照数字来排
	item->setData(Qt::UserRole,value);
方法一有一个问题,当double数据太长时,数据类型会自
                                    PyQt5中的QTableWidget 是按照string类型进行排序的,所以遇到数字或数字和字符混合的情况,排序的结果就和预期不太一样,这里记录下如何解决此问题。