2015-12-09 24 views
11

Ho la seguente pyqtmain.py:PyQt4: come mettere in pausa una discussione fino a quando non viene emesso un segnale?

#!/usr/bin/python3 
import sys 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 
from pyqtMeasThread import * 


class MainWindow(QMainWindow): 
    def __init__(self, parent=None): 
     self.qt_app = QApplication(sys.argv) 
     QMainWindow.__init__(self, parent) 

     buttonWidget = QWidget() 
     rsltLabel = QLabel("Result:") 
     self.rsltFiled = QLineEdit() 
     self.buttonStart = QPushButton("Start") 

     verticalLayout = QVBoxLayout(buttonWidget) 
     verticalLayout.addWidget(rsltLabel) 
     verticalLayout.addWidget(self.rsltFiled) 
     verticalLayout.addWidget(self.buttonStart) 

     butDW = QDockWidget("Control", self) 
     butDW.setWidget(buttonWidget) 
     self.addDockWidget(Qt.LeftDockWidgetArea, butDW) 

     self.mthread = QThread() # New thread to run the Measurement Engine 
     self.worker = MeasurementEngine() # Measurement Engine Object 

     self.worker.moveToThread(self.mthread) 
     self.mthread.finished.connect(self.worker.deleteLater) # Cleanup after thread finished 

     self.worker.measure_msg.connect(self.showRslt) 

     self.buttonStart.clicked.connect(self.worker.run) 

     # Everything configured, start the worker thread. 
     self.mthread.start() 

    def run(self): 
     """ Show the window and start the event loop """ 
     self.show() 
     self.qt_app.exec_() # Start event loop 

    @pyqtSlot(str) 
    def showRslt(self, mystr): 
     self.rsltFiled.setText(mystr) 


def main(): 
    win = MainWindow() 
    win.run() 


if __name__ == '__main__': 
    main() 

E un altro script filo di eseguire la misura reale:

from PyQt4.QtCore import * 
import time 

class MeasurementEngine(QObject): 
    measure_msg = pyqtSignal(str) 
    def __init__(self): 
     QObject.__init__(self) # Don't forget to call base class constructor 

    @pyqtSlot() 
    def run(self): 
     self.measure_msg.emit('phase1') 
     time.sleep(2) # here I would like to make it as an interrupt 
     self.measure_msg.emit('phase2') 

di questo codice ora è che dopo che il pulsante di avvio viene premuto, la funzione di corsa nel thread verrà eseguito. Tuttavia, effettivamente nell'esecuzione della funzione, ci sono due fasi della misurazione. In questo momento ho usato un ritardo.

Ma quello che vorrei implementare in realtà è che dopo la misurazione di "fase1" viene eseguita. Verrà visualizzata una finestra di messaggio e, allo stesso tempo, la discussione verrà messa in pausa/trattenuta. Fino a quando l'utente non ha chiuso la finestra del messaggio, la funzione thread verrà ripristinata.

risposta

2

Non è possibile visualizzare uno QDialog all'interno di uno QThread. Tutte le informazioni relative alla GUI devono essere eseguite nel thread della GUI (quello che ha creato l'oggetto QApplication). Che cosa si potrebbe fare è quella di utilizzare 2 QThread:

  • 1 °: eseguire fase1. È possibile collegare il segnale finished a questo QThread a uno slot nel QMainWindow che visualizzerà il popup (utilizzando QDialog.exec_() in modo che sia modale).
  • 2 °: eseguire phase2. Si crea il QThread dopo che il popup mostrato qui sopra è stato chiuso.
1

Il thread può emettere un segnale alla finestra principale per mostrare la finestra di dialogo. Se non si desidera chiudere il thread mentre la finestra di dialogo è aperta, il thread potrebbe entrare in un ciclo while per l'attesa. Nel ciclo while è possibile controllare continuamente una variabile che il thread principale può impostare su true al termine della finestra di dialogo. Questa potrebbe non essere la soluzione più pulita, ma dovrebbe funzionare.

Per chiarire la mia risposta un po ', ho aggiunto qualche pseudo codice. Quello che ti interessa è come condividere la variabile dialog_closed. Potresti ad es. utilizzare una variabile membro della classe thread.

Thread: 
emit_signal 
dialog_closed = False 
while not dialog_closed: 
    pass 
go_on_with_processing 

MainThread: 
def SignalRecieved(): 
    open_dialog 
    dialog_closed = True 
5

Utilizzare un QWaitCondition dal modulo QtCore. Usando un blocco mutex, si imposta il thread in background per attendere/dormire fino a quando il thread in primo piano non lo riattiva. Poi continuerà a fare il suo lavoro da lì.

#!/usr/bin/python3 
import sys 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 
from pyqtMeasThread import * 


class MainWindow(QMainWindow): 
    def __init__(self, parent=None): 
     self.qt_app = QApplication(sys.argv) 
     QMainWindow.__init__(self, parent) 

     buttonWidget = QWidget() 
     rsltLabel = QLabel("Result:") 
     self.rsltFiled = QLineEdit() 
     self.buttonStart = QPushButton("Start") 

     verticalLayout = QVBoxLayout(buttonWidget) 
     verticalLayout.addWidget(rsltLabel) 
     verticalLayout.addWidget(self.rsltFiled) 
     verticalLayout.addWidget(self.buttonStart) 

     butDW = QDockWidget("Control", self) 
     butDW.setWidget(buttonWidget) 
     self.addDockWidget(Qt.LeftDockWidgetArea, butDW) 

     self.mutex = QMutex() 
     self.cond = QWaitCondition() 
     self.mthread = QThread() # New thread to run the Measurement Engine 
     self.worker = MeasurementEngine(self.mutex, self.cond) # Measurement Engine Object 

     self.worker.moveToThread(self.mthread) 
     self.mthread.finished.connect(self.worker.deleteLater) # Cleanup after thread finished 

     self.worker.measure_msg.connect(self.showRslt) 

     self.buttonStart.clicked.connect(self.worker.run) 

     # Everything configured, start the worker thread. 
     self.mthread.start() 

    def run(self): 
     """ Show the window and start the event loop """ 
     self.show() 
     self.qt_app.exec_() # Start event loop 

    # since this is a slot, it will always get run in the event loop in the main thread 
    @pyqtSlot(str) 
    def showRslt(self, mystr): 
     self.rsltFiled.setText(mystr) 
     msgBox = QMessageBox(parent=self) 
     msgBox.setText("Close this dialog to continue to Phase 2.") 
     msgBox.exec_() 
     self.cond.wakeAll() 


def main(): 
    win = MainWindow() 
    win.run() 


if __name__ == '__main__': 
    main() 

E:

from PyQt4.QtCore import * 
import time 

class MeasurementEngine(QObject): 
    measure_msg = pyqtSignal(str) 
    def __init__(self, mutex, cond): 
     QObject.__init__(self) # Don't forget to call base class constructor 
     self.mtx = mutex 
     self.cond = cond 

    @pyqtSlot() 
    def run(self): 
     # NOTE: do work for phase 1 here 
     self.measure_msg.emit('phase1') 
     self.mtx.lock() 
     try: 
      self.cond.wait(self.mtx) 
      # NOTE: do work for phase 2 here 
      self.measure_msg.emit('phase2') 
     finally: 
      self.mtx.unlock() 

tuo tempismo è un po 'fuori in tutto questo però. Crea l'app e avvia la discussione prima ancora di mostrare la tua finestra. Pertanto, la finestra di messaggio comparirà su prima dello, anche la finestra principale si apre. Per ottenere la giusta sequenza di eventi, è necessario avviare il thread come parte del metodo run della MainWindow, dopo, è già stata visualizzata la finestra principale. Se si desidera che la condizione di attesa sia separata dall'impostazione dei messaggi, potrebbe essere necessario un segnale e uno slot separati per gestirlo.

Problemi correlati