You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 04:24:02