在做某事之前等待 PyQt/PySide.QtCore.QThread 完成

问题描述 投票:0回答:1

我有一个数据采集线程,它对数据进行采样和处理,然后将其作为信号发送到接收器。

现在,当该线程停止时,如何确保它已完成当前循环并在继续之前发出信号(例如发出摘要信号)?

import sys
import time

from PySide6.QtCore import Signal, Slot
from PySide6 import QtCore
from PySide6 import QtWidgets


##==============================================================================
class EmitterClassThreaded(QtCore.QThread):
    ## Define a signal that emits a dictionary
    data_signal = Signal(dict)
    
    ##--------------------------------------------------------------------------
    def __init__(self):
        super().__init__()
        self.counter = 0
        self.t_start = time.time()
        self.running = True

        ## Connect the signal to a method within the same class
        self.data_signal.connect(self.handle_data)

    ##--------------------------------------------------------------------------
    def run(self):
        while self.running:
            self.counter += 1
            now = time.time() - self.t_start
            data = {'counter': self.counter, 'timestamp': f"{now:.1f}"}
            time.sleep(1)  # <------ doing something here which takes time
            self.data_signal.emit(data)

    ##--------------------------------------------------------------------------
    def stop(self):
        self.running = False

    ##--------------------------------------------------------------------------
    @Slot(dict)
    def handle_data(self, data):
        print(f"EmitterClassThreaded received data: {data}")


##==============================================================================
class ReceiverClass():
    def __init__(self):
        super().__init__()

    ##--------------------------------------------------------------------------
    @Slot(dict)
    def handle_data(self, data):
        print(f"ReceiverClass received data: {data}")


##==============================================================================
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Example ThreadedEmitter-Receiver")
        self.setGeometry(100, 100, 400, 200)

        self.label = QtWidgets.QLabel("Waiting for signal...", self)
        self.label.move(150, 80)

        self.stop_button = QtWidgets.QPushButton("Stop Emitter", self)
        self.stop_button.move(150, 120)
        self.stop_button.clicked.connect(self.stop_emitter)

        self.emitter = EmitterClassThreaded()
        self.emitter.data_signal.connect(self.handle_data)

        self.receiver = ReceiverClass()

        ## Connect the signal from EmitterClass to the method in ReceiverClass
        self.emitter.data_signal.connect(self.receiver.handle_data)

        ## Start the emitter thread
        self.emitter.start()
        self.emitter.running = True

    ##--------------------------------------------------------------------------
    @Slot(dict)
    def handle_data(self, data):
        self.label.setText(f"Counter: {data['counter']}\nTimestamp: {data['timestamp']}")

    ##--------------------------------------------------------------------------
    def stop_emitter(self):
        print("ReceiverClass: Stopping the emitter thread...")
        self.emitter.stop()
        ## TODO: Wait for the thread to finish (incl. emitting the last signal) before proceeding
        print("Creating own data to emit.")
        self.emitter.data_signal.emit({'counter': -999, 'timestamp': 0})

##******************************************************************************
##******************************************************************************
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

在我当前的示例中,来自线程的最后一个信号始终会覆盖该摘要信号。 预先感谢!

python pyqt pyside qthread
1个回答
0
投票

与此同时,我发现了一个使用已完成信号的潜在解决方案。如果有什么不对的地方请评论!

import sys
import time

from PySide6.QtCore import Signal, Slot, QEventLoop
from PySide6 import QtCore
from PySide6 import QtWidgets


##==============================================================================
class EmitterClassThreaded(QtCore.QThread):
    ## Define a signal that emits a dictionary
    data_signal = Signal(dict)
    ## Define a signal for when the thread has finished
    finished_signal = Signal()

    ##--------------------------------------------------------------------------
    def __init__(self):
        super().__init__()
        self.counter = 0
        self.t_start = time.time()
        self.running = True

        ## Connect the signal to a method within the same class
        self.data_signal.connect(self.handle_data)

    ##--------------------------------------------------------------------------
    def run(self):
        while self.running:
            self.counter += 1
            now = time.time() - self.t_start
            data = {'counter': self.counter, 'timestamp': f"{now:.1f}"}
            time.sleep(1)  # <------ doing something here which takes time
            self.data_signal.emit(data)

        ## Emit finished signal
        self.finished_signal.emit()

    ##--------------------------------------------------------------------------
    def stop(self):
        self.running = False
        self.wait()

    ##--------------------------------------------------------------------------
    @Slot(dict)
    def handle_data(self, data):
        print(f"EmitterClassThreaded received data: {data}")


##==============================================================================
class ReceiverClass():
    def __init__(self):
        super().__init__()

    ##--------------------------------------------------------------------------
    def handle_data(self, data):
        print(f"ReceiverClass received data: {data}")


##==============================================================================
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Example ThreadedEmitter-Receiver")
        self.setGeometry(100, 100, 400, 200)

        self.label = QtWidgets.QLabel("Waiting for signal...", self)
        self.label.move(150, 80)

        self.stop_button = QtWidgets.QPushButton("Stop Emitter", self)
        self.stop_button.move(150, 120)
        self.stop_button.clicked.connect(self.stop_emitter)

        self.emitter = EmitterClassThreaded()
        self.emitter.data_signal.connect(self.handle_data)
        self.emitter.finished_signal.connect(self.handle_finished)

        self.receiver = ReceiverClass()

        ## Connect the signal from EmitterClass to the method in ReceiverClass
        self.emitter.data_signal.connect(self.receiver.handle_data)

        ## Start the emitter thread
        self.emitter.start()
        self.emitter.running = True

    ##--------------------------------------------------------------------------
    @Slot(dict)
    def handle_data(self, data):
        self.label.setText(f"Counter: {data['counter']}\nTimestamp: {data['timestamp']}")

    ##--------------------------------------------------------------------------
    def stop_emitter(self):
        print("ReceiverClass: Stopping the emitter thread...")
        loop = QEventLoop()
        self.emitter.finished_signal.connect(loop.quit)
        self.emitter.stop()
        loop.exec()

    ##--------------------------------------------------------------------------
    @Slot()
    def handle_finished(self):
        ## NOTE: This can put into stop_emitter() method, too, after loop.exec()
        print("Thread finished, creating own data to emit...")
        self.emitter.data_signal.emit({'counter': -999, 'timestamp': 0})


##******************************************************************************
##******************************************************************************
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())
© www.soinside.com 2019 - 2024. All rights reserved.