2016-08-07 85 views
1

我目前正在嘗試構建一個PyQt5應用程序,它應該由主GUI和背景中應該有一個不同的線程,應該測量無限循環中的某些東西。我想用QAction或複選框來啓動和停止這個線程。啓動和停止線程使用QAction切換

所以說,當我按下複選框,狀態爲真時,線程應該啓動,如果再次單擊它應該停止。

現在最好的實現方式是什麼?

目前我使用一個工作線程是這樣的:

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 

,這在主線程,使其運行:

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

到目前爲止,這個工程。但我並不確定這是做這件事的最好方式,如果我能按照上述方式使用複選框做同樣的事情,我也會更加喜歡它。

回答

1

就目前而言,您發佈的代碼不是多線程的。這是因爲worker.task()由主線程中的代碼啓動,所以它也會在主線程中運行。您需要使用工作線程的started信號來啓動任務,並在工作人員上使用自定義信號來退出線程。

下面的演示腳本應該解決這些問題:

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

非常感謝您!你有什麼特別的原因叫你在任務方法中停止?不管怎麼樣,爲了達到這一點,不應該停止假?另外我還需要做些什麼來使工作線程在GUI線程中更改標籤而不會造成混亂? – haxor789

+1

@ haxor789。你說'stop()'是正確的 - 它只是早期版本遺留下來的東西。我已經更新了演示,包括更改標籤。 – ekhumoro