Scrollbar jumping to top when shifting rows in QTableView



  • The following program will intermittently enter a failure mode where the scrollbar jumps at the top whenever a new row is added (and the first one discarded). The failure mode is sometimes triggered by the main window losing and reacquiring focus. How do I fix this bug?

    import sys
    from PyQt5 import QtCore, QtWidgets
    
    
    class _Scroller(QtCore.QAbstractTableModel):
        def __init__(self, parent):
            QtCore.QAbstractTableModel.__init__(self, parent)
    
            self.headers = ["Test"]
            self.depth = 20
            self.entries = []
            self.counter = 0
    
            timer = QtCore.QTimer(self)
            timer.timeout.connect(self.timer_tick)
            timer.start(100)
    
        def headerData(self, col, orientation, role):
            if (orientation == QtCore.Qt.Horizontal
                    and role == QtCore.Qt.DisplayRole):
                return self.headers[col]
            return None
    
        def rowCount(self, parent):
            return len(self.entries)
    
        def columnCount(self, parent):
            return len(self.headers)
    
        def insertRows(self, position, rows=1, index=QtCore.QModelIndex()):
            self.beginInsertRows(QtCore.QModelIndex(), position, position+rows-1)
            self.endInsertRows()
    
        def removeRows(self, position, rows=1, index=QtCore.QModelIndex()):
            self.beginRemoveRows(QtCore.QModelIndex(), position, position+rows-1)
            self.endRemoveRows()
    
        def timer_tick(self):
            to_add = [self.counter]
            self.counter += 1
    
            nrows = len(self.entries)
            self.entries.extend(to_add)
            self.insertRows(nrows, len(to_add))
            if len(self.entries) > self.depth:
                start = len(self.entries) - self.depth
                self.entries = self.entries[start:]
                self.removeRows(0, start)
    
        def data(self, index, role):
            if index.isValid():
                if role == QtCore.Qt.DisplayRole:
                    return str(self.entries[index.row()])
    
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
    
        w = QtWidgets.QMainWindow()
        table = QtWidgets.QTableView()
        w.setCentralWidget(table)
        w.show()
    
        table.setModel(_Scroller(table))
    
        sys.exit(app.exec_())
    
    
    if __name__ == '__main__':
        main()

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.