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