2013-04-26 10 views
7

Sto cercando di capire come utilizzare la segnalazione da un Qthread all'interfaccia Gui avviata.Come segnalare un QThread in esecuzione al PyQt Gui che lo ha avviato?

Configurazione: ho un processo (una simulazione) che deve essere eseguito quasi indefinitamente (o almeno per lunghi periodi di tempo)., Mentre è in esecuzione, esegue vari calcoli, e alcuni dei risultati devono essere rimandati alla GUI, che li visualizzerà in modo appropriato in tempo reale. Sto usando PyQt per la GUI. Inizialmente ho provato ad usare il modulo di threading di python, poi sono passato a QThreads dopo aver letto diversi post sia qui su SO che altrove.

In base a questo post sul Qt Blog You're doing it wrong, il modo migliore per utilizzare QThread è creare un QObject e quindi spostarlo in un Qthread. Così ho seguito il consiglio in Thread di riempimento con QThread in PyQt "> questa domanda SO e ho provato una semplice app di test (codice di seguito): apre una semplice GUI, consente di avviare il processo in background e emette un aggiornamento del valore del passo in ... una casella numerica

Ma non funziona L'interfaccia grafica è mai aggiornato che cosa sto facendo di sbagliato

import time, sys 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 

class SimulRunner(QObject): 
    'Object managing the simulation' 

    stepIncreased = pyqtSignal(int, name = 'stepIncreased') 
    def __init__(self): 
     super(SimulRunner, self).__init__() 
     self._step = 0 
     self._isRunning = True 
     self._maxSteps = 20 

    def longRunning(self): 
     while self._step < self._maxSteps and self._isRunning == True: 
      self._step += 1 
      self.stepIncreased.emit(self._step) 
      time.sleep(0.1) 

    def stop(self): 
     self._isRunning = False 

class SimulationUi(QDialog): 
    'PyQt interface' 

    def __init__(self): 
     super(SimulationUi, self).__init__() 

     self.goButton = QPushButton('Go') 
     self.stopButton = QPushButton('Stop') 
     self.currentStep = QSpinBox() 

     self.layout = QHBoxLayout() 
     self.layout.addWidget(self.goButton) 
     self.layout.addWidget(self.stopButton) 
     self.layout.addWidget(self.currentStep) 
     self.setLayout(self.layout) 

     self.simulRunner = SimulRunner() 
     self.simulThread = QThread() 
     self.simulRunner.moveToThread(self.simulThread) 
     self.simulRunner.stepIncreased.connect(self.currentStep.setValue) 


     self.connect(self.stopButton, SIGNAL('clicked()'), self.simulRunner.stop) 
     self.connect(self.goButton, SIGNAL('clicked()'), self.simulThread.start) 
     self.connect(self.simulRunner,SIGNAL('stepIncreased'), self.currentStep.setValue) 


if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    simul = SimulationUi() 
    simul.show() 
    sys.exit(app.exec_()) 

risposta

7

Il problema qui è semplice: il vostro SimulRunner non viene mai inviato un segnale che causa l'avvio un modo per farlo sarebbe quello di collegarlo al segnale della Discussione.

A lso, in Python dovresti usare il nuovo modo di connettere i segnali:

... 
self.simulRunner = SimulRunner() 
self.simulThread = QThread() 
self.simulRunner.moveToThread(self.simulThread) 
self.simulRunner.stepIncreased.connect(self.currentStep.setValue) 
self.stopButton.clicked.connect(self.simulRunner.stop) 
self.goButton.clicked.connect(self.simulThread.start) 
# start the execution loop with the thread: 
self.simulThread.started.connect(self.simulRunner.longRunning) 
... 
+1

Hai perfettamente ragione, ho appena realizzato l'errore. Ho tagliato e incollato il codice da una versione precedente in cui stavo sottoclasse Qthread invece di usare moveToThread e mi sono completamente dimenticato del metodo started(). Grazie per segnalarlo. – stefano

+0

questo è un esempio molto interessante. Comunque segui questo suggerimento il thread inizia ma il pulsante stop non lo ferma. Sarebbe bello avere un esempio funzionante. E forse un pulsante Go che può riavviare il tutto – Fabrizio

+0

Lo stop invia semplicemente un segnale, ma come 'simulThread' è occupato nell'esecuzione di' longRunning', quel segnale può essere processato solo dopo che quel metodo è terminato, ecco perché non lo fa fermare il contatore. Per fare ciò, 'stop' dovrebbe essere chiamato da un thread diverso (ad esempio il thread principale del gui). Per riavviare il contatore, è necessario reimpostare il flag '_isRunning' se è stato arrestato, ma questo va oltre lo scopo originale della domanda. Tuttavia, ho pubblicato un esempio un po 'più completo [qui] (http://pastebin.com/kmvLb6Y2) (ci sarebbero ancora alcune cose che potrebbero essere migliorate ...) – mata