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

时间:2016-02-20 18:41:07

标签: python multithreading python-3.x pyqt pyqt4

我有一个线程类" MyThread"我的主要应用程序简称为#Gui"。我想从线程类创建一些对象,但是对于这个例子,我只创建了一个对象。线程类做了一些工作,然后向Gui类发出一个信号,指示需要用户输入(此指示现在只是更改按钮的文本)。然后线程应该等待用户输入(在这种情况下是一个按钮点击),然后继续做它正在做的事情......

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

如何在(多个)线程中等待用户输入?

1 个答案:

答案 0 :(得分:8)

默认情况下,QThread有一个可以处理信号和插槽的事件循环。在您当前的实现中,遗憾的是,通过覆盖QThread.run来删除此行为。如果你恢复它,你可以得到你想要的行为。

所以如果你不能覆盖QThread.run(),你如何在Qt中进行线程化?另一种线程方法是将代码放在QObject的子类中,并将该对象移动到标准QThread实例。然后,您可以在主线程和QThread之间将信号和插槽连接在一起,以便在两个方向上进行通信。这将允许您实现所需的行为。

在下面的例子中,我启动了一个工作线程,它打印到终端,等待2秒,再次打印,然后等待用户输入。单击该按钮时,工作线程中的第二个单独函数运行,并以与第一次相同的模式打印到终端。请注意我使用moveToThread()的顺序并连接信号(根据this)。

代码:

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