2013-04-26 7 views
7

Próbuję zrozumieć, jak używać sygnalizacji z Qthread z powrotem do interfejsu Gui, który się rozpoczął.Jak zasygnalizować z uruchomionego QThreada do PyQt Gui, które go uruchomiło?

Ustawienia: Mam proces (symulacja), który musi działać prawie w nieskończoność (lub przynajmniej przez bardzo długi czas)., Podczas działania, wykonuje różne obliczenia, a niektóre wyniki muszą być odesłane do GUI, który wyświetli je odpowiednio w czasie rzeczywistym. Używam PyQt dla GUI. Oryginalnie próbowałem używać modułu wątków Pythona, a następnie przełączałem się na QThreads po przeczytaniu kilku postów, zarówno tutaj, na SO i gdzie indziej.

Zgodnie z tym wpisem na Qt Blog You're doing it wrong, preferowanym sposobem użycia QThread jest utworzenie QObject, a następnie przeniesienie go do Qthread. Więc poszedłem za poradą w wątku Backspace z QThread w PyQt "> to pytanie SO i wypróbowałem prostą aplikację testową (kod poniżej): otwiera prosty GUI, pozwala rozpocząć proces w tle, i ma aktualizować wartość kroku w .. a. Okno wyboru

Ale to nie działa GUI nie jest aktualizowana co robię źle

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

Odpowiedz

7

problemem tutaj jest prosta: Twój SimulRunner nigdy nie zostanie wysłany sygnał, który powoduje to, aby rozpocząć Jednym ze sposobów, aby to zrobić, jest połączenie go z sygnałem z Gwizdki

A lso, w pytonie powinieneś użyć nowego stylu łączenia sygnałów:

... 
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

Masz absolutną rację, właśnie zdałem sobie sprawę z błędu. Przecinałem i wklejałem kod z poprzedniej wersji, w której podklasowałem Qthread zamiast używać moveToThread i zupełnie zapomniałem o metodzie begin(). Dziękuję za wskazanie. – stefano

+0

jest to bardzo interesujący przykład. Jednak postępuj zgodnie z tą sugestią, ale wątek zaczyna się, ale przycisk zatrzymania go nie zatrzymuje. Byłoby wspaniale mieć działający przykład. A może przycisk "Go", który może ponownie uruchomić cały obiekt. – Fabrizio

+0

Stop tylko wysyła sygnał, ale ponieważ 'simulThread' jest zajęty przez' longRunning', ten sygnał może być przetworzony dopiero po wyjściu z tej metody, dlatego tak naprawdę nie działa zatrzymaj licznik. Aby to zrobić, 'stop' musiałby zostać wywołany z innego wątku (np. Główny wątek GUI). Aby zrestartować licznik, konieczne jest zresetowanie flagi '_isRunning', jeśli zostało zatrzymane, ale wykracza to poza pierwotny zakres pytania. Niemniej jednak zamieściłem trochę bardziej kompletny przykład [tutaj] (http://pastebin.com/kmvLb6Y2) (nadal będą pewne rzeczy, które mogą być ulepszone ...) – mata

Powiązane problemy