2016-08-07 29 views
1

Ich versuche gerade eine PyQt5-App zu erstellen und sie sollte aus der Haupt-GUI bestehen und im Hintergrund sollte es einen anderen Thread geben, der etwas in einer Endlosschleife messen sollte. Und ich möchte diesen Thread mit einer QAction oder Checkbox starten und stoppen.Thread starten und stoppen mit QAction getoggelt

Also wenn ich die Checkbox drücke und der Status wahr ist, sollte der Thread gestartet werden und wenn ich ihn erneut anklicke, sollte er gestoppt werden.

Nun, was ist der beste Weg, dies zu implementieren?

Zeit einen Worker-Thread wie dies Ich verwende:

class Worker(QtCore.QObject): 
    def __init__(self): 
     super(Worker, self).__init__() 
     self._isRunning = True 

    def task(self): 
     if not self._isRunning: 
      self._isRunning = True 
     while self._isRunning: 
      time.sleep(0.5) 
      ... measure ... 

    def stop(self): 
     self._isRunning = False 

und diese im Hauptthread zu machen laufen:

self.thread = QtCore.QThread() 
self.thread.start() 
self.worker = Worker() 
self.worker.moveToThread(self.thread) 

self.btn_start.clicked.connect(self.worker.task) 
self.btn_stopped.clicked.connect(lambda: self.worker.stop()) 

Bisher dies funktioniert. Aber ich bin nicht wirklich zuversichtlich, dass dies der beste Weg ist, um es zu tun, und es würde mir auch viel besser gefallen, wenn ich dasselbe mit einer Checkbox in der beschriebenen Weise machen könnte.

Antwort

1

So wie es aussieht, ist der von Ihnen gepostete Code nicht multi-threaded. Das liegt daran, dass worker.task() durch den Code im Hauptthread gestartet wird, also auch im Hauptthread. Sie müssen das started-Signal des Arbeitsthreads verwenden, um die Aufgabe zu starten, und ein benutzerdefiniertes Signal für den Worker, um den Thread zu beenden.

Die Demo-Skript unten sollten diese Probleme beheben:

import sys, time 
from PyQt5 import QtCore, QtWidgets 

class Worker(QtCore.QObject): 
    finished = QtCore.pyqtSignal() 
    messageSent = QtCore.pyqtSignal(str) 

    def __init__(self): 
     super(Worker, self).__init__() 
     self._isRunning = False 

    def task(self): 
     print('WKR thread:', QtCore.QThread.currentThread()) 
     self._isRunning = True 
     count = 0 
     while self._isRunning: 
      time.sleep(0.5) 
      count += 1 
      self.messageSent.emit('count: %s' % count) 
     self.finished.emit() 

    def stop(self): 
     self._isRunning = False 

class Window(QtWidgets.QWidget): 
    def __init__(self): 
     super(Window, self).__init__() 
     self.button = QtWidgets.QCheckBox('Test', self) 
     self.button.toggled.connect(self.handleButton) 
     self.label = QtWidgets.QLabel(self) 
     layout = QtWidgets.QVBoxLayout(self) 
     layout.addWidget(self.label) 
     layout.addWidget(self.button) 
     self.thread = QtCore.QThread() 
     self.worker = Worker() 
     self.worker.moveToThread(self.thread) 
     self.thread.started.connect(self.worker.task) 
     self.worker.finished.connect(self.thread.quit) 
     self.worker.messageSent.connect(self.label.setText) 

    def handleButton(self, checked=False): 
     print('GUI thread:', QtCore.QThread.currentThread()) 
     if checked: 
      self.label.clear() 
      self.thread.start() 
     else: 
      self.worker.stop() 

if __name__ == '__main__': 

    app = QtWidgets.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(800, 150, 200, 50) 
    window.show() 
    sys.exit(app.exec_()) 
+0

Vielen Dank! Gibt es einen bestimmten Grund, warum Sie in der Task-Methode anhalten? Sollte nicht aufhören, False zu sein, um an diesen Punkt zu kommen? Was würde ich auch tun müssen, damit der Worker-Thread ein Label im GUI-Thread ändert, ohne ein Chaos zu verursachen? – haxor789

+1

@ haxor789. Sie haben recht mit 'stop()' - es war nur etwas von einer früheren Version übrig. Ich habe die Demo aktualisiert, um ein Etikett zu ändern. – ekhumoro