从文本 slug 获取 QTreeview 索引

Get QTreeview index from text slug

我正在尝试使用给定的 slug 检索 QTreeView 项目的模型索引 - 它是一个字符串,表示由连字符分隔的 treeview 项目的层次结构。在这种情况下,我想获取给定 slug 'Vegetable-Carrot-Blackbean':

的模型索引

我当前的函数总是 returns "Vegetable" 我觉得它的编写方式我希望它不断循环给定索引的子项直到它失败,返回最后找到的树项:

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()

在这种情况下,方便的方法是递归迭代子项:

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

您当前的实现不起作用的原因是 match()start 参数需要是有效索引。不可见的根项永远不会有效,因为它的行和列将始终为 -1。因此,您必须使用模型的 index() 函数来尝试获取当前父项的第一个子索引。您还需要确保当 any 部分 slug 无法匹配时 returned,否则您可以错误地结束了 returning 祖先索引。

这是实现所有这些的方法:

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]

作为替代方案,您可能需要考虑 returning 一个 项目,因为这样您就可以访问整个 QStandardItem API(索引仍然可以通过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

但请注意,如果找不到 slug,则此 returns None(尽管它可以很容易地调整为 return 不可见的根项目)。