从 QTreeWidgetItem 子类发出信号的替代方案 PyQt/PySide

alternatives to emit a signal from a QTreeWidgetItem SubClass PyQt/PySide

我正在实现一个 gui 分析软件,它使用带有几个自定义 TreeWidgetItem 的 QTreeWidget 类。树中的每个项目都或多或少地负责自己的簿记,以跟踪附加到它的数据集和对象。我希望能够从自定义 QTreeWidgetItems 的函数中发出信号,但以下代码导致无法将 myTWItem 转换为 QObject 的错误。有没有办法以这种方式从 QTreeWidgetItem 发出信号?

import sys
from PyQt5 import QtCore, QtWidgets, QtGui


class myTWItem(QtWidgets.QTreeWidgetItem):
    childAdded = QtCore.pyqtSignal(object)

    def addChild(self, child):
        super(myTWItem, self).addChild(child)
        self.childAdded.emit(child)

app = QtWidgets.QApplication(sys.argv)
tw = QtWidgets.QTreeWidget()

item = myTWItem()

tw.addTopLevelItem(item)
item.setText(0, "James")

child = QtWidgets.QTreeWidgetItem()
child.setText(0, "Braddock")
item.addChild(child)

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

输出:

>>Traceback (most recent call last):
>>  File "C:/Coding/Python/dataquick/sandbox/treewidgettest.py", line 22, in <module>
>>    item.addChild(child)
>>  File "C:/Coding/Python/dataquick/sandbox/treewidgettest.py", line 10, in addChild
>>    self.childAdded.emit(child)
>>TypeError: myTWItem cannot be converted to PyQt5.QtCore.QObject in this context
>>
>>Process finished with exit code 1

实现此目的的一种方法是在父树小部件上定义自定义信号。然后,从该项目中,您可以执行以下操作:

tree = self.treeWidget()
if tree is not None:
    tree.childAdded.emit(child)

当然,这里明显的缺点是,这不适用于尚未添加到树中的项目(尽管在某些情况下,这可能是一个优势)。

另一种方法是创建一个单独的信号 class 继承 QObject。为了保持轻量化,最好使用它的共享实例,而不是为每个项目创建一个。这也将避免必须为树中的 每个 项目建立连接:

import sys
from PyQt5 import QtCore, QtWidgets, QtGui

class TWSignals(QtCore.QObject):
    childAdded = QtCore.pyqtSignal(object)

class myTWItem(QtWidgets.QTreeWidgetItem):
    signals = TWSignals()

    def addChild(self, child):
        super(myTWItem, self).addChild(child)
        self.signals.childAdded.emit(child)

app = QtWidgets.QApplication(sys.argv)
tw = QtWidgets.QTreeWidget()

# connect using the class attribute
myTWItem.signals.childAdded.connect(
    lambda item: print('child added:', item.text(0)))

item = myTWItem()

tw.addTopLevelItem(item)
item.setText(0, "James")

child = QtWidgets.QTreeWidgetItem()
child.setText(0, "Braddock")
item.addChild(child)

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

(注意:当然,以这两种方式中的任何一种方式做事都意味着 sender() 不会 return 您通常期望的结果。