处理来自引用未知的小部件的信号
Posted
技术标签:
【中文标题】处理来自引用未知的小部件的信号【英文标题】:Handle signal from a widget whose reference is unkown 【发布时间】:2015-04-01 10:07:54 【问题描述】:假设我已经实现了一个小部件 A,它需要处理小部件 C 发送的信号。但是小部件 a 没有小部件 C 的引用(至少获取起来非常麻烦)。正确的做法是什么?
这是一个简单的例子:
class WidgetA(QtGui.QWidget):
def __init__(self):
self._tab_widget = QtGui.QTabWidget()
self.layout().addWidget(_tab_widget)
self._tab_widget.addTab(WidgetB())
self._tab_widget.addTab(...)
def show_another_tab(self, index):
self._tab_widget.setCurrentIndex(index)
class WidgetB(QtGui.QWidget):
def __init__(self):
self.layout().addWidget(WidgetC())
class WidgetC(QtGui.QWidget):
show_another_tab = QtCore.pyqtSignal()
def __init__(self):
button = QtGui.QPushButton("show_another_tab")
button.clicked.connect(lambda: self.show_another_tab.emit(2))
所以基本上,我有一个以上的标签。其中一个选项卡中有一个小按钮。当用户单击按钮时,我想切换到另一个选项卡。遗憾的是,该按钮是 WidgetA 的子项的子项,因此在 WidgetA 中保留对按钮的引用对我来说很麻烦。更多的按钮可以在运行时动态创建。
在这种情况下使用信号的正确方法是什么?或者我应该只是在全局变量中引用 WidgetA(我真的不想这样做,但似乎是最简单的方法)?
【问题讨论】:
将一个信号从小部件 c 连接到小部件 b 的信号,并将该信号连接到小部件 a 的插槽? @thuga 我不知道这是否是个好主意,如果我有另一个小部件 d,它是小部件 c 的子部件,而小部件 a 不想处理来自 d 的信号。跨度> 然后你可以重新设计你的应用程序,这样你就不会遇到这样的问题,或者你可以将小部件 d 的信号连接到小部件 c 的信号。 【参考方案1】:如果您在设置父母方面始终如一,那么获取参考资料就不会很麻烦。如果你在你的例子中这样做了,你可以这样做:
class WidgetA(QtGui.QWidget):
def __init__(self):
...
self._tab_widget.addTab(WidgetB(self))
def show_another_tab(self, index):
self._tab_widget.setCurrentIndex(index)
class WidgetB(QtGui.QWidget):
def __init__(self, parent):
self.layout().addWidget(WidgetC(self))
class WidgetC(QtGui.QWidget):
show_another_tab = QtCore.pyqtSignal()
def __init__(self, parent):
...
button.clicked.connect(
lambda: self.parent().parent().show_another_tab.emit(2))
但是,如果您想避免parent()
调用的长链,更全局的方法可能会更好。一种方法是将qApp
设置为QApplication
的子类:
# do this before QtGui is imported elsewhere
QtGui.qApp = MyApplication()
然后您可以提供访问器方法,允许您从上到下导航您的小部件层次结构:
button.clicked.connect(
lambda: QtGui.qApp.tabManager().setCurrentIndex(2))
(注意:显式设置 qApp
不是可选的 - 如果不这样做,您将无法访问子类的任何属性)。
【讨论】:
我想在其他选项卡甚至其他应用程序中重用 WidgetC。因此,如果 WidgetC 不需要知道父母,而只是发出它的信号会更好。 Qt 中没有通用信号之类的东西。你总是连接两个特定的对象,即使它们不是父子关系。但事实上,在您的示例中,WidgetC
实例确实知道他们的父母,因为他们引用了show_another_tab
。他们还知道其他选项卡,因为它们引用了它们的特定索引。确实,WidgetA
类应该负责连接信号,WidgetB
和 WidgetC
类应该具有通用接口(即像标准项目模型及其标准项目)。
对不起,我没有把例子写得更清楚。 WidgetC
没有引用 show_another_tab
,show_another_tab
本身就是一个信号。 WidgetA
恰好有一个 show_another_tab
刚刚成为我想在同名的函数中处理 show_another_tab
信号。我注意到qt中除了信号系统之外还有一个事件系统。我可以创建一个自定义事件并通过 eventFilter 在WidgetA
中处理此事件吗?我正在寻找这种方法。谢谢。
@kkpattern。抱歉,很清楚 - 我只是错过了那个细节。不过,它并没有真正改变我之前的评论。 WidgetC
类知道它是选项卡小部件中选项卡的一部分,并且它还了解其他选项卡(即它们的特定索引)。可能是您的示例不切实际,但这对我来说似乎倒退了。 WidgetA
类应该管理标签,而不是标签内的小部件试图自下而上控制标签管理器。
您可以将WidgetC
作为热链接,供用户跳转到特定标签。由于WidgetC
可以放在任何地方(在WidgetB
内部,WidgetD
... 内部),它不会知道到WidgetA
的父链的长度。我认为将WidgetA
放在全局变量中会是更好的方法。通过这种方式,WidgetC
很难在其他应用程序中重用。以上是关于处理来自引用未知的小部件的信号的主要内容,如果未能解决你的问题,请参考以下文章
来自 Room 的小部件中的 setImageViewUri