从字符串构建 QTreeView

Building a QTreeView from strings

我正在尝试使用所谓的 slug 构建树视图:这是一个由连字符分隔的字符串(例如 Fruit-Apple)。然后,如果该项目尚不存在,您只需遍历各个部分并构建树。列表中的第一项始终是最顶层的父项。任何建议或帮助将不胜感激。我在尝试将项目附加到正确的父项时遇到问题。

    appendCategorySlug('Fruit-Apple')
    appendCategorySlug('Fruit-Orange')
    appendCategorySlug('Vegetable-Lettuce')
    appendCategorySlug('Fruit-Kiwi')
    appendCategorySlug('Vegetable-Carrot')
    appendCategorySlug('Vegetable-Carrot-Blackbean')
    appendCategorySlug('Vegan-Meat-Blackbean')

我不太确定这里出了什么问题。结果很接近,但有些地方不对...

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):
        # sourceIndex = self.categoryProxyModel.mapToSource(proxyIndex)
        # item = self.categoryModel.itemFromIndex(sourceIndex)
        parts = slug.split('-')
        parent = self.categoryModel.invisibleRootItem()
        for name in parts:
            # find part and it doesn't exist append it
            items = self.categoryModel.findItems(name, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive, 0)
            if len(items) == 1:
                print items[0].data()
                parent = items[0]            
            item = QtGui.QStandardItem(name)
            parent.appendRow(item)
            parent = item


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.show()
    sys.exit(app.exec_())


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

这里有一些问题。递归搜索很容易出错,因为后代项可能与其祖先之一具有相同的名称。而且它也是低效的,因为在每一步我们只想知道在当前级别是否存在一个同名的项目——它下面的是无关紧要的。此外,我们应该避免搜索当前父级是否没有子级,并确保只有在他们丢失时才创建新的父级(这是您当前实现的主要问题)。

如果使用模型的 match function 而不是 findItems,则可以最轻松地解决上述问题,因为它可以更好地控制搜索的完成方式:

def appendCategorySlug(self, slug):
    parts = slug.split('-')
    parent = self.categoryModel.invisibleRootItem()
    for name in parts:
        if parent.rowCount():
            indexes = self.categoryModel.match(
                parent.child(0).index(),
                QtCore.Qt.DisplayRole, name, 1,
                QtCore.Qt.MatchExactly)
            if indexes:
                parent = self.categoryModel.itemFromIndex(indexes[0])
                continue
        item = QtGui.QStandardItem(name)
        parent.appendRow(item)
        parent = item

这个算法可以用一个简单的for循环实现得更简单,也许更容易理解:

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