PyQt6:在 QTreewidget 中按路径查找元素

问题描述 投票:0回答:3

如何使用元素的路径在 Qtreewidget 中选择该元素?

路径被写为示例字符串:parent/parent/parent/parent/element

沿整个路径搜索元素,而不仅仅是通过该元素的名称来搜索元素很重要,因为树中可能有很多具有相同名称的元素,但每个元素肯定会有不同的路径。

我尝试用十种方法来解决:

def find_and_select_item(self):
    path = self.comboBox_Scene.currentText()
    path_elements = path.split('/')
    current_item = self.treeWidget.invisibleRootItem()
    for element in path_elements:
        items = self.treeWidget.findItems(element, Qt.MatchFlag, 0)
        if items:
            current_item = items[0]
        else:
            # Element not found in the current level of the tree
            return None

    # Select the found item
    current_item.setSelected(True)
    return current_item

不幸的是,这个函数返回一个错误::

TypeError: findItems(self, text: str, flags: Qt.MatchFlag, column: int = 0): argument 2 has unexpected type 'EnumType'

python search pyqt6 qtreewidget
3个回答
0
投票

我正在尝试以新的方式解决它:

def iterator_treewiget(self, widget, content):
    for i in range(widget.childCount()):
        item = widget.child(i)
        text = item.text(0)

        if content in text:
            self.treeWidget.setCurrentItem(item)
            return
        self.iterator_treewiget(item, content)

def find_and_select_item(self):
    content = self.comboBox_Scene.currentText()
    items = content.split('/')
    n = len(items)
    item = items[n-1]
    if content:
        root = self.treeWidget.invisibleRootItem()
        self.iterator_treewiget(root, item)

我找到了解决问题的方法,但它有一些缺点。首先,当有两个相同但位于不同位置的元素时,它会挂起。 例如:

parent/parent/parent/parent/element
parent1/parent1/element
paren2/parent2/parent2/element1
parent/parent/parent/parent/element2
parent1/parent1/element3
paren2/parent2/parent2/element4
parent/parent/parent/parent/element5
parent1/parent1/element6
paren2/parent2/parent2/element7
parent/parent/parent/parent/element8
parent1/parent1/element9
paren2/parent2/parent2/element10

当我指向“element1”、“element2”、“element3”... 4、5、6、7、8、9、10 时,一切正常。当我选择其中一个“元素”时,程序会挂起。 其次,在选择多个不同的元素后,对于更大的元素数据库,会出现错误“RecursionError:调用 Python 对象时超出了最大递归深度”


0
投票

使用递归最容易实现这一点,递归可以提供更通用的解决方案,能够在树中找到多个匹配路径(如果需要)。

下面是一个基本的工作演示,展示了如何实现这一目标。由于问题指出每个元素都有一个不同的路径,因此该演示仅查找第一个匹配项。然而,

searchByPath
方法返回一个生成器,可以在必要时迭代 all 匹配(并且它也可以从树中的任何点开始搜索)。

enter image description here

from PyQt6 import QtCore, QtGui, QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.button = QtWidgets.QPushButton('Test')
        self.button.clicked.connect(self.handleButton)
        self.edit = QtWidgets.QLineEdit()
        self.tree = QtWidgets.QTreeWidget()
        self.tree.setHeaderHidden(True)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.tree)
        layout.addWidget(self.edit)
        layout.addWidget(self.button)
        for text in ('Red', 'Blue', 'Green'):
            level0 = QtWidgets.QTreeWidgetItem(self.tree, [text])
            for text in ('Cyan', 'Violet', 'Yellow'):
                level1 = QtWidgets.QTreeWidgetItem(level0, [text])
                for text in ('Orange', 'Brown', 'Purple'):
                    level2 = QtWidgets.QTreeWidgetItem(level1, [text])
                    for text in ('Gold', 'Silver', 'Bronze'):
                        level3 = QtWidgets.QTreeWidgetItem(level2, [text])
        self.edit.setText('Green/Violet/Orange/Bronze')

    def handleButton(self):
        self.tree.clearSelection()
        self.tree.collapseAll()
        path = self.edit.text()
        if path:
            item = next(self.searchByPath(path), None)
            if item is not None:
                self.tree.scrollToItem(item)
                item.setSelected(True)

    def searchByPath(self, path, root=None):
        if root is None:
            root = self.tree.invisibleRootItem()
        elements = list(map(str.strip, path.split('/')))
        last = len(elements) - 1
        def search(parent, level=0):
            if level <= last:
                target = elements[level]
                for index in range(parent.childCount()):
                    child = parent.child(index)
                    if child.text(0) != target:
                        continue
                    if level == last:
                        yield child
                    else:
                        yield from search(child, level + 1)
        return search(root)


if __name__ == '__main__':

    app = QtWidgets.QApplication(['Test'])
    window = Window()
    window.setGeometry(600, 100, 300, 300)
    window.show()
    app.exec()

-1
投票

在 PyQt6 中,枚举的使用可能与 PyQt5 略有不同。 在 PyQt6 中,Qt.MatchFlag 可能会替换为特定的枚举,例如 Qt.MatchFlag.MatchExactly。

这是您的函数的更新版本:

from PyQt6.QtCore import QDir, Qt  # Make sure to include the specific Qt modules you need

def find_and_select_item(self):
    path = self.comboBox_Scene.currentText()
    path_elements = path.split('/')
    current_item = self.treeWidget.invisibleRootItem()
    
    for element in path_elements:
        items = self.treeWidget.findItems(element, Qt.MatchFlag.MatchExactly, 0)
        if items:
            current_item = items[0]
        else:
            # Element not found in the current level of the tree
            return None

    # Select the found item
    current_item.setSelected(True)
    return current_item

方法2:

问题似乎可能与 PyQt6 中的差异或 findItems 方法的使用方式有关。确保您要搜索的元素完全匹配并且区分大小写:

from PyQt6.QtCore import Qt

def find_and_select_item(self):
    path = self.comboBox_Scene.currentText()
    path_elements = path.split('/')
    current_item = self.treeWidget.invisibleRootItem()

    for element in path_elements:
        items = self.treeWidget.findItems(element, Qt.MatchExactly | Qt.MatchCaseSensitive, 0)
        if items:
            current_item = items[0]
            print("Found item:", current_item.text(0))  # Print the text content of the found item
            # Move the current_item reference to the found item
            current_item = items[0]
        else:
            print(f"Element '{element}' not found in the current level of the tree.")
            return None

    # Select the last found item
    current_item.setSelected(True)
    print("Selected item:", current_item.text(0))  # Print the text content of the selected item
    return current_item
© www.soinside.com 2019 - 2024. All rights reserved.