2013-04-26 23 views
7

Tôi đang cố gắng hiểu cách sử dụng tín hiệu từ Qthread trở lại giao diện Gui đã bắt đầu.Làm thế nào để tín hiệu từ một QThread chạy trở lại PyQt Gui mà bắt đầu nó?

Thiết lập: Tôi có một quy trình (mô phỏng) cần chạy gần như vô thời hạn (hoặc ít nhất là trong khoảng thời gian rất dài). Trong khi chạy, nó thực hiện các tính toán khác nhau, một số kết quả phải là được gửi trở lại GUI, sẽ hiển thị chúng một cách thích hợp trong thời gian thực. Tôi đang sử dụng PyQt cho GUI. Ban đầu tôi đã thử sử dụng mô-đun luồng của python, sau đó chuyển sang QThreads sau khi đọc một số bài đăng cả ở đây trên SO và ở nơi khác.

Theo bài đăng này trên Blog Qt You're doing it wrong, cách ưa thích để sử dụng QThread là tạo QObject và sau đó chuyển nó sang Qthread. Vì vậy, tôi đã làm theo lời khuyên trong ThreadBackground với QThread trong PyQt "> câu hỏi SO này và thử một ứng dụng thử nghiệm đơn giản (mã bên dưới): nó mở ra một giao diện đơn giản, cho phép bạn bắt đầu quá trình nền và nó được phát hành để cập nhật giá trị bước trong ... một spinbox

Nhưng nó không hoạt động GUI được không bao giờ được cập nhật tôi đang làm gì sai

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

Trả lời

7

vấn đề ở đây rất đơn giản:? SimulRunner của bạn không bao giờ được gửi một tín hiệu gây ra nó để bắt đầu công việc của nó Một cách để làm điều đó là kết nối nó với tín hiệu started của Chủ đề.

A lso, trong python bạn nên sử dụng kiểu kết nối tín hiệu kiểu mới:

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

Bạn hoàn toàn đúng, tôi vừa mới nhận ra sai lầm. Tôi cắt và dán mã từ một phiên bản trước đó, trong đó tôi đã phân lớp Qthread thay vì sử dụng moveToThread, và hoàn toàn quên về phương thức started(). Cảm ơn đã chỉ ra điều đó. – stefano

+0

đây là một ví dụ rất thú vị. Tuy nhiên, hãy làm theo đề xuất này, chuỗi bắt đầu nhưng nút dừng không dừng lại. Nó sẽ là tuyệt vời để có một ví dụ làm việc. Và có thể nút Go có thể khởi động lại toàn bộ điều – Fabrizio

+0

Điểm dừng chỉ gửi tín hiệu, nhưng khi 'simulThread' đang bận chạy' longRunning', tín hiệu đó chỉ có thể được xử lý sau khi phương thức đó đã thoát, đó là lý do tại sao nó không thực sự dừng bộ đếm. Để làm như vậy, 'stop' sẽ havet được gọi từ một luồng khác (ví dụ: chuỗi gui chính). Để khởi động lại bộ đếm, bạn cần đặt lại cờ '_isRunning' nếu nó đã bị dừng, nhưng vượt quá phạm vi ban đầu của câu hỏi. Tuy nhiên, tôi đã đăng một ví dụ hoàn chỉnh hơn [ở đây] (http://pastebin.com/kmvLb6Y2) (vẫn sẽ có một số điều có thể được cải thiện khó khăn ...) – mata

Các vấn đề liên quan