qtreeview not showing created items when a column other than the first is selected



  • Hello all,

    I have experienced an strange behaviour with qtreeview in the code below, where the newly created items are not shown in the view if I created them clicking on a column other than the first one. The steps to reproduce are:

    1. Click on the "Add Child" button
    2. Click on the second column of the item created in the qtreeview.
    3. Click on the "Add Child" button
    4. Any subsequent click to the "Add Child" button creates a new item, but it is not shown in the qtreeview.
    5. Click on the first column of the item created in the qtreeview, instead of the second column
    6. Click on the "Add Child" button. All the previously created items show up now.

    In step 2, if instead of clicking on the second column, I click on the first column the issue disappears, but it is quite disturbing for the users to keep in mind that they only should click on the first column to work properly.
    I found a quick and dirty solution, which is activated by changing the variable fix to True, but I would like to know if there is a better way of fixing it.

    Many thanks,

    #!/usr/bin/env python3
    
    import sys
    import signal
    from PySide2 import QtCore, QtGui, QtWidgets
    
    class NodeClass(object):
        def __init__(self, data, parent=None):
            self.parentItem = parent
            self.itemData = data
            self.childItems = []
    
        def child(self, row):
            return self.childItems[row]
    
        def childCount(self):
            return len(self.childItems)
    
        def childNumber(self):
            if self.parentItem != None:
                return self.parentItem.childItems.index(self)
            return 0
    
        def columnCount(self):
            return len(self.itemData)
    
        def data(self, column):
            return self.itemData[column]
    
        def insertChildren(self, position, count, columns, kind):
            if position < 0 or position > len(self.childItems):
                insert_status = False
            else:
                for row in range(count):
                    data = ["NA" for v in range(columns)]
                    item = kind(data, self)
                    self.childItems.insert(position, item)
                insert_status = True
            return insert_status
    
        def parent(self):
            return self.parentItem
    
        def setData(self, column, value):
            if column < 0 or column >= len(self.itemData):
                set_status = False
            else:
                self.itemData[column] = value
                set_status = True
            return set_status
    
    class ModelClass(QtCore.QAbstractItemModel):
        def __init__(self, parent=None):
            super(ModelClass, self).__init__(parent)
            headers      = ["COL_1", "COL_2"]
            rootData = [header for header in headers]
            self.rootItem = NodeClass(rootData)
    
        def columnCount(self, parent=QtCore.QModelIndex()):
            return self.rootItem.columnCount()
    
        def data(self, index, role):
            if not index.isValid():
                return None
            item = self.getItem(index)
            if role != QtCore.Qt.DisplayRole and role != QtCore.Qt.EditRole:
                return None
            return item.data(index.column())
    
        def flags(self, index):
            if not index.isValid():
                return 0
            return QtCore.Qt.ItemIsEditable | super(ModelClass, self).flags(index)
    
        def getItem(self, index):
            if index.isValid():
                item = index.internalPointer()
                if item:
                    return item
            return self.rootItem
    
        def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
            if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
                return self.rootItem.data(section)
            return None
    
        def index(self, row, column, parent=QtCore.QModelIndex()):
            if parent.isValid() and parent.column() != 0:
                return QtCore.QModelIndex()
            parentItem = self.getItem(parent)
            childItem = parentItem.child(row)
            if childItem:
                return self.createIndex(row, column, childItem)
            else:
                return QtCore.QModelIndex()
    
        def insertRows(self, position, rows, kind, parent=QtCore.QModelIndex()):
            parentItem = self.getItem(parent)
            self.beginInsertRows(parent, position, position + rows - 1)
            success = parentItem.insertChildren( position, rows, self.rootItem.columnCount(), kind)
            self.endInsertRows()
            self.initRow(position,parent)
            return success
    
        def initRow(self,row,index):
            for column in range(self.columnCount(index)):
                child = self.index(row, column, index)
                self.setData(child, "[No data]", QtCore.Qt.EditRole)
    
        def parent(self, index):
            if not index.isValid():
                return QtCore.QModelIndex()
            childItem = self.getItem(index)
            parentItem = childItem.parent()
            if parentItem == self.rootItem:
                return QtCore.QModelIndex()
            return self.createIndex(parentItem.childNumber(), 0, parentItem)
    
        def rowCount(self, parent=QtCore.QModelIndex()):
            parentItem = self.getItem(parent)
            return parentItem.childCount()
    
        def setData(self, index, value, role=QtCore.Qt.EditRole):
            if role != QtCore.Qt.EditRole:
                set_data_status = False
            else:
                item = self.getItem(index)
                set_data_status = item.setData(index.column(), value)
                if set_data_status:
                    self.dataChanged.emit(index, index)
            return set_data_status
    
    class WindowClass(QtWidgets.QMainWindow):
        def __init__(self):
            super(WindowClass, self).__init__()
            self.centralwidget = QtWidgets.QWidget(self)
            self.centralwidget.setObjectName("centralwidget")
            self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
            self.verticalLayout.setObjectName("verticalLayout")
            self.horizontalLayout = QtWidgets.QHBoxLayout()
            self.horizontalLayout.setObjectName("horizontalLayout")
            self.treeView = QtWidgets.QTreeView(self.centralwidget)
            self.treeView.setObjectName("treeView")
            self.horizontalLayout.addWidget(self.treeView)
            self.verticalLayout.addLayout(self.horizontalLayout)
            self.setCentralWidget(self.centralwidget)
            self.toolBar = QtWidgets.QToolBar(self)
            self.toolBar.setIconSize(QtCore.QSize(48, 48))
            self.toolBar.setObjectName("toolBar")
            self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
            self.actionButton = QtWidgets.QAction(self)
            self.actionButton.setObjectName("actionButton")
            self.actionButton.setText("Add child")
            self.toolBar.addAction(self.actionButton)
            QtCore.QMetaObject.connectSlotsByName(self)
            self.__model    = ModelClass()
            self.treeView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
            self.treeView.setModel(self.__model)
            self.treeView.setAlternatingRowColors(True)
            self.actionButton.triggered.connect(self.ButtonMethod)
    
        def ButtonMethod(self):
            fix = False
            if fix is True:
                if len(self.treeView.selectedIndexes()) > 0:
                    index = self.treeView.selectedIndexes()[0]
                else:
                    index = self.treeView.selectionModel().currentIndex()
            else:
                index = self.treeView.selectionModel().currentIndex()
    
    
    
            model = self.treeView.model()
            if not model.insertRows(0, 1, NodeClass, index):
                return
            self.treeView.setExpanded(index, True)
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
        main_window = WindowClass()
        main_window.show()
        sys.exit(app.exec_())
    
    if __name__ == "__main__":
        main()
    
    


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