简体   繁体   中英

Get QTreeview index from text slug

I'm trying to retrieve the model index for the QTreeView item using the given slug - which is a single string representing the treeview item's hierarchy separated by hyphens. In this case, I want to get the model index for the given slug 'Vegetable-Carrot-Blackbean' :

在此处输入图片说明

My current function always returns "Vegetable" and I feel like the way it's written I'd expect it to continually loop through a given index's children until it fails, returning the last found tree item:

import os, sys
from Qt import QtWidgets, QtGui, QtCore


class CategoryView(QtWidgets.QWidget):

    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.resize(250,400)

        self.categoryModel = QtGui.QStandardItemModel()
        self.categoryModel.setHorizontalHeaderLabels(['Items'])

        self.categoryProxyModel = QtCore.QSortFilterProxyModel()
        self.categoryProxyModel.setSourceModel(self.categoryModel)
        self.categoryProxyModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.categoryProxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.categoryProxyModel.setDynamicSortFilter(True)

        self.uiTreeView = QtWidgets.QTreeView()
        self.uiTreeView.setModel(self.categoryProxyModel)
        self.uiTreeView.sortByColumn(0, QtCore.Qt.AscendingOrder)

        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.uiTreeView)
        self.setLayout(self.layout)


    def appendCategorySlug(self, slug):
        parts = slug.split('-')
        parent = self.categoryModel.invisibleRootItem()
        for name in parts:
            for row in range(parent.rowCount()):
                child = parent.child(row)
                if child.text() == name:
                    parent = child
                    break
            else:
                item = QtGui.QStandardItem(name)
                parent.appendRow(item)
                parent = item


    def getIndexBySlug(self, slug):
        parts = slug.split('-')
        index = QtCore.QModelIndex()

        if not parts:
            return index

        root = self.categoryModel.index(0, 0)
        for x in parts:
            indexes = self.categoryModel.match(root, QtCore.Qt.DisplayRole, x, 1, QtCore.Qt.MatchExactly)
            if indexes:
                index = indexes[0]
                root = index

        print index, index.data()
        return index


def test_CategoryView():
    app = QtWidgets.QApplication(sys.argv)
    ex = CategoryView()
    ex.appendCategorySlug('Fruit-Apple')
    ex.appendCategorySlug('Fruit-Orange')
    ex.appendCategorySlug('Vegetable-Lettuce')
    ex.appendCategorySlug('Fruit-Kiwi')
    ex.appendCategorySlug('Vegetable-Carrot')
    ex.appendCategorySlug('Vegetable-Carrot-Blackbean')
    ex.appendCategorySlug('Vegan-Meat-Blackbean')

    ex.getIndexBySlug('Vegetable-Carrot-Blackbean')

    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    pass
    test_CategoryView()

In this case the convenient way is to iterate over the children recursively:

def getIndexBySlug(self, slug):
    parts = slug.split("-")

    index = QtCore.QModelIndex()

    if not parts:
        return index

    for part in parts:
        found = False
        for i in range(self.categoryModel.rowCount(index)):
            ix = self.categoryModel.index(i, 0, index)
            if ix.data() == part:
                index = ix
                found = True
        if not found:
            return QtCore.QModelIndex()
    return index

The reason your current implementation doesn't work is that the start argument of match() needs to be valid index. The invisisble root item can never be valid because its row and column will always be -1 . So, instead, you must use the the model's index() function to try to get the first child index of the current parent. You also need to make sure that an invalid index is returned when any part of the slug cannot be matched, otherwise you could wrongly end up returning an ancestor index.

Here's a method that implements all that:

def getIndexBySlug(self, slug):
    parts = slug.split('-')
    indexes = [self.categoryModel.invisibleRootItem().index()]
    for name in parts:
        indexes = self.categoryModel.match(
            self.categoryModel.index(0, 0, indexes[0]),
            QtCore.Qt.DisplayRole, name, 1,
            QtCore.Qt.MatchExactly)
        if not indexes:
            return QtCore.QModelIndex()
    return indexes[0]

As an alternative, you might want to consider returning an item instead, as that will then give you access to the whole QStandardItem API (and the index can be still be easily obtained via item.index() ):

def itemFromSlug(self, slug):
    item = None
    parent = self.categoryModel.invisibleRootItem()
    for name in slug.split('-'):
        for row in range(parent.rowCount()):
            item = parent.child(row)
            if item.text() == name:
                parent = item
                break
        else:
            item = None
            break
    return item

But note that this returns None if the slug cannot be found (although it could easily be tweaked to return the invisible root item instead).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM