Search code examples
pythonpyside2qabstracttablemodel

QAbstractTableModel emits dataChanged, but update is never drawn


I am using Python and the PySide2 Qt bindings.

My program is intended to load records from a csv file, display them as rows in a table, and when asked, upload each to a remote database. Each upload takes a few seconds, so I figured I'd change the background color of each row as it's uploading, then change it again to either red or green based of success or failure.

I have a TableModel class that extends QAbstractTableModel. The program doesn't need to edit the values, just load them from csv, so it doesn't implement setData(), just data(). I have it passed through an extended QSortFilterProxyModel into a QTableView for sorting purposes.

class TableModel(QAbstractTableModel):
    records = [] #Where the list of records is kept
    def data(self, index, role=Qt.DisplayRole):
        record = self.records[index.row()]
        if role == Qt.DisplayRole:
            #bunch of table data stuff
        elif role == Qt.BackgroundColorRole:
            #This gets called all the time
            #but is never called during the uploading process
            if record.uploading: return QColor.cyan

    def upload(self):
        for recordRow in range(len(self.records)):
            record = self.records[recordRow]
            start = self.createIndex(recordRow, 0)
            end = self.createIndex(recordRow, 4)
            record.uploading = True
            #I've tried both explicitly specifying the desired role
            #as well as omitting the argument
            self.dataChanged.emit(start, end, [Qt.BackgroundColorRole])
            record.upload() #Currently just waits for 1 second
            record.uploading = False
            self.dataChanged.emit(start, end, [Qt.BackgroundColorRole])

As you can see, I set an uploading flag, emit the dataChanged signal, upload (actually just waits for 1 second at the moment), turn the flag back off, and emit dataChanged again. I expect to see the cyan highlight stay on each row for one second, moving down the list, but instead nothing happens.

When I monitor the data() method, it never gets called with the BackgroundColorRole during the upload iterations.

I connected a test method to the dataChanged signal as well, and it does get emitted with the correct indices.

Do I need to do something else to connect dataChanged properly? Does the QSortFilterProxyModel between my model and view cause issues?


Solution

  • You should not have tasks that delay more than 30 ms in the main thread since it blocks the GUI avoiding that the event loop is executed and consequently the signals do not notify causing the updates of the GUI not to occur. So you should run it on a thread or better use QtNetwork because it is friendly with the Qt event loop.