PyQt信号:断开连接后,被激发的信号是否仍能正常工作?

时间:2018-05-22 12:58:03

标签: qt pyqt qt5 pyqt5 signals-slots

我正在处理一个应用程序,其中许多信号被触发,然后重新连接。我将详细解释该应用程序的工作原理,以及我的困惑开始的地方。


1。重新连接信号

在我的应用程序中,我经常重新连接信号。我将使用以下静态函数,取自@ekhumoro的答案(并稍加修改)来自这篇文章:PyQt Widget connect() and disconnect()

def reconnect(signal, newhandler):
    while True:
        try:
            signal.disconnect()
        except TypeError:
            break
    if newhandler is not None:
        signal.connect(newhandler)


2。申请

想象一下,函数emitterFunc(self)循环遍历一个对象列表。在每次迭代时,函数将mySignal连接到对象,触发信号,然后在下一个迭代步骤开始时再次断开mySignal。触发信号还携带一些有效载荷,例如对象Foo()


enter image description here

修改

  • 上面显示的设计简化了很多。在最终设计中,信号发射器和接收槽可能在不同的线程中运行。

  • 由于导致我们误入歧途的原因,我不能一次连接所有对象,发出信号,最后将它们全部断开。我必须逐个循环,执行connect-emit-disconnect过程。

  • 再次由于导致我们走得太远的原因,我不能直接调用这些插槽。


3。信号槽机制的心理图像

随着时间的推移,我已经建立了信号槽机制如何工作的心理图像。我想象一个信号槽引擎吸收所有发射信号并将它们放入队列中。每个信号等待轮到他们。当时间准备就绪时,引擎将给定信号传递给适当的处理程序。为了正确地做到这一点,引擎有一些'簿记'工作,以确保每个信号在正确的插槽中结束。

enter image description here


4。信号槽引擎的行为

想象一下,我们正处于n th 迭代步骤。我们将self.mySignal object_n 相关联。然后我们用它的有效载荷发射信号。在执行此操作后,我们几乎立即断开连接并建立与 object_n + 1 的新连接。目前我们打破了连接,被发射的信号可能还没有完成它的工作。我可以想象Signal-Slot引擎的三种可能行为:

  • [选项1]引擎注意到连接已断开,并从其队列中丢弃sig_n

  • [选项2]引擎注意到连接已重新建立到另一个处理程序,并将sig_n发送到 object_n + 1 的处理程序(只要它到达队列的前面。

  • [选项3]引擎不会更改sig_n的任何内容。在被解雇时,它被用于 object_n 的处理程序,并且它将在那里结束。


5。我的问题

我的第一个问题现在非常明显。什么是正确的信号槽引擎行为?我希望这是第三种选择。

作为第二个问题,我想知道给定的心理图像在多大程度上是正确的。例如,我可以依赖于按顺序退出队列的信号吗?这个问题不太重要 - 这对我的申请来说当然不是很重要。

第三个问题与时间效率有关。是否重新连接到另一个处理程序耗时?一旦我知道第一个问题的答案,我将继续构建应用程序,我可以自己测量重新连接时间。所以这个问题不是那么重要。但如果你知道答案,请分享: - )

1 个答案:

答案 0 :(得分:2)

我会从第二个问题开始,说你的心理图像部分正确,因为涉及队列,但并非总是如此。当发出信号时,有三种可能的方式来调用连接的插槽,其中两个使用事件队列(动态实例化QMetaCallEvent并使用QCoreApplication的方法发布postEvent,其中事件目标是插槽持有者,或者信号接收器,如果您愿意的话)。第三种情况是直接调用,因此发出信号就像调用插槽一样,没有任何内容排队。

现在到第一个问题:在任何情况下,当发出信号时,遍历一个连接列表(属于信号发射器)并且使用其中一个连接调用插槽上面提到的三种方法。无论何时建立连接或断开连接,列表都将更新,但这必须在发出信号之前或之后发生。简而言之:在发出信号后成功阻止对连接槽的调用的机会很小,至少不会破坏与disconnect()的连接。所以我会将[OPTION 3]标记为正确。

如果您想进一步深入挖掘,请从ConnectionType enum documentation开始,其中详细解释了三种基本类型的连接(直接,排队和阻塞排队)。可以将连接类型指定为QObject方法connect的第五个参数,但是,正如您将从上述链接文档中学习的那样,通常是Qt本身选择最适合的情况的连接类型。剧透:涉及线程:)

关于第三个问题:我手边没有基准测试显示,所以我会给出一个所谓的主要基于意见的答案,这种答案开始与恕我直言。我认为 signal / slot 域是 keep-it-simple 规则的规则之一,而你的重新连接模式似乎使事情变得比他们需要的复杂得多。如上所述,当建立连接时,连接对象将附加到列表中。当发出信号时,将以某种方式一个接一个地调用所有连接的插槽。因此,不是在循环中的每个循环中断开/重新连接/发出,为什么不先连接所有项目,然后发出信号,然后将它们全部断开?

我希望我的(长期的,可能是tldr)答案有所帮助。好读。