Info about items and signal in QTreeView - PyQt5

Viewed 262

There are rows in QTreeView, each row has two columns. The first column carries a name, second column carries a preview.

Questions:

  1. How to get click on row signal? If row is selected by single mouse click, how to get signal? I use QTreeView.doubleClicked.connect() now, but is there way how to do?

  2. I follow up on the first question. If I choose by clicking on the item in the second column how to get item name from the first column? (if is not possible to perform the action with a single mouse click, how to do it with QTreeView.doubleClicked.connect()? )

  3. How to get information about category, subcategories, row, column of item?

Thanks for hints and help.

Code preview:

  1. QTreeView
self.tree = QtWidgets.QTreeView()
self.model = QtGui.QStandardItemModel(self.tree)
self.tree.setDragEnabled(True)
self.tree.doubleClicked.connect(self.getValue)
  1. Filling QTreeView
self.model.setHorizontalHeaderLabels(('Category / Subcategories / Name', 'Preview'))
self.tree.setModel(self.model)
self.tree.setColumnWidth(0, 200)
#root = self.tree.rootIndex()
for row, (keys, vals) in enumerate(self.dataStatObj.items()):
    if row == 0:
        kategorie = keys[0]
        podkategorie = keys[1]
        categoryTV = QtGui.QStandardItem(keys[0])
        subcategoriesTV = QtGui.QStandardItem(keys[1])
        self.model.appendRow(categoryTV)
        for iimg in listImagesNameSuffix:
            if iimg[1] == keys[2]:
                print(iimg[1])
                print(keys[2])
                imgName = iimg[0]
        imgTV = StandardItemObr()
        imgTV.setIcon(QtGui.QIcon(pathToImages + imgName))
        imgTV.setEditable(False)
        nameImgTV = QStandardItem(keys[2])
        nameImgTV.setEditable(False)
        categoryTV.appendRow(subcategoriesTV)
        categoryTV.setEditable(False)
        subcategoriesTV.appendRow([nameImgTV, imgTV])
        subcategoriesTV.setEditable(False)
    ...
    ...
        
self.tree.expandAll()
self.tree.setIconSize(QtCore.QSize(100, 100))
  1. getValue (self.tree.doubleClicked.connect(self.getValue))
def getValue(self, val):
    print(val.data(), 'If I click on the first column, the text will appear.'
                      ' When I click on the second column I need to return the same as for the first column ')
    if val.data() is None:
        print('None')
        print(val.parent(), "PARENT")
  1. Preview

Click on second column (there is QIcon)

1 Answers

QTreeView, like other views such as QListView or QTableView, inherits from QAbstractItemView, and if you look at the Signals section you'll see that there are other signals other than doubleClicked. What you need, obviously, is the clicked signal.

That signal, like most of the others, returns the model index (a QModelIndex instance) that has been clicked, which is an object that is used to locate the data within the model, including its "coordinates": row, column and parent (the last is fundamental for tree models).

The QModelIndex class has various convenience functions that allow easy access to the relation with the model:

  • data(), which you're already using, that returns the value(s) associated to that specific index in the model; it's actually a "shortcut" to model.data(index, role);
  • parent() is pretty explanatory; same as model.parent(index);
  • sibling(), returns an index at the specified row or column that shares the same parent of the given one; it's the same as model.sibling(row, column, index);

Considering the above, if you want to get data about the first column after a click, you need to connect the function to the clicked signal; then, in order to get information about any possible parent, you can use a basic recursive function:

def getValue(self, index):
    if index.column():
        index = index.sibling(index.row(), 0)
        # since Qt 5.11 you can use `index.siblingAtColumn(0)`

    def getValueRecursive(index):
        info = ['"{}" (row {}, col {})'.format(
            index.data(), index.row(), index.column())]
        if index.parent().isValid():
            info.extend(getValueRecursive(index.parent()))
        return info

    print('Index clicked!')
    for indexInfo in reversed(getValueRecursive(index)):
        print(indexInfo)

Note that the clicked signal will obviously only work for mouse clicks: if the current index is changed using the keyboard, it will not be emitted, so you should better use the selectionModel of the view and use the selectionChanged or currentChanged signals instead.

I strongly recommend you to carefully and patiently study the classes you're using, including the inherited ones; for instance, if you're using QTreeView, you should consider studying all the documentation about: QAbstractItemView, QAbstractScrollArea, QFrame, QWidget and, finally, QObject; since you're using models, you also need to know more about QModelIndex, QAbstractItemModel and read the documentation about the model/view framework.

Related