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

csv, excel, pyqt4, qtableview, sorting

Solution

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 demo script that reads csv files into a table, automatically converting the fields into the correct data-type for sorting:

import sys, csv
from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.model = QtGui.QStandardItemModel(self)
        self.model.setSortRole(QtCore.Qt.UserRole)
        self.tableView = QtGui.QTableView()
        self.tableView.setSortingEnabled(True)
        self.tableView.setModel(self.model)
        self.button = QtGui.QPushButton('Open CSV', self)
        self.button.clicked.connect(self.handleButton)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.tableView)
        layout.addWidget(self.button)

    def handleButton(self):
        path = QtGui.QFileDialog.getOpenFileName(
            self, 'Open CSV', '', 'CSV files (*.csv *.txt)')
        if path:
            self.model.setRowCount(0)
            with open(path) as stream:
                reader = csv.reader(stream)
                next(reader, None)
                for row in reader:
                    items = []
                    for field in row:
                        item = QtGui.QStandardItem(field)
                        for numtype in (int, float):
                            try:
                                data = numtype(field)
                                break
                            except (ValueError, OverflowError):
                                pass
                        else:
                            print('Not a number: %r' % field)
                            data = field
                        item.setData(data, QtCore.Qt.UserRole)
                        items.append(item)
                    self.model.appendRow(items)

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 150, 600, 400)
    window.show()
    sys.exit(app.exec_())

Problem

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) ``` Update 1: ``` if (".csv" or ".txt") in self.File_Name: with open(file_name_temp, "rt") as fileInput: i = 1 reader = csv.reader(fileInput) next(reader, None) for row in reader: for x in range(0,Num_col+1): try: int(row[x]) row[x]=int(row[x]) except ValueError: print('Not Int') items = [] for field in row: item = QtGui.QStandardItem(field) if type(field)==int: print('yyy') data = int(field) else: data = field item.setData(data, QtCore.Qt.UserRole) items.append(item) print(items) self.model.appendRow(items) ``` gives the output as: ``` yyy yyy yyy yyy yyy yyy yyy yyy yyy [<PyQt4.QtGui.QStandardItem object at 0x0000000006DF3948>, <PyQt4.QtGui.QStandardItem object at 0x0000000006DF38B8>, <PyQt4.QtGui.QStandardItem object at 0x0000000006DF3828>, <PyQt4.QtGui.QStandardItem object at 0x0000000006DF3798>, <PyQt4.QtGui.QStandardItem object at 0x0000000006DF3678>, <PyQt4.QtGui.QStandardItem object at 0x0000000006DF3EE8>, <PyQt4.QtGui.QStandardItem object at 0x0000000006DF3F78>, <PyQt4.QtGui.QStandardItem object at 0x00000000095D4048>, <PyQt4.QtGui.QStandardItem object at 0x00000000095D40D8>] ``` everything seems good in console but on the GUI window it does not show the table?

Original source