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

Mae*_*cky 7 python multithreading pyqt pyqt4 python-3.x

我有一个线程类"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_())
Run Code Online (Sandbox Code Playgroud)

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

thr*_*les 10

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

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

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

码:

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_()
Run Code Online (Sandbox Code Playgroud)

  • @two_pineapples 不确定它在 PyQt 中是如何进行的,以及它是否在内部得到处理,但是在 Qt C++ 中,当您不清理对象并且还调用退出线程时,一旦您停止应用程序,您就会收到一条警告,表明线程已过早销毁。我也不确定将动态分配的“QObject”(即使它是 PyQt 下面我们有 C++)移动到“QThread”是否也会使“QThread”成为该对象的父对象。如果不是这种情况,我们就会遇到内存泄漏(再次 - 此处讨论的是底层 C++)。 (2认同)