Venkata Narsi Reddy Vaddula Venkata Narsi Reddy Vaddula - 1 month ago 14
Python Question

PyQt: How to sort QTableView columns(strings and numericals)

The line

self.tableView.setSortingEnabled(True)
sorts a table view when clicking on the header, but it sorts incorrectly. That is, it thinks every column is a string (e.g. it sorts numbers like
1,11,12,2,22,3
, etc). How do I correct this?

My code:

self.model = QtGui.QStandardItemModel()

with open(file_name_temp, "rt") as fileInput:
i = 1
for row in csv.reader(fileInput):
item = QtGui.QStandardItem()
for field in row:
items = [
item.setData(field, QtCore.Qt.UserRole)
]
print(items)
self.model.appendRow(items)

tab_table_view = QtGui.QWidget()
self.Tab.insertTab(0, tab_table_view, self.File_Name)
self.tableView = QtGui.QTableView(tab_table_view)
self.tableView.setGeometry(QtCore.QRect(0, 0, 721, 571))
self.model = QtGui.QStandardItemModel(self)
self.tableView.setModel(self.model)
colll = self.Datas.dtypes.index
col_names = np.array(colll)
col_names = np.insert(col_names, 0, self.Datas.index.name)
self.model.setHorizontalHeaderLabels(col_names)
self.tableView.hideRow(0)
self.model.setSortRole(QtCore.Qt.UserRole)

Answer

You don't show how you are creating the items for the model, but presumably you are doing something like this:

item = QtGui.QStandardItem(str(value))

where value is a python numeric type.

To get numeric sorting, set the values like this instead:

item = QtGui.QStandardItem()
item.setData(value, QtCore.Qt.DisplayRole)

But note that this will also make the table automatically use spin-boxes for editing cells, which you may not want. So an alternative solution would be:

item = QtGui.QStandardItem(str(value))
item.setData(value, QtCore.Qt.UserRole)
...
model.setSortRole(QtCore.Qt.UserRole)

Finally, for fully customised sorting, you can also subclass QStandardItem:

class StandardItem(QtGui.QStandardItem):
    def __lt__(self, other):
        return int(self.text()) < int(other.text())

item = StandardItem(str(value))

UPDATE:

Here is a solution for your own example:

numeric_columns = {2, 3, 5, 8} # change as necessary    
with open(file_name_temp, "rt") as fileInput:
    for row in csv.reader(fileInput):
        items = []
        for index, field in enumerate(row):
            item = QtGui.QStandardItem(field)
            if index in numeric_columns:
                data = int(field)
            else:
                data = field
            item.setData(data, QtCore.Qt.UserRole)
            items.append(item)            
        self.model.appendRow(items)
Comments