gpt4 book ai didi

python - PyQt线程通信帮助? QThread 和 QObject

转载 作者:太空狗 更新时间:2023-10-30 02:58:46 28 4
gpt4 key购买 nike

阅读和搜索后,我尝试使用生成 QObject 然后使用 movetoThread 方法运行独立进程并允许 QMainWindow 继续响应。当我尝试在 QThread.run() 方法中实现该操作时,这没有用。下面的代码是我尝试做一个简单的例子。虽然代码在独立于 MainWindow 的运行线程中运行,但它不会中止。让线程停止的唯一方法是设置 worker.end = True。我认为不应该这样做。

"""
This is a program to test Threading with Objects in PyQt4.
"""

from time import sleep
import sys

from PyQt4.QtCore import QObject, pyqtSlot, pyqtSignal, QThread
from PyQt4.QtGui import QMainWindow, QApplication, QProgressBar
from PyQt4.QtGui import QPushButton, QVBoxLayout, QWidget

class workerObject(QObject):
bar_signal = pyqtSignal(int)
res_signal = pyqtSignal(str)
term_signal = pyqtSignal()

def __init__(self, maxIters):
super(workerObject, self).__init__()
self.maxIters = maxIters

def run(self):
self.bar_signal.emit(self.maxIters)
sleep(1)
self.end = False

for step in range(self.maxIters):
if self.end:
self.maxIters = step
break
self.bar_signal.emit(step)
sleep(2)

self.res_signal.emit("Got to {}".format(self.maxIters))
self.term_signal.emit()

@pyqtSlot()
def mystop(self):
print "stop signalled?"
self.end = True

class MCwindow(QMainWindow):
abort_signal = pyqtSignal(name='abort_signal')

def __init__(self):
super(MCwindow,self).__init__()
self.maxIters = 50

widget = QWidget()
layout = QVBoxLayout(widget)
self.go_btn = QPushButton()
self.go_btn.setText('Go')
layout.addWidget(self.go_btn)
self.abort_btn = QPushButton()
self.abort_btn.setText('Stop')
layout.addWidget(self.abort_btn)
self.simulation_bar = QProgressBar()
self.simulation_bar.setRange(0, self.maxIters)
self.simulation_bar.setFormat("%v")
layout.addWidget(self.simulation_bar)
self.setCentralWidget(widget)

self.go_btn.clicked.connect(self.run_mc)
# The button calls the windows method to stop --- it could
# be that is 'clicked' calls the worker.mystop
# self.abort_btn.clicked.connect(self.stop_mc)
# This allows for the abort button to do somethign in the MainWindow
# before the abort_signal is sent, this works
self.abort_btn.clicked.connect(self.stop_mc)

def run_mc(self):
self.thread = QThread()
self.worker = workerObject(self.maxIters)
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
# This is the simple stop method, but does not work
# self.abort_btn.clicked.connect(self.worker.mystop)
# This uses the signal in the MCwindow - this connection does NOT works
self.abort_signal.connect(self.worker.mystop)
# This does NOT stop the thread
# and would not allow for any clean up in the worker.
# self.abort_signal.connect(self.thread.terminate)
# This is a 'bad' way to stop the woker ... It does, however, work
# self.abort_signal.connect(self.stopper)
self.worker.bar_signal.connect(self.setBar)
self.worker.res_signal.connect(self.setData)
self.worker.term_signal.connect(self.thread.terminate)
self.thread.start()

def stop_mc(self):
print "Stopping?!"
# This signal is NEVER seen by the Worker.
self.abort_signal.emit()

def stopper(self):
print "I should stop?!"
# Should use signals to tell the worker to stop - and not setting a attribute
self.worker.end=True

@pyqtSlot(int)
def setBar(self, val):
self.simulation_bar.setValue(val)

@pyqtSlot(str)
def setData(self, txt):
print "Got done Sig!", txt

if __name__ == '__main__':
app = QApplication(sys.argv)
window = MCwindow()
window.show()
sys.exit(app.exec_())

最佳答案

连接到 abort_signal 的插槽似乎没有被调用的原因是因为默认情况下跨线程信号排队。这意味着信号将被包装为一个事件并发布到接收者所在的任何线程的事件队列中。

在您的特定示例中,接收器是一个工作对象,它已被移动到工作线程。在工作线程上调用 start() 将启动其事件循环,这就是 abort_signal 将排队的地方。但是,worker 对象的 run() 方法启动了一个 for 循环,这将阻塞线程的事件处理,其方式与它完全相同如果它在主 gui 线程中执行,会怎样!

如果您对示例进行一些调整,您可以更清楚地看到发生了什么:

class MCwindow(QMainWindow):
abort_signal = pyqtSignal(name='abort_signal')

def __init__(self):
super(MCwindow,self).__init__()
# use a sane default
self.maxIters = 5
...
# DO NOT use QThread.terminate
self.worker.term_signal.connect(self.thread.quit)

现在运行示例,然后点击Go按钮,点击Stop按钮,等待worker正常完成。这应该产生如下输出:

Stopping?!
Got done Sig! Got to 5
stop signalled?

请注意,“停止信号”是 last 的输出 - 即 after run() 退出并且控制权已返回到线程的事件循环.为了在 worker 运行时处理传入信号,您需要强制立即处理线程的未决事件。这可以像这样完成:

     for step in range(self.maxIters):
QApplication.processEvents()
...

有了它,您应该会看到这样的输出:

Stopping?!
stop signalled?
Got done Sig! Got to 2

这大概是您的意图。

关于python - PyQt线程通信帮助? QThread 和 QObject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33108337/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com