Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort data in QTableWidget?

Tags:

qt

I have a QTableWidget and the first column contains numbers from 1 to 1000. Now I need to sort the table based on this first column.

I'm using the function sortItems(int column, Qt::AscendingOrder), but it is displayed as:

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

Yet I need this result:

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

I'm using a CSV file for populating the table.

like image 819
Shyam Avatar asked Oct 21 '11 11:10

Shyam


4 Answers

The values are sorted as strings because you stored them as such in the model.

The QVariant can remember the original type of the data if you let it do the conversion itself, and the comparison operator from that type will be used when sorting:

// 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);    

The cell editor will also adapt to the type of the QVariant:

  • QSpinBox for int,
  • QDoubleSpinBox for double and float,
  • QDateTimeEdit for QDateTime
  • ...
like image 79
alexisdm Avatar answered Oct 23 '22 14:10

alexisdm


The easiest way is probably to subclass QTableWidgetItem and then implement the < operator to be smart about the fact that you're sorting numbers and not strings.

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

Then when you're populating your table you can pass it instances of your custom items that know how to sort themselves properly instead of the generic ones.

like image 34
Chris Avatar answered Oct 23 '22 14:10

Chris


One way that worked in my situation was

1) before filling the table, turn off sorting:

table.setSortingEnabled(False)

2) pad the number strings with blanks and make all strings in the column have the same length:

('    '+numStr)[-4:]

3) after filling the table, turn on sorting:

table.setSortingEnabled(True)

This fixed the row sorting problem and the numerical order.

like image 3
SoloPilot Avatar answered Oct 23 '22 15:10

SoloPilot


I don't know if the accepted answer used to work, but with Qt5.1, it doesn't. In order to work, the operator< definition has to match the virtual definition from qtablewidget.h.

Another interesting addition is to sort items that have numbers, but start with a currency sign ($ or for instance) or end with %.

Here is the updated code:

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();
    }
};

Then, you add the items that contain numbers using something like this:

myTableWidget->setItem(row, col, new TableNumberItem("$0"));

Note that this class must be used with numbers only, it will not sort strings correctly (as is also the case with the accepted answer).

like image 2
Sir Athos Avatar answered Oct 23 '22 13:10

Sir Athos