暂停工作线程并等待来自主线程的事件
Pause worker thread and wait for event from main thread
我们有一个执行不同查询的应用程序。它最多启动四个线程,并在它们上运行提取。
那部分看起来像这样:
if len(self.threads) == 4:
self.__maxThreadsMsg(base)
return False
else:
self.threads.append(Extractor(self.ui, base))
self.threads[-1].start()
self.__extractionMsg(base)
return True
我们的Extractor
class继承QThread
:
class Extractor(QThread):
def init(self, ui, base):
QThread.__init__(self)
self.ui = ui
self.base = base
def run(self):
self.run_base(base)
和 self.ui
设置为 Ui_MainWindow()
:
class Cont(QMainWindow):
def __init__(self, parent=None):
QWidget.__init__(self,parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
有一个特定的基础在继续之前将数据发送给用户(返回主window)(在本例中,有两个按钮的弹出窗口):
#This code is in the main file inside a method, not in the Extractor class
msg_box = QMessagebox()
msg_box.setText('Quantity in base: '.format(n))
msg_box.setInformativeText('Would you like to continue?')
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
signal = msg_box.exec_()
我怎样才能在某个点暂停线程,显示 window (我相信这将 returning 到主线程)和 return 到工作线程, 传递按钮点击事件?
我读了一些关于信号的内容,但它似乎令人困惑,因为这是我第一次处理线程。
编辑: 看完这个问题:,我把代码改成这样:
On a method inside Cont class
thread = QThread(self)
worker = Worker()
worker.moveToThread(thread)
worker.bv.connect(self.bv_test)
thread.started.connect(worker.process()) # This, unlike in the linked question..
#doesn't work if I remove the parentheses of the process function.
#If I remove it, nothing happens and I get QThread: "Destroyed while thread is still running"
thread.start()
@pyqtSlot(int)
def bv_test(self, n):
k = QMessageBox()
k.setText('Quantity: {}'.format(n))
k.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
ret = k.exec_()
return ret
这是 Worker
class:
class Worker(QObject):
#Signals
bv = pyqtSignal(int)
def process(self):
self.bv.emit(99)
现在我只需要弄清楚如何将 ret
值发送回工作线程,以便它启动第二个进程。我也不断收到此错误:
TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'
如果您希望线程等待操作,请使用
连接到来自线程的信号
PyQt4.QtCore.Qt.BlockingQueuedConnection
作为标志。
现在我不明白如果让它们等待,为什么还需要线程,这会带来很多复杂性。对我来说,更好的解决方案是将要在线程中执行的任务分成更小的部分。每次准备好一件作品时,您都可以询问用户是否也想要下一件。
下面是一个简单的演示,它基于您问题中的代码,可以满足您的要求。关于它没什么可说的,真的,除了你需要通过信号(双向)在工作线程和主线程之间进行通信。 finished
信号用于退出线程,这将停止显示警告消息 QThread: "Destroyed while thread is still running"
。
您看到错误的原因:
TypeError: connect() slot argument should be a callable or a signal, not `NoneType'
是因为您试图将信号与函数的 return 值(即 None
)连接,而不是函数对象本身。您必须始终将 python 可调用对象传递给 connect
方法 - 任何其他方法都会引发 TypeError
.
请运行下面的脚本并确认它按预期工作。希望应该很容易看出如何使它适应您的实际代码。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Cont(QWidget):
confirmed = pyqtSignal()
def __init__(self):
super(Cont, self).__init__()
self.thread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.worker.bv.connect(self.bv_test)
self.worker.finished.connect(self.thread.quit)
self.confirmed.connect(self.worker.process_two)
self.thread.started.connect(self.worker.process_one)
self.thread.start()
def bv_test(self, n):
k = QMessageBox(self)
k.setAttribute(Qt.WA_DeleteOnClose)
k.setText('Quantity: {}'.format(n))
k.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
if k.exec_() == QMessageBox.Yes:
self.confirmed.emit()
else:
self.thread.quit()
class Worker(QObject):
bv = pyqtSignal(int)
finished = pyqtSignal()
def process_two(self):
print('process: two: started')
QThread.sleep(1)
print('process: two: finished')
self.finished.emit()
def process_one(self):
print('process: one: started')
QThread.sleep(1)
self.bv.emit(99)
print('process: one: finished')
app = QApplication([''])
win = Cont()
win.setGeometry(100, 100, 100, 100)
win.show()
app.exec_()
我们有一个执行不同查询的应用程序。它最多启动四个线程,并在它们上运行提取。
那部分看起来像这样:
if len(self.threads) == 4:
self.__maxThreadsMsg(base)
return False
else:
self.threads.append(Extractor(self.ui, base))
self.threads[-1].start()
self.__extractionMsg(base)
return True
我们的Extractor
class继承QThread
:
class Extractor(QThread):
def init(self, ui, base):
QThread.__init__(self)
self.ui = ui
self.base = base
def run(self):
self.run_base(base)
和 self.ui
设置为 Ui_MainWindow()
:
class Cont(QMainWindow):
def __init__(self, parent=None):
QWidget.__init__(self,parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
有一个特定的基础在继续之前将数据发送给用户(返回主window)(在本例中,有两个按钮的弹出窗口):
#This code is in the main file inside a method, not in the Extractor class
msg_box = QMessagebox()
msg_box.setText('Quantity in base: '.format(n))
msg_box.setInformativeText('Would you like to continue?')
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
signal = msg_box.exec_()
我怎样才能在某个点暂停线程,显示 window (我相信这将 returning 到主线程)和 return 到工作线程, 传递按钮点击事件?
我读了一些关于信号的内容,但它似乎令人困惑,因为这是我第一次处理线程。
编辑: 看完这个问题:
On a method inside Cont class
thread = QThread(self)
worker = Worker()
worker.moveToThread(thread)
worker.bv.connect(self.bv_test)
thread.started.connect(worker.process()) # This, unlike in the linked question..
#doesn't work if I remove the parentheses of the process function.
#If I remove it, nothing happens and I get QThread: "Destroyed while thread is still running"
thread.start()
@pyqtSlot(int)
def bv_test(self, n):
k = QMessageBox()
k.setText('Quantity: {}'.format(n))
k.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
ret = k.exec_()
return ret
这是 Worker
class:
class Worker(QObject):
#Signals
bv = pyqtSignal(int)
def process(self):
self.bv.emit(99)
现在我只需要弄清楚如何将 ret
值发送回工作线程,以便它启动第二个进程。我也不断收到此错误:
TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'
如果您希望线程等待操作,请使用
连接到来自线程的信号PyQt4.QtCore.Qt.BlockingQueuedConnection
作为标志。
现在我不明白如果让它们等待,为什么还需要线程,这会带来很多复杂性。对我来说,更好的解决方案是将要在线程中执行的任务分成更小的部分。每次准备好一件作品时,您都可以询问用户是否也想要下一件。
下面是一个简单的演示,它基于您问题中的代码,可以满足您的要求。关于它没什么可说的,真的,除了你需要通过信号(双向)在工作线程和主线程之间进行通信。 finished
信号用于退出线程,这将停止显示警告消息 QThread: "Destroyed while thread is still running"
。
您看到错误的原因:
TypeError: connect() slot argument should be a callable or a signal, not `NoneType'
是因为您试图将信号与函数的 return 值(即 None
)连接,而不是函数对象本身。您必须始终将 python 可调用对象传递给 connect
方法 - 任何其他方法都会引发 TypeError
.
请运行下面的脚本并确认它按预期工作。希望应该很容易看出如何使它适应您的实际代码。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Cont(QWidget):
confirmed = pyqtSignal()
def __init__(self):
super(Cont, self).__init__()
self.thread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.worker.bv.connect(self.bv_test)
self.worker.finished.connect(self.thread.quit)
self.confirmed.connect(self.worker.process_two)
self.thread.started.connect(self.worker.process_one)
self.thread.start()
def bv_test(self, n):
k = QMessageBox(self)
k.setAttribute(Qt.WA_DeleteOnClose)
k.setText('Quantity: {}'.format(n))
k.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
if k.exec_() == QMessageBox.Yes:
self.confirmed.emit()
else:
self.thread.quit()
class Worker(QObject):
bv = pyqtSignal(int)
finished = pyqtSignal()
def process_two(self):
print('process: two: started')
QThread.sleep(1)
print('process: two: finished')
self.finished.emit()
def process_one(self):
print('process: one: started')
QThread.sleep(1)
self.bv.emit(99)
print('process: one: finished')
app = QApplication([''])
win = Cont()
win.setGeometry(100, 100, 100, 100)
win.show()
app.exec_()