python multithreading python-3.x pyqt pyqt4

python - PyQt4 Espere en el hilo para la entrada del usuario desde la GUI



multithreading python-3.x (1)

Tengo una clase de hilo "MyThread" y mi aplicación principal que simplemente se llama "Gui". Quiero crear algunos objetos de la clase de hilo pero para este ejemplo creé solo un objeto. La clase de subproceso hace algo de trabajo, luego emite una señal a la clase Gui, indicando que se necesita una entrada del usuario (esta indicación por ahora simplemente está cambiando el texto de un botón). Luego, el hilo debe esperar una entrada del usuario (en este caso, un clic en el botón) y luego continuar haciendo lo que está haciendo ...

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

¿Cómo puedo esperar en (múltiples) hilos una entrada del usuario?


Por defecto, un QThread tiene un bucle de eventos que puede procesar señales y ranuras. En su implementación actual, desafortunadamente ha eliminado este comportamiento al anular QThread.run . Si lo restaura, puede obtener el comportamiento que desea.

Entonces, si no puede anular QThread.run() , ¿cómo lo hace enhebrar en Qt? Un enfoque alternativo al subprocesamiento es colocar el código en una subclase de QObject y mover ese objeto a una instancia estándar de QThread . Luego puede conectar señales y ranuras entre el hilo principal y el QThread para comunicarse en ambas direcciones. Esto le permitirá implementar su comportamiento deseado.

En el siguiente ejemplo, comencé un subproceso de trabajo que imprime en el terminal, espera 2 segundos, imprime nuevamente y luego espera la entrada del usuario. Cuando se hace clic en el botón, se ejecuta una segunda función separada en el subproceso de trabajo e imprime en el terminal con el mismo patrón que la primera vez. Tenga en cuenta el orden en que uso moveToThread() y conecto las señales (según this ).

Código:

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