PyQt5关闭含matplotlib实时绘图的子窗口后计算方法仍运行如何解决
问题根因
你遇到的现象核心有两个原因:
- 你在
Matplotlibwidget.plot_widget中创建的QTimer是方法内的局部变量,没有作为实例属性存储,窗口关闭时你无法主动停止这个定时器 - 定时器未被停止的情况下,每秒都会触发
plotting方法调用func.calculate()执行计算,即使子窗口已经关闭,这个触发逻辑还在PyQt的事件循环中持续运行
修复方案
我们需要将定时器提升为类的可访问属性,在子窗口关闭时停止定时器,重新打开子窗口时重启定时器即可,完整修改后的代码如下:
from PyQt5 import QtCore from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout import sys import random from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure # 主窗口类 class Window(QWidget): def __init__(self): super().__init__() self.setGeometry(200,200, 400,300) self.setWindowTitle('Test') self.demo = None self.create_buttons() def create_buttons(self): btn1 = QPushButton('Open window', self) btn1.setGeometry(100,100, 100,100) btn1.clicked.connect(self.open_w) def open_w(self): if self.demo is None: self.demo = AppDemo() else: # 重新打开窗口时重启定时器 self.demo.chart.timer.start(1000) self.demo.show() # 用于绘图的次级窗口类 class AppDemo(QWidget): def __init__(self): super().__init__() self.resize(650, 500) self.plotwidget = QWidget(self) self.chart = Matplotlibwidget() self.chart.plot_widget(self.plotwidget, self.chart) def closeEvent(self, event): event.accept() # 关闭窗口时停止定时器 self.chart.timer.stop() func.start_lists() print('Window closed') # 自定义绘图组件类 class Matplotlibwidget(FigureCanvas): def __init__(self, parent=None): fig = Figure() self.axes = fig.add_subplot(111) # 提前声明定时器属性 self.timer = None FigureCanvas.__init__(self, fig) self.setParent(parent) FigureCanvas.updateGeometry(self) def plot_widget(self, canvasWidget, graph): self.layoutvertical = QVBoxLayout(canvasWidget) self.layoutvertical.addWidget(graph) # 定时器赋值给实例属性 self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.plotting) self.timer.start(1000) def plotting(self): self.y = func.calculate() func.appends(self.y) self.axes.cla() self.axes.plot(func.x, func.y) self.draw() # 数值计算类,原用于传感器数据处理 class FuncTime (): def __init__(self): self.start_lists() def start_lists(self): self.x, self.y = [0], [1] def calculate(self): return self.y[-1] + self.y[-1] * random.uniform(-0.1, 0.1) def appends(self, y): print(self.x[-1], ', ', self.y[-1]) self.x.append(self.x[-1] + 1) self.y.append(y) app = QApplication(sys.argv) func = FuncTime() window = Window() window.show() sys.exit(app.exec_())
关键修改点说明
- 将
QTimer从plot_widget的局部变量改为Matplotlibwidget的实例属性,方便外部控制启停 - 在子窗口
AppDemo的closeEvent方法中新增停止定时器的逻辑,关闭窗口时直接终止定时触发的计算逻辑 - 在主窗口
open_w方法中新增重启定时器的逻辑,每次重新打开子窗口时恢复定时计算和绘图
内容的提问来源于stack exchange,提问作者Jorge Lozano
相关产品推荐
相关产品推荐

