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

PyQt6/Matplotlib:多FigureCanvasQTAgg共享单个Figure时如何冻结画布

问题解决思路与代码修复

代码问题分析

你当前的eventFilter逻辑存在错误:在Qt的事件过滤器中,返回True才会拦截事件,而你返回False相当于允许事件继续传播,所以根本没起到阻止Canvas重绘的作用。

临时修复:拦截Paint事件实现"冻结"

修改你的Canvas类,调整事件过滤器的返回值,同时确保Canvas完成初始绘制后再冻结:

import sys
import random
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt6 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

class Canvas(FigureCanvas):
    def __init__(self, fig):
        self.paint_enabled = True
        super().__init__(fig)
        self.installEventFilter(self)

    def eventFilter(self, obj, event):
        # 返回True拦截Paint事件,阻止Canvas更新
        if obj == self and event.type() == QtCore.QEvent.Type.Paint and not self.paint_enabled:
            return True
        return super().eventFilter(obj, event)

app = QtWidgets.QApplication(sys.argv)

fig = Figure(figsize=(5, 4), dpi=100)
ax = fig.add_subplot(111)

xdata = list(range(50))
ydata = [random.randint(0, 10) for i in range(50)]
ax.plot(xdata, ydata)

c1 = Canvas(fig)
c1.move(100,100)
c1.draw()
c1.show()
# 必须等draw完成后再冻结,确保Canvas缓存了初始图像
c1.paint_enabled = False

def second_plot():
    ydata = [random.randint(0, 10) for i in range(50)]
    ax.clear()
    ax.plot(xdata, ydata)

    c2 = Canvas(fig)
    c2.move(600,600)
    c2.draw()
    c2.show()

timer = QtCore.QTimer()
timer.setSingleShot(True)
timer.timeout.connect(second_plot)
timer.start(1000)

app.exec()

更可靠的解决方案

共享单个Figure的方案本身存在状态耦合风险,更推荐以下两种方式:

方案1:将Canvas转为静态图像显示

直接把Matplotlib绘制的内容转成QPixmap,用QLabel显示,彻底和原Figure解耦:

import sys
import random
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt6 import QtCore, QtWidgets, QtGui
from matplotlib.figure import Figure

def get_plot_pixmap():
    fig = Figure(figsize=(5, 4), dpi=100)
    ax = fig.add_subplot(111)
    xdata = list(range(50))
    ydata = [random.randint(0, 10) for _ in range(50)]
    ax.plot(xdata, ydata)
    # 将Figure转为QPixmap
    fig.canvas.draw()
    buf = fig.canvas.buffer_rgba()
    pixmap = QtGui.QPixmap.fromImage(QtGui.QImage(buf, buf.shape[1], buf.shape[0], QtGui.QImage.Format.Format_RGBA8888))
    return pixmap

app = QtWidgets.QApplication(sys.argv)

# 第一个窗口
label1 = QtWidgets.QLabel()
label1.setPixmap(get_plot_pixmap())
label1.move(100,100)
label1.show()

def show_second_plot():
    # 第二个窗口
    label2 = QtWidgets.QLabel()
    label2.setPixmap(get_plot_pixmap())
    label2.move(600,600)
    label2.show()

timer = QtCore.QTimer()
timer.setSingleShot(True)
timer.timeout.connect(show_second_plot)
timer.start(1000)

app.exec()

方案2:使用独立Figure并修复内存释放问题

你最初的多Figure方案内存释放问题,大概率是因为没有正确销毁对象引用。可以通过以下方式解决:

  • 为每个窗口创建独立的Figure和Canvas
  • 窗口关闭时手动清理引用,触发垃圾回收
  • 避免全局引用持有这些对象

示例代码:

import sys
import random
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt6 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

class PlotWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        # 每个窗口独立创建Figure和Canvas
        self.fig = Figure(figsize=(5, 4), dpi=100)
        self.ax = self.fig.add_subplot(111)
        self.canvas = FigureCanvas(self.fig)
        self.setCentralWidget(self.canvas)
        self.draw_plot()

    def draw_plot(self):
        xdata = list(range(50))
        ydata = [random.randint(0, 10) for _ in range(50)]
        self.ax.plot(xdata, ydata)
        self.canvas.draw()

    def closeEvent(self, event):
        # 窗口关闭时清理引用,帮助内存释放
        self.ax.clear()
        self.canvas.close()
        self.fig.clear()
        del self.ax, self.canvas, self.fig
        super().closeEvent(event)

app = QtWidgets.QApplication(sys.argv)

# 第一个窗口
w1 = PlotWindow()
w1.move(100,100)
w1.show()

def open_second_window():
    # 第二个窗口
    w2 = PlotWindow()
    w2.move(600,600)
    w2.show()

timer = QtCore.QTimer()
timer.setSingleShot(True)
timer.timeout.connect(open_second_window)
timer.start(1000)

app.exec()

内容的提问来源于stack exchange,提问作者Bearify

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 07:35:24