简体   繁体   English

PyQt4在线程中等待来自GUI的用户输入

[英]PyQt4 Wait in thread for user input from GUI

I have a thread class "MyThread" and my main application which is simply called "Gui". 我有一个线程类“ MyThread”和我的主应用程序,简称为“ Gui”。 I want to create a few objects from the thread class but for this example I created only one object. 我想从线程类创建一些对象,但在本示例中,我仅创建了一个对象。 The thread class does some work, then emits a signal to the Gui class, indicating that a user input is needed (this indication for now is simply changing the text of a button). 线程类完成一些工作,然后向Gui类发出信号,指示需要用户输入(此指示目前仅是更改按钮的文本)。 Then the thread should wait for a user input (in this case a button click) and then continue doing what it is doing... 然后线程应等待用户输入(在这种情况下为单击按钮),然后继续执行其操作...

from PyQt4 import QtGui, QtCore
class MyTrhead(QtCore.QThread):
    trigger = QtCore.pyqtSignal(str)

    def run(self):
        print(self.currentThreadId())
        for i in range(0,10):
            print("working ")
            self.trigger.emit("3 + {} = ?".format(i))
            #### WAIT FOR RESULT
            time.sleep(1)


class Gui(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(Gui, self).__init__(parent)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.btn)

        self.t1 = MyTrhead()
        self.t1.trigger.connect(self.dispaly_message)
        self.t1.start()
        print("thread: {}".format(self.t1.isRunning()))


    @QtCore.pyqtSlot(str)
    def dispaly_message(self, mystr):
        self.pushButton.setText(mystr)

    def btn(self):
        print("Return result to corresponding thread")



if "__main__" == __name__:
    import sys
    app = QtGui.QApplication(sys.argv)
    m = Gui()
    m.show()
    sys.exit(app.exec_())

How can I wait in (multiple) threads for a user input? 如何在(多个)线程中等待用户输入?

By default, a QThread has an event loop that can process signals and slots. 默认情况下, QThread具有事件循环,可以处理信号和插槽。 In your current implementation, you have unfortunately removed this behaviour by overriding QThread.run . 在当前的实现中,不幸的是,您通过重写QThread.run删除了此行为。 If you restore it, you can get the behaviour you desire. 如果还原它,则可以得到所需的行为。

So if you can't override QThread.run() , how do you do threading in Qt? 因此,如果您不能覆盖QThread.run() ,那么如何在Qt中进行线程处理? An alternative approach to threading is to put your code in a subclass of QObject and move that object to a standard QThread instance. 另一种线程化方法是将代码放入QObject的子类中,然后将该对象移至标准QThread实例。 You can then connect signals and slots together between the main thread and the QThread to communicate in both directions. 然后,您可以将信号和插槽连接到主线程和QThread之间,以双向通信。 This will allow you to implement your desired behaviour. 这将使您能够实现所需的行为。

In the example below, I've started a worker thread which prints to the terminal, waits 2 seconds, prints again and then waits for user input. 在下面的示例中,我启动了一个工作线程,该工作线程将打印到终端,等待2秒钟,再次打印,然后等待用户输入。 When the button is clicked, a second separate function in the worker thread runs, and prints to the terminal in the same pattern as the first time. 单击该按钮时,工作线程中的第二个单独的函数运行,并以与第一次相同的模式打印到终端。 Please note the order in which I use moveToThread() and connect the signals (as per this ). 请注意我使用moveToThread()并连接信号的顺序(按照this )。

Code: 码:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import time

class MyWorker(QObject):

    wait_for_input = pyqtSignal()
    done = pyqtSignal()


    @pyqtSlot()
    def firstWork(self):
        print 'doing first work'
        time.sleep(2)
        print 'first work done'
        self.wait_for_input.emit()

    @pyqtSlot()
    def secondWork(self):
        print 'doing second work'
        time.sleep(2)
        print 'second work done'
        self.done.emit()


class Window(QWidget):
    def __init__(self, parent = None):
        super(Window, self).__init__()

        self.initUi()
        self.setupThread()

    def initUi(self):
        layout = QVBoxLayout()
        self.button = QPushButton('User input')
        self.button.setEnabled(False)
        layout.addWidget(self.button)
        self.setLayout(layout)
        self.show()

    @pyqtSlot()
    def enableButton(self):
        self.button.setEnabled(True)

    @pyqtSlot()    
    def done(self):
        self.button.setEnabled(False)

    def setupThread(self):
        self.thread = QThread()
        self.worker = MyWorker()

        self.worker.moveToThread(self.thread)

        self.thread.started.connect(self.worker.firstWork)
        self.button.clicked.connect(self.worker.secondWork)
        self.worker.wait_for_input.connect(self.enableButton)
        self.worker.done.connect(self.done)

        # Start thread
        self.thread.start()    

if __name__ == "__main__":
    app = QApplication([])
    w = Window()
    app.exec_()

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

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