3

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?

learncode
  • 1,105
  • 4
  • 18
  • 36

1 Answers1

4

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_())
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • 1
    I have now posted how the items are declared. now can you help me? – learncode Oct 28 '16 at 18:34
  • 1
    @VenkataNarsiReddyVaddula. The model has the `setSortRole` method. You can create the items in any of the three different ways I showed. The items certainly do have a `setData` method - you must be doing something wrong, somehow. – ekhumoro Oct 28 '16 at 19:48
  • 1
    Yes, it has that, but I am still not able to sort the data as I am appending the entire row at he same time to the QTableView, I have updated the code now can you help me? – learncode Oct 28 '16 at 19:52
  • 1
    @VenkataNarsiReddyVaddula. Use an inner loop to create the items one by one, and append them to a list for each row. Do **all** your columns contain numeric data? – ekhumoro Oct 28 '16 at 19:58
  • 1
    @VenkataNarsiReddyVaddula. I've updated the code in your question. I've assumed all your columns are integers, though - so you might need to chnage that. – ekhumoro Oct 28 '16 at 20:06
  • 1
    No not all my columns. they have numbers, there are string columns, date columns also. using your updated code gives Value Error.invalid literal for int() with base 10: 'Date' – learncode Oct 28 '16 at 20:06
  • 1
    Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126934/discussion-between-venkata-narsi-reddy-vaddula-and-ekhumoro). – learncode Oct 28 '16 at 20:13
  • 1
    @VenkataNarsiReddyVaddula. I have added a solution to my answer. Use `numeric_columns` to specify which columns have numbers. – ekhumoro Oct 28 '16 at 20:18
  • 1
    No i cannot do this, because I have to open a new different file every time. is there any other way? – learncode Oct 28 '16 at 20:23
  • 2
    @VenkataNarsiReddyVaddula. You can do it. You just need to write a little bit of code to check which kind of data is in each column. – ekhumoro Oct 28 '16 at 20:39
  • 1
    @VenkataNarsiReddyVaddula. I have updated my answer with a demo script that should do what you want. (PS: please restore the upvote/accept as you did with my other answer). – ekhumoro Nov 02 '16 at 01:01
  • 1
    Thanks, there is one more thing, can we sort "date type" columns? they still are not sorting quite well yet. – learncode Nov 02 '16 at 14:57
  • 1
    this should probably be in another question but I am doing the same thing with excel files and I have the same problem? can you see the update 2 in the question and help me! (PS: sorry I am new to this PyQt4 coding and am in a hurry to finish the project) – learncode Nov 02 '16 at 15:02
  • 1
    @VenkataNarsiReddyVaddula. Use a timestamp for date sorting. As for the other points: please start a new question - I think I have been more than generous with my help on this one question (which you have still not accepted). – ekhumoro Nov 02 '16 at 16:38
  • 1
    I did not think the upvotes and accepting matter much, I have already used my 40 upvotes today to upvote your other pyqt answers. Anyway thanks! (PS: I am just afraid that the new question will not reach you!). Thanks a lot Again! – learncode Nov 02 '16 at 16:43
  • 1
    here is the follow up question please help me! http://stackoverflow.com/questions/40385408/pyqt-how-to-sort-qtableview-columns-of-a-excel-filestrings-and-numericals-and – learncode Nov 02 '16 at 16:51
  • 2
    @VenkataNarsiReddyVaddula. It doesn't matter *that* much - it's just a way to give a small token of gratitude to the people who are volunteering their own time to help you. So if you find the answers useful, please upvote and accept them (it only takes a few seconds). However, please avoid giving people lots of **extra** upvotes **all at once**. There are automatic systems in place to prevent "serial upvoting" - so it's likely I will lose most of those extra upvotes you gave me. Thanks for thinking of me, though. – ekhumoro Nov 02 '16 at 17:07