线程中记录PyQt5 PlotWidget触发警告,求可行解决方案
解决跨线程更新PyQt5 UI组件的问题
你遇到的警告是因为Qt的UI组件只能在主线程操作,子线程里直接调用PlotWidget.plot()触发了跨线程操作UI的违规问题。下面是具体的修复方案,核心是用Qt的信号与槽机制实现线程间安全的数据传递:
核心修改思路
- 让日志处理器
PlotLogger继承QObject,这样可以定义Qt信号 - 把原来在
emit里直接操作UI的逻辑,改成发射信号传递数据 - 在主线程的窗口类里,绑定信号到槽函数,由槽函数在主线程中更新UI
修改后的完整代码
import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import QObject, pyqtSignal import pyqtgraph as pg import logging import threading from tqdm import tqdm import time class MyWindow(QMainWindow): def __init__(self): super().__init__() self.plot_widget = pg.PlotWidget() self.setCentralWidget(self.plot_widget) self.plot_data = [] # 初始化空列表,避免None判断 self.setupPlotLogger() threading.Thread(target=self.foo, daemon=True).start() # 设为守护线程,关闭窗口时自动退出 def foo(self): for i in tqdm(range(100)): time.sleep(0.1) logging.getLogger('test').debug(i) def setupPlotLogger(self): pl = PlotLogger() # 连接信号与槽:子线程发的数据,主线程的槽函数处理 pl.new_data_signal.connect(self.update_plot) logging.getLogger('test').setLevel(logging.DEBUG) logging.getLogger('test').addHandler(pl) def update_plot(self, value): # 这个方法在主线程执行,安全操作UI self.plot_data.append(value) self.plot_widget.plot(self.plot_data, clear=True) # clear=True避免重复绘制 class PlotLogger(logging.Handler, QObject): # 定义信号,传递浮点型数据 new_data_signal = pyqtSignal(float) def __init__(self): logging.Handler.__init__(self) QObject.__init__(self) def emit(self, record): # 子线程中只处理数据,发射信号,不碰UI try: record_value = float(self.format(record)) self.new_data_signal.emit(record_value) except ValueError: # 处理格式转换失败的情况 pass if __name__ == "__main__": app = QApplication(sys.argv) window = MyWindow() window.show() app.exec_()
关键修改点说明
PlotLogger同时继承logging.Handler和QObject,并定义new_data_signal信号emit方法不再直接操作PlotWidget,而是把解析后的数据通过信号发送MyWindow中新增update_plot槽函数,专门在主线程更新UI和绘图- 把原来的
plot_data初始化为空列表,简化逻辑 - 子线程设为守护线程,避免关闭窗口后线程还在运行
其他可选方案
如果你的任务逻辑更复杂,也可以用Qt自带的QThread来管理子线程,核心还是通过信号槽传递数据,原理和上面一致。
内容的提问来源于stack exchange,提问作者Changwoo Song
相关产品推荐
相关产品推荐

