2

我决定使用信号来指示线程的完成。如果仍然存在更多工作,我将信号连接到重新启动进程的代码。唉,连接到信号的代码永远不会触发。这让我很难过。

我需要知道为什么下面代码块中的方法“Tester”没有触发。

我是 python 新手,所以当我开始写这篇文章时,我研究了信号并根据tgray在此处发布的解决方案对代码进行了建模,显然我错过了一些重要的东西,但我真的看不到它是什么。

这是我的代码的大量简化版本:

from PyQt4.QtCore import *
import time

class Worker(QThread):
    __pyqtSignals__ = ( "a", 
                        "b" )
    def __init__(self):
        QThread.__init__(self, None)


    def run(self):
        print "'Worker.run' starts"
        self.emit(SIGNAL("a"))
        print "'Worker.run' ends"


class Main:
    def Do(self):
        print "'Do' starts"
        self.Launch()
        time.sleep(2)
        print "'Do' ends"


    def Launch(self):
        print "'Launch' starts"
        self.worker = Worker()
        QObject.connect(self.worker, SIGNAL("a"), self.Tester)
        self.worker.daemon = True
        self.worker.start()
        print "'Launch' ends"


    def Tester(self):
        print "Tester Fired!!"

m=Main()

跑步:

>>> m.Do()

产量:

'Do' starts
'Launch' starts
'Launch' ends
'Do' ends
'Worker.run' starts
'Worker.run' ends

但不是预期的:

Tester Fired!!

我错过了什么?此外,为什么“Worker.run”中的打印出现在其他所有内容之后,即使使用sleep(2)?

4

1 回答 1

4

如果你想看到你的回调被调用,你必须改变你将 QThread 信号连接到你的插槽的方式:

 QtCore.QObject.connect(self.worker,
                        Qt.SIGNAL("a"),
                        self.Tester,
                        Qt.Qt.DirectConnection) #this is added

说明: 自 Qt 4 以来,Qt 信号/插槽是线程安全的。文档说将信号连接到插槽时的正常行为是“自动连接”,这意味着如果信号和插槽都在,它是直接的(在发出后立即触发回调)同一个线程,而如果信号是从另一个线程发出的(你的情况),它就会排队。

然后,必须处理这个队列:通常,这是在您的应用程序运行时由 Qt 循环完成的。

信号“排队”这一事实意味着控制权被转移到 Qt 循环中,以确保在主线程中调用回调,即使信号来自另一个线程。

在您的问题代码中,根本没有事件循环 - 因此从另一个线程调用您的插槽的唯一方法是更改​​信号的分派方式。但是不要在你的代码中使用它,因为在一个正常的应用程序中你有 Qt 循环运行,它会被正确地调度(并且安全地避免线程问题)。

于 2013-10-07T06:04:19.440 回答