2015-12-09 14 views
11

Tôi có pyqtmain.py sau:PyQt4: Làm thế nào để tạm dừng một chủ đề cho đến khi một tín hiệu được phát ra?

#!/usr/bin/python3 
import sys 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 
from pyqtMeasThread import * 


class MainWindow(QMainWindow): 
    def __init__(self, parent=None): 
     self.qt_app = QApplication(sys.argv) 
     QMainWindow.__init__(self, parent) 

     buttonWidget = QWidget() 
     rsltLabel = QLabel("Result:") 
     self.rsltFiled = QLineEdit() 
     self.buttonStart = QPushButton("Start") 

     verticalLayout = QVBoxLayout(buttonWidget) 
     verticalLayout.addWidget(rsltLabel) 
     verticalLayout.addWidget(self.rsltFiled) 
     verticalLayout.addWidget(self.buttonStart) 

     butDW = QDockWidget("Control", self) 
     butDW.setWidget(buttonWidget) 
     self.addDockWidget(Qt.LeftDockWidgetArea, butDW) 

     self.mthread = QThread() # New thread to run the Measurement Engine 
     self.worker = MeasurementEngine() # Measurement Engine Object 

     self.worker.moveToThread(self.mthread) 
     self.mthread.finished.connect(self.worker.deleteLater) # Cleanup after thread finished 

     self.worker.measure_msg.connect(self.showRslt) 

     self.buttonStart.clicked.connect(self.worker.run) 

     # Everything configured, start the worker thread. 
     self.mthread.start() 

    def run(self): 
     """ Show the window and start the event loop """ 
     self.show() 
     self.qt_app.exec_() # Start event loop 

    @pyqtSlot(str) 
    def showRslt(self, mystr): 
     self.rsltFiled.setText(mystr) 


def main(): 
    win = MainWindow() 
    win.run() 


if __name__ == '__main__': 
    main() 

Và một kịch bản chủ đề thực hiện đo thực tế:

from PyQt4.QtCore import * 
import time 

class MeasurementEngine(QObject): 
    measure_msg = pyqtSignal(str) 
    def __init__(self): 
     QObject.__init__(self) # Don't forget to call base class constructor 

    @pyqtSlot() 
    def run(self): 
     self.measure_msg.emit('phase1') 
     time.sleep(2) # here I would like to make it as an interrupt 
     self.measure_msg.emit('phase2') 

gì mã này làm bây giờ là sau khi nút Start được nhấn, các chức năng chạy trong chuỗi sẽ được thực thi. Tuy nhiên, thực tế trong hàm chạy, có hai pha của phép đo. Ngay bây giờ tôi đã sử dụng thời gian trễ.

Nhưng những gì tôi muốn thực hiện thực sự là sau khi đo 'phase1' được thực hiện. Một hộp thông báo sẽ xuất hiện và đồng thời, chuỗi sẽ bị tạm dừng/giữ. Cho đến khi người dùng đóng hộp tin nhắn, sau đó chức năng chủ đề sẽ được tiếp tục.

Trả lời

2

Bạn không thể hiển thị số QDialog từ trong một số QThread. Tất cả các công cụ liên quan đến GUI phải được thực hiện trong luồng GUI (cái đã tạo đối tượng QApplication). Những gì bạn có thể làm là sử dụng 2 QThread:

  • 1: thực hiện phase1. Bạn có thể kết nối tín hiệu finished của số này QThread với một vị trí trong số QMainWindow sẽ hiển thị cửa sổ bật lên (sử dụng QDialog.exec_() để nó sẽ là phương thức).
  • Thứ hai: thực hiện phase2. Bạn tạo QThread sau khi cửa sổ bật lên được hiển thị ở đây ở trên đã bị đóng.
1

Chuỗi của bạn có thể phát tín hiệu đến cửa sổ chính để hiển thị hộp thoại. Nếu bạn không muốn đóng chuỗi trong khi hộp thoại đang mở, chuỗi có thể nhập một vòng lặp while để chờ. Trong vòng lặp while nó có thể liên tục kiểm tra một biến mà thread chính có thể thiết lập là true sau khi hộp thoại kết thúc. Đây có thể không phải là giải pháp sạch nhất, nhưng nó sẽ hoạt động.

Để làm rõ câu trả lời của tôi một chút, tôi đã thêm một số mã giả. Những gì bạn phải quan tâm là cách bạn chia sẻ biến số dialog_closed. Bạn có thể ví dụ: sử dụng biến thành viên của lớp chuỗi.

Thread: 
emit_signal 
dialog_closed = False 
while not dialog_closed: 
    pass 
go_on_with_processing 

MainThread: 
def SignalRecieved(): 
    open_dialog 
    dialog_closed = True 
5

Sử dụng QWaitCondition từ mô-đun QtCore. Sử dụng khóa mutex, bạn đặt chuỗi nền để chờ/ngủ cho đến khi chuỗi nền trước đánh thức nó trở lại. Sau đó, nó sẽ tiếp tục thực hiện công việc của nó từ đó.

#!/usr/bin/python3 
import sys 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 
from pyqtMeasThread import * 


class MainWindow(QMainWindow): 
    def __init__(self, parent=None): 
     self.qt_app = QApplication(sys.argv) 
     QMainWindow.__init__(self, parent) 

     buttonWidget = QWidget() 
     rsltLabel = QLabel("Result:") 
     self.rsltFiled = QLineEdit() 
     self.buttonStart = QPushButton("Start") 

     verticalLayout = QVBoxLayout(buttonWidget) 
     verticalLayout.addWidget(rsltLabel) 
     verticalLayout.addWidget(self.rsltFiled) 
     verticalLayout.addWidget(self.buttonStart) 

     butDW = QDockWidget("Control", self) 
     butDW.setWidget(buttonWidget) 
     self.addDockWidget(Qt.LeftDockWidgetArea, butDW) 

     self.mutex = QMutex() 
     self.cond = QWaitCondition() 
     self.mthread = QThread() # New thread to run the Measurement Engine 
     self.worker = MeasurementEngine(self.mutex, self.cond) # Measurement Engine Object 

     self.worker.moveToThread(self.mthread) 
     self.mthread.finished.connect(self.worker.deleteLater) # Cleanup after thread finished 

     self.worker.measure_msg.connect(self.showRslt) 

     self.buttonStart.clicked.connect(self.worker.run) 

     # Everything configured, start the worker thread. 
     self.mthread.start() 

    def run(self): 
     """ Show the window and start the event loop """ 
     self.show() 
     self.qt_app.exec_() # Start event loop 

    # since this is a slot, it will always get run in the event loop in the main thread 
    @pyqtSlot(str) 
    def showRslt(self, mystr): 
     self.rsltFiled.setText(mystr) 
     msgBox = QMessageBox(parent=self) 
     msgBox.setText("Close this dialog to continue to Phase 2.") 
     msgBox.exec_() 
     self.cond.wakeAll() 


def main(): 
    win = MainWindow() 
    win.run() 


if __name__ == '__main__': 
    main() 

Và:

from PyQt4.QtCore import * 
import time 

class MeasurementEngine(QObject): 
    measure_msg = pyqtSignal(str) 
    def __init__(self, mutex, cond): 
     QObject.__init__(self) # Don't forget to call base class constructor 
     self.mtx = mutex 
     self.cond = cond 

    @pyqtSlot() 
    def run(self): 
     # NOTE: do work for phase 1 here 
     self.measure_msg.emit('phase1') 
     self.mtx.lock() 
     try: 
      self.cond.wait(self.mtx) 
      # NOTE: do work for phase 2 here 
      self.measure_msg.emit('phase2') 
     finally: 
      self.mtx.unlock() 

thời gian của bạn là một chút tắt trong tất cả mặc dù điều này. Bạn tạo ứng dụng và bắt đầu chuỗi trước khi bạn hiển thị cửa sổ của mình. Do đó, hộp thông báo sẽ bật lên trước cửa sổ chính thậm chí bật lên. Để nhận chuỗi sự kiện đúng, bạn nên bắt đầu chuỗi của mình như một phần của phương pháp run của MainWindow, sau bạn đã làm cửa sổ chính hiển thị. Nếu bạn muốn điều kiện chờ tách biệt với cài đặt của tin nhắn, bạn có thể cần một tín hiệu và khe riêng để xử lý.

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