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.
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
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.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With