PyQt 信号:在 disconnect() 之后,触发的信号是否仍能正常工作?
PyQt signals: will a fired signal still do its job after a disconnect()?
我正在处理一个应用程序,在该应用程序中会触发许多信号,然后重新连接。我将详细解释该应用程序的工作原理,以及我的困惑是从哪里开始的。
1。重新连接信号
在我的应用程序中,我经常重新连接信号。为此,我将使用以下静态函数,取自@ekhumoro 的回答(并稍作修改)来自 post: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()
.
编辑:
上面显示的设计简化了很多。在最终设计中,信号发射器和接收槽可能在不同的线程中运行。
出于可能会误入歧途的原因,我不能一次连接所有对象,发出信号,最后断开所有对象。我必须一个接一个地循环,执行连接-发射-断开程序。
同样,由于某些原因会使我们走得太远,我不能直接调用这些插槽。
3。信号槽机制的心理形象
随着时间的推移,我已经在脑海中形成了信号槽机制如何工作的印象。我想象一个 Signal-Slot 引擎 吸收所有发射的信号并将它们放入队列中。每个信号等待轮到它。当时间准备就绪时,引擎将给定的信号传递给适当的处理程序。为了正确地做到这一点,引擎有一些 'bookkeeping' 工作来确保每个信号都在正确的插槽中结束。
4。 Signal-Slot 引擎的行为
假设我们正处于第 nth 迭代步骤。我们将 self.mySignal
连接到 object_n。然后我们用它的有效载荷发射信号。几乎在这样做之后,我们立即断开连接并建立到 object_n+1 的新连接。在我们断开连接的那一刻,发射的信号可能还没有完成它的工作。我可以想象 Signal-Slot 引擎的三种可能行为:
[选项 1] 引擎注意到连接断开,并从其队列中丢弃 sig_n
。
[OPTION 2] 引擎注意到连接重新建立到另一个处理程序,并发送 sig_n
到 object_n+ 的处理程序1(一旦它到达队列的前面)。
[选项 3] 引擎不会为 sig_n
更改任何内容。当被触发时,它是为 object_n 的处理程序准备的,这就是它将结束的地方。
5。我的问题
我的第一个问题现在已经很明显了。正确的 Signal-Slot 引擎行为是什么?我希望是第三种选择。
作为第二个问题,我想知道给定的心理图像在多大程度上是正确的。例如,我可以依赖信号按顺序离开队列吗?这个问题不太重要——它对我的申请当然不重要。
第三个问题与时间效率有关。重新连接到另一个处理程序是否耗时?知道第一个问题的答案后,我将继续构建应用程序,我可以自己测量重新连接时间。所以这个问题不是那么重要。但是,如果您无论如何都知道答案,请分享:-)
我将从你的第二个问题开始,说你的心理形象部分正确,因为涉及队列,但是不总是。发出信号时,可以通过三种可能的方式调用连接的插槽,其中两种使用事件队列(QMetaCallEvent
即时实例化并使用 QCoreApplication
的方法发布postEvent
,其中事件目标是插槽持有者,或者信号接收器,如果你愿意的话)。第三种情况是直接调用,所以发出信号就像调用插槽一样,没有任何东西排队。
现在第一个问题:在任何情况下,当发出信号时,都会遍历一个连接列表(属于信号发射器),然后调用插槽另一个使用上面提到的三种方法之一。每当连接建立或断开时,列表都会更新,但这必然发生在信号发出之前或之后。简而言之:在信号发出后,成功阻止对已连接插槽的调用的机会很小,至少不会断开与 disconnect()
的连接。所以我会将 [OPTION 3]
标记为正确。
如果您想深入了解,请从 ConnectionType enum documentation 开始,其中对三种基本连接类型(直接、排队和阻塞排队)进行了很好的解释。 连接类型 可以指定为 QObject
方法 connect
的第五个参数,但是,正如您将从上述链接文档中了解到的那样,通常是Qt自己选择最适合情况的连接类型。剧透:涉及线程:)
关于第三个问题:我手头没有基准测试可以展示,所以我会给出所谓的主要基于意见答案,以恕我直言开头的那种答案。我认为 signal/slot 领域是 保持简单 规则统治的领域之一,而你的 reconnect 模式似乎使事情变得比他们需要的复杂得多。正如我在上面所暗示的,建立连接后,连接对象将附加到列表中。当信号发出时,所有连接的插槽将以某种方式被调用,一个接一个。因此,为什么不先连接所有项目,然后发出信号,然后将它们全部断开,而不是在循环中的每个循环中 disconnect/reconnect/emit 呢?
我希望我的(冗长而冗长的)回答对您有所帮助。好读。
我正在处理一个应用程序,在该应用程序中会触发许多信号,然后重新连接。我将详细解释该应用程序的工作原理,以及我的困惑是从哪里开始的。
1。重新连接信号
在我的应用程序中,我经常重新连接信号。为此,我将使用以下静态函数,取自@ekhumoro 的回答(并稍作修改)来自 post: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()
.
编辑:
上面显示的设计简化了很多。在最终设计中,信号发射器和接收槽可能在不同的线程中运行。
出于可能会误入歧途的原因,我不能一次连接所有对象,发出信号,最后断开所有对象。我必须一个接一个地循环,执行连接-发射-断开程序。
同样,由于某些原因会使我们走得太远,我不能直接调用这些插槽。
3。信号槽机制的心理形象
随着时间的推移,我已经在脑海中形成了信号槽机制如何工作的印象。我想象一个 Signal-Slot 引擎 吸收所有发射的信号并将它们放入队列中。每个信号等待轮到它。当时间准备就绪时,引擎将给定的信号传递给适当的处理程序。为了正确地做到这一点,引擎有一些 'bookkeeping' 工作来确保每个信号都在正确的插槽中结束。
4。 Signal-Slot 引擎的行为
假设我们正处于第 nth 迭代步骤。我们将 self.mySignal
连接到 object_n。然后我们用它的有效载荷发射信号。几乎在这样做之后,我们立即断开连接并建立到 object_n+1 的新连接。在我们断开连接的那一刻,发射的信号可能还没有完成它的工作。我可以想象 Signal-Slot 引擎的三种可能行为:
[选项 1] 引擎注意到连接断开,并从其队列中丢弃
sig_n
。[OPTION 2] 引擎注意到连接重新建立到另一个处理程序,并发送
sig_n
到 object_n+ 的处理程序1(一旦它到达队列的前面)。[选项 3] 引擎不会为
sig_n
更改任何内容。当被触发时,它是为 object_n 的处理程序准备的,这就是它将结束的地方。
5。我的问题
我的第一个问题现在已经很明显了。正确的 Signal-Slot 引擎行为是什么?我希望是第三种选择。
作为第二个问题,我想知道给定的心理图像在多大程度上是正确的。例如,我可以依赖信号按顺序离开队列吗?这个问题不太重要——它对我的申请当然不重要。
第三个问题与时间效率有关。重新连接到另一个处理程序是否耗时?知道第一个问题的答案后,我将继续构建应用程序,我可以自己测量重新连接时间。所以这个问题不是那么重要。但是,如果您无论如何都知道答案,请分享:-)
我将从你的第二个问题开始,说你的心理形象部分正确,因为涉及队列,但是不总是。发出信号时,可以通过三种可能的方式调用连接的插槽,其中两种使用事件队列(QMetaCallEvent
即时实例化并使用 QCoreApplication
的方法发布postEvent
,其中事件目标是插槽持有者,或者信号接收器,如果你愿意的话)。第三种情况是直接调用,所以发出信号就像调用插槽一样,没有任何东西排队。
现在第一个问题:在任何情况下,当发出信号时,都会遍历一个连接列表(属于信号发射器),然后调用插槽另一个使用上面提到的三种方法之一。每当连接建立或断开时,列表都会更新,但这必然发生在信号发出之前或之后。简而言之:在信号发出后,成功阻止对已连接插槽的调用的机会很小,至少不会断开与 disconnect()
的连接。所以我会将 [OPTION 3]
标记为正确。
如果您想深入了解,请从 ConnectionType enum documentation 开始,其中对三种基本连接类型(直接、排队和阻塞排队)进行了很好的解释。 连接类型 可以指定为 QObject
方法 connect
的第五个参数,但是,正如您将从上述链接文档中了解到的那样,通常是Qt自己选择最适合情况的连接类型。剧透:涉及线程:)
关于第三个问题:我手头没有基准测试可以展示,所以我会给出所谓的主要基于意见答案,以恕我直言开头的那种答案。我认为 signal/slot 领域是 保持简单 规则统治的领域之一,而你的 reconnect 模式似乎使事情变得比他们需要的复杂得多。正如我在上面所暗示的,建立连接后,连接对象将附加到列表中。当信号发出时,所有连接的插槽将以某种方式被调用,一个接一个。因此,为什么不先连接所有项目,然后发出信号,然后将它们全部断开,而不是在循环中的每个循环中 disconnect/reconnect/emit 呢?
我希望我的(冗长而冗长的)回答对您有所帮助。好读。