Learn Qt Custom Sorting (Three Ways)

Sorting Overview

Sorting happens a lot in qt viewports like list, table and tree. Using convenience class such as item-based widget provides limited sorting options.

One common thing may occur when we are sorting items is the widget treats their value as string instead of int, which will result incorrect ordering

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
list = ["3", "1", "2", "20", "92", "89", "40", "10", "11"]

if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
mywidget = QtWidgets.QTableWidget()
mywidget.insertColumn(0)

for index in range(len(list)):
mywidget.insertRow(index)
value = list[index]
item = QtWidgets.QTableWidgetItem(value)
mywidget.setItem(index, 0, item)

mywidget.sortItems(0, QtCore.Qt.AscendingOrder)
mywidget.show()
sys.exit(app.exec_())

This will sort the list of items based on their string, so the order will be:

1
2
3
4
- 1
- 10
- 11
- 2

instead of

1
2
3
- 1
- 2
- ...

So naturally, we would need to specify the item value as integer type, but we cannot instantiate item with integer, but setData() will work

1
2
3
4
# intead of 
item = QtWidgets.QTableWidgetItem(int(value))
# do this
item.setData(QtCore.Qt.ItemDataRole, int(value))

Now everything will sort by numeric order

Custom Sorting (Operator override)

What if we need more than numeric value for our data, for example, when displaying frame number, we would like to include frame range too. Like frame 1, frame 2, frame 3-7, frame 8, frame 9-14. It looks like using string is the only option.

This time we need to override value compare operator for these value, that is making our own item class like the following example

the __lt__ is the less than operator (<)

Everything should behave correctly

Custom Sorting (QSortFilterProxyModel Class)

https://doc-snapshots.qt.io/qtforpython-5.15/PySide2/QtCore/QSortFilterProxyModel.html

Reference

Stack Overflow - Is it possible to sort numbers in a QTreeWidget column?