PyQt4 在线程中等待来自 GUI 的用户输入
PyQt4 Wait in thread for user input from GUI
我有一个线程 class "MyThread" 和我的主应用程序,简称为 "Gui"。我想从线程 class 创建一些对象,但在这个例子中我只创建了一个对象。线程 class 做了一些工作,然后向 Gui class 发出一个信号,指示需要用户输入(目前这个指示只是更改按钮的文本)。然后线程应等待用户输入(在本例中为单击按钮),然后继续执行它正在执行的操作...
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_())
如何在(多个)线程中等待用户输入?
默认情况下,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_()
我有一个线程 class "MyThread" 和我的主应用程序,简称为 "Gui"。我想从线程 class 创建一些对象,但在这个例子中我只创建了一个对象。线程 class 做了一些工作,然后向 Gui class 发出一个信号,指示需要用户输入(目前这个指示只是更改按钮的文本)。然后线程应等待用户输入(在本例中为单击按钮),然后继续执行它正在执行的操作...
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_())
如何在(多个)线程中等待用户输入?
默认情况下,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_()