如何使用元素的路径在 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'
我正在尝试以新的方式解决它:
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 对象时超出了最大递归深度”
使用递归最容易实现这一点,递归可以提供更通用的解决方案,能够在树中找到多个匹配路径(如果需要)。
下面是一个基本的工作演示,展示了如何实现这一目标。由于问题指出每个元素都有一个不同的路径,因此该演示仅查找第一个匹配项。然而,
searchByPath
方法返回一个生成器,可以在必要时迭代 all 匹配(并且它也可以从树中的任何点开始搜索)。
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()
在 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