我有一个数据采集线程,它对数据进行采样和处理,然后将其作为信号发送到接收器。
现在,当该线程停止时,如何确保它已完成当前循环并在继续之前发出信号(例如发出摘要信号)?
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())
在我当前的示例中,来自线程的最后一个信号始终会覆盖该摘要信号。 预先感谢!
与此同时,我发现了一个使用已完成信号的潜在解决方案。如果有什么不对的地方请评论!
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())