我正在使用python和PySide开发GUI应用程序。我需要在一个单独的线程中运行长背景任务。对于线程,我决定根据'正确'方法使用QThread,而不从if(参见http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/)继承。因此,为了在后台运行我的长任务,我只需将线程的信号'started'连接到一个执行长任务的方法。
出于某种原因,我的程序没有按预期工作。我花了几个小时才发现如果我将插槽名称重命名为'public'(删除下划线),一切都会按预期开始工作。我想知道私人插槽有什么问题?似乎由于某种原因,主事件循环在私有插槽正在进行时不起作用,虽然我可以看到它是在与主线程不同的线程中执行的(参见下面的程序输出)。
以下是再现问题的示例:
from PySide.QtCore import QThread, QObject, QCoreApplication, QTimer
import time
import sys
class BackgroundWorker(QObject):
def __init__(self):
QObject.__init__(self)
def __process(self):
self.process()
def process(self):
print 'Background thread:', QThread.currentThread()
for i in xrange(0, 5):
print 'In background thread', i
time.sleep(1)
self.thread.quit()
def start(self):
self.thread = QThread()
self.moveToThread(self.thread)
#self.thread.started.connect(self.process) # <---- Case 1: This works as expected
self.thread.started.connect(self.__process) # <---- Case 2: Main event loop freezes.
self.thread.finished.connect(app.quit)
self.thread.start()
def main_thread():
print 'Main thread:', QThread.currentThread()
for i in xrange(0, 5):
print 'In main thread', i
time.sleep(1)
if __name__ == '__main__':
app = QCoreApplication(sys.argv)
bw = BackgroundWorker()
QTimer.singleShot(0, bw.start)
QTimer.singleShot(100, main_thread)
app.exec_()
在上面的方法'BackgroundWorker.start'中,有两行用于将线程'started'信号连接到插槽。 “案例1”行按预期工作(公共插槽已连接),但“案例2”行 - 不是(私有插槽已连接)。
案例1的程序输出:
Background thread: <PySide.QtCore.QThread object at 0x02161738>
In background thread 0
Main thread: <PySide.QtCore.QThread object at 0x021616E8>
In main thread 0
In background thread 1
In main thread 1
In background thread 2
In main thread 2
In background thread 3
In main thread 3
In background thread 4
In main thread 4
案例2的程序输出:
Background thread: <PySide.QtCore.QThread object at 0x021916E8>
In background thread 0
In background thread 1
In background thread 2
In background thread 3
In background thread 4
Main thread: <PySide.QtCore.QThread object at 0x02191788>
In main thread 0
In main thread 1
In main thread 2
In main thread 3
In main thread 4
我怀疑这与PySide中的信号/插槽实现有某种关系,但我没有设法找到任何错误报告或与我观察到的行为相关的事情。
PySide版本是1.2.2,python版本是2.6.6
答案 0 :(得分:0)
当你在python中连接一个QObject的方法时,它会自动注册其meta-Object作为一个插槽。但是,对于以双下划线开头的方法,这不会发生。
您可以在一个简单的示例中看到这一点:
from PySide.QtCore import *
class Test(QObject):
sig = Signal()
def __test(self):
pass
def test(self):
pass
t = Test()
print(t.metaObject().methodCount()) # prints 5
t.sig.connect(t.test)
print(t.metaObject().methodCount()) # prints 6
t.sig.connect(t._Test__test) # name mangling is applied to the __test method
print(t.metaObject().methodCount()) # still prints 6!
这意味着这样的方法被视为正常函数,它连接到一个信号,将始终在主事件线程中运行。如果你真的想要使用以__
开头的方法名称,你需要明确地将它装饰成一个插槽,然后它应该工作:
from PySide.QtCore import QThread, QObject, QCoreApplication, QTimer, Slot
import time
import sys
class BackgroundWorker(QObject):
def __init__(self):
QObject.__init__(self)
@Slot()
def __process(self):
self.process()
...