简体   繁体   English

暂停工作线程并等待主线程中的事件

[英]Pause worker thread and wait for event from main thread

We have an application that executes different queries. 我们有一个执行不同查询的应用程序。 It starts up to four threads, and runs the extractions on them. 它最多启动四个线程,并在它们上运行提取。

That part looks like this: 那部分看起来像这样:

    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

Our Extractor class inherits QThread : 我们的Extractor类继承了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)

and self.ui is set to Ui_MainWindow() : self.ui设置为Ui_MainWindow()

class Cont(QMainWindow):
    def __init__(self, parent=None):
        QWidget.__init__(self,parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

There is a specific base that sends data to the user (back to the main window) before proceeding (in this case, a pop-up with two buttons): 在继续之前,有一个特定的基础将数据发送给用户(返回主窗口)(在这种情况下,带有两个按钮的弹出窗口):

#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_()

How can I pause the thread at a certain point, display the window (which I believe would be returning to the main thread) and return to the worker thread, passing the button clicked event? 如何在特定点暂停线程,显示窗口(我相信将返回主线程)并返回工作线程,传递按钮点击事件?

I read a bit about signals but it seems confusing as it is my first time dealing with threads. 我读了一些关于信号的内容,但它似乎令人困惑,因为这是我第一次处理线程。

Edit: After reading this question: Similar question , I altered the code to this: 编辑:阅读此问题后: 类似问题 ,我将代码更改为:

On a method inside of the Cont class Cont类的内部方法

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

and this is the Worker class: 这是Worker类:

class Worker(QObject):

    #Signals
    bv = pyqtSignal(int)

    def process(self):
        self.bv.emit(99)

Now I just need to figure out how to send the ret value back to the worker thread so it starts the second process. 现在我只需要弄清楚如何将ret值发送回工作线程,以便启动第二个进程。 I also keep getting this error: 我也一直收到这个错误:

TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'

Below is a simple demo based on the code in your question which does what you want. 下面是一个基于您的问题中的代码的简单演示,它可以满足您的需求。 There is not much to say about it, really, other than that you need to communicate between the worker and the main thread via signals (in both directions). 除此之外,没有什么可说的,除了你需要通过信号(两个方向)在工作者和主线程之间进行通信。 The finished signal is used to quit the thread, which will stop the warning message QThread: "Destroyed while thread is still running" being shown. finished信号用于退出线程,这将停止警告消息QThread: "Destroyed while thread is still running"QThread: "Destroyed while thread is still running"被显示。

The reason why you are seeing the error: 您看到错误的原因:

TypeError: connect() slot argument should be a callable or a signal, not `NoneType'

is because you are trying to connect a signal with the return value of a function (which is None ), rather than the function object itself. 是因为您尝试使用函数的返回值( None )来连接信号,而不是函数对象本身。 You must always pass a python callable object to the connect method - anything else will raise a TypeError . 您必须始终将python可调用对象传递给connect方法 - 其他任何东西都会引发TypeError

Please run the script below and confirm that it works as expected. 请运行下面的脚本并确认它按预期工作。 Hopefully it should be easy to see how to adapt it to work with your real code. 希望应该很容易看到如何使其适应您的真实代码。

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 you want the thread to wait for the action, connect to a signal from the thread using 如果您希望线程等待操作,请使用线程连接到线程的信号

PyQt4.QtCore.Qt.BlockingQueuedConnection

as flag. 作为旗帜。

Now I do not understand why you need threading if you let them wait, which brings in a lot of complexity. 现在我不明白为什么你需要线程如果你让他们等待,这会带来很多复杂性。 For me the better solution would be to cut the task you want to perform in the threads in smaller pieces. 对我来说,更好的解决方案是将您想要在线程中执行的任务切成小块。 Each time a piece is ready, you can ask if the user wants the next too. 每次准备就绪时,您都可以询问用户是否还想要下一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM