如何在QTableWidget中对数据进行排序?

19

我有一个 QTableWidget,其中第一列包含从1到1000的数字。现在我需要根据这个第一列对表格进行排序。

我正在使用函数sortItems(int column, Qt::AscendingOrder),但它显示为:

1,10,100,1000,101,102,......

然而我需要以下结果:

1,2,3,4,......,1000。

我正在使用CSV文件填充表格。


那不是一个问题。它是一个带问号的名词短语。 - CodeLurker
5个回答

29

因为你在模型中存储了字符串,所以这些值被当作字符串进行排序。

QVariant 可以记住数据的原始类型,如果你让它自己进行转换,那么将会使用该类型的比较运算符进行排序:

// Get the value from the CSV file as a numeric type
int valueFromCsvFile = ...;

// don't do this
QTableWidgetItem *item = new QTableWidgetItem(QString::number(valueFromCsvFile));

// but do this instead
QTableWidgetItem *item = new QTableWidgetItem;
item.setData(Qt::EditRole, valueFromCsvFile);    

单元格编辑器还会根据QVariant的类型进行适应:

  • QSpinBox 用于 int
  • QDoubleSpinBox 用于 doublefloat
  • QDateTimeEdit 用于 QDateTime
  • ...

我使用了'item.setData(Qt :: EditRole,valueFromCsvFile)',现在它运行良好。 - Shyam
1
@Shyam,为什么不将此设置为被接受的答案呢?我遇到这个问题是因为我正在使用long int,并且奇怪的是QVariant将适用于long long int或int,但不适用于long int。将我的long int强制转换为qlonglong对我有用。 - M_M
2
这应该是被接受的答案,它比其他答案简单得多! - Spencer
无法与表格的默认排序一起工作,即尝试通过点击标题箭头进行排序时。 - Elad Weiss

16

最简单的方法可能是继承QTableWidgetItem并实现运算符<,以便在排序时智能地处理数字而不是字符串。

class MyTableWidgetItem : public QTableWidgetItem {
    public:
        bool operator <(const QTableWidgetItem &other) const
        {
            return text().toInt() < other.text().toInt();
        }
};

然后,在填充表格时,您可以传递自定义项的实例,这些实例知道如何正确排序,而不是使用通用项。


谢谢,这个可行。在较新版本的Qt中,签名略有更改为bool operator< ( const QTableWidgetItem & other ) const - iliis
如果 setData(Qt::DisplayRole, num) 对你不起作用,那么你应该尝试这个。 - Wesley

2
我不知道被接受的答案以前是否有效,但在Qt5.1中,它已经失效了。为了使其工作,operator<的定义必须与qtablewidget.h中的虚拟定义相匹配。
另一个有趣的补充是对具有数字但以货币符号(例如$)开头或以%结尾的项目进行排序。
以下是更新后的代码:
class TableNumberItem : public QTableWidgetItem
{
public:
    TableNumberItem(const QString txt = QString("0"))
        :QTableWidgetItem(txt)
    {
    }

    bool operator < (const QTableWidgetItem &other) const
    {
        QString str1 = text();
        QString str2 = other.text();

        if (str1[0] == '$' || str1[0] == '€') {
            str1.remove(0, 1);
            str2.remove(0, 1); // we assume both items have the same format
        }

        if (str1[str1.length() - 1] == '%') {
            str1.chop(1);
            str2.chop(1); // this works for "N%" and for "N %" formatted strings
        }

        double f1 = str1.toDouble();
        double f2 = str2.toDouble();

        return str1.toDouble() < str2.toDouble();
    }
};

然后,您可以使用以下类似的方法添加包含数字的项:
myTableWidget->setItem(row, col, new TableNumberItem("$0"));

请注意,此类只能用于数字,它不能正确排序字符串(与被接受的答案一样)。请注意,此类必须仅与数字一起使用,否则无法正确排序字符串。

2

在我遇到的情况下,有效的一种方法是:

1)在填充表格之前,关闭排序功能:

table.setSortingEnabled(False)

2) 在数字字符串两侧填充空格,使列中的所有字符串具有相同的长度:

('    '+numStr)[-4:]

3) 在填写表格后,开启排序功能:

table.setSortingEnabled(True)

这解决了行排序问题和数字顺序。

0

我遇到了同样的问题,@Chris的答案对我有用!但需要做一点修改。我无法评论,所以在这里写。

   class MyTableWidgetItem : public QTableWidgetItem {
    public:
        bool operator <(const QTableWidgetItem &other) const
        {
            if (text()=="")
                return text().toDouble() > other.text().toDouble();
            else
                return text().toDouble() < other.text().toDouble();
        }
    };

这没有意义。如果 text() 是空的,那么 text().toDouble() 返回 -1.0,而你可能期望的是 0.0。你应该检查具体的数字,而不是更改运算符。此外,如果你期望 text() 为空,那么 other.text() 也可能为空。 - Alexis Wilke
我认为空单元格是空的,不需要排序。对于所有正数包括0,这对我有效。 - M.Hu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接