Search code examples
pythonpyqtpyqt5qtreeview

Change certain data in QTreeView


I am trying to make a virtual file system for a part of a project (since I couldn't find any libraries for this — all the ones I found were for accessing your actual file system).

I decided to store it as an XML, and then to display it by generating a QStandardItemModel, and generating a QTreeView based on that model.

I am currently trying to add the rename, move, etc options. I can perform these changes in the XML fairly easily, but I've spent hours trying to figure it out with the treeview and haven't gotten anywhere. The best thing I've been able to do is to regenerate the model from the xml file, and then make that the treeview model. However, this will probably be too slow for my end program (which will have a few thousand "files"), and this also collapses all the nodes in the treeview which seems pretty annoying to fix. Overall, this just doesn't seem like the best way to do it, especially since I know which nodes are being changed, so it would be much simpler to just edit those individual nodes in the treeview (or in the model).

The way I would want this to work, is that the user selects an element of the treeview to rename, I get the selectedItem from the treeview, then somehow lookup the corresponding item in the model and modify that.

I've also considered traversing the model to find the item I want to move/rename and then doing that within the model, but I couldn't find any good documentation for how to traverse the model (it doesn't even seem to have a method that returns the number of children of a node).

Is there a "nice" way of doing this?

Example:

def clicked():
    index = list(treeView.selectedIndexes())[0]
    # TODO: change text of index to "changed text"


app = QApplication([])

window = QWidget()
layout = QVBoxLayout()

treeView = QTreeView()

model = QStandardItemModel()
model.invisibleRootItem().appendRow(QStandardItem('a'))
child_node = QStandardItem('b')
child_node.appendRow(QStandardItem('c'))
model.invisibleRootItem().appendRow(child_node)

treeView.setModel(model)
treeView.clicked.connect(clicked)

layout.addWidget(treeView)

window.setLayout(layout)

window.show()

app.exec_()

Solution

  • The clicked signal sends the QModelIndex associated with the clicked item so it is not necessary to use selectedIndexes().

    Going to the bottom problem, the logic is to use the model to get the item given the QModelIndex and then use the setText() method, another more general option is to use the setData() method:

    def clicked(index):
        model = index.model()
    
        item = model.itemFromIndex(index)
        item.setText("changed text")
    
        # or
        # model.setData(index, "changed text", Qt.DisplayRole)