【编程实践】Windows + PySide6 + Matplotlib 绘图时 WinError 32 的完整排查与解决方案

1. 问题背景

在基于 PySide6(Qt)+ Matplotlib 开发桌面 GUI 程序时,需要在界面中动态生成 Matplotlib 图像,并显示在 QLabel 中。

程序功能表现为:

  • Matplotlib 图像可以正常绘制

  • 图像可以正常显示在界面中

  • 但在生成图像后,程序弹出错误提示:

    // 提示信息
    WinError 32: 另一个程序正在使用此文件,进程无法访问
    C:\Users\xxx\AppData\Local\Temp\tmpxxxx.png

该错误并不会影响图像显示结果,但会中断后续逻辑,严重影响程序稳定性。

2. 初步误判与无效尝试

在排查过程中,最先怀疑的方向包括:

  • Matplotlib 后端问题(Qt5Agg / 默认后端)
  • plt.close(fig) 是否调用正确
  • 是否需要切换为 Agg 后端
  • 是否应避免使用系统临时目录

尝试过的方案包括:

  • 显式调用 plt.close(fig)
  • 移除 matplotlib.use('Qt5Agg')
  • 改用 fig.savefig()
  • 改变临时文件保存路径
    这些修改均无法彻底解决问题,说明问题不在 Matplotlib 后端本身。

3. 问题本质定位

最终定位发现,该问题是Windows 文件锁机制 + Qt 文件加载行为共同导致的结果。

3.1 关键代码模式(问题写法)

javascript 复制代码
// python
temp_file = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
plt.savefig(temp_file.name)

pixmap = QPixmap(temp_file.name)
os.unlink(temp_file.name)

(1)NamedTemporaryFile 文件句柄未释放

在 Windows 系统中:

  • NamedTemporaryFile 在未关闭前
  • 文件始终处于 被占用状态
  • 即使 delete=False,依然无法被其他进程安全删除

(2)QPixmap(file_path) 会锁定文件

QPixmap(path) 在 Windows 下会:

  • 直接占用并锁定该文件
  • 且不会在短时间内释放句柄
  • 导致后续 os.unlink() 必然失败

两者叠加后,100% 触发 WinError 32。

4. 正确的解决方案

核心思想

Qt 显示图像应从内存加载,而不是直接从文件路径加载。

即:

  • 文件只作为中转
  • Qt 只接触内存数据
  • 文件可在加载后立即删除

4.1 推荐实现方式(稳定方案)

javascript 复制代码
// python
import tempfile
import os
from PySide6.QtGui import QPixmap

# 1. 生成临时文件路径(不保持打开状态)
fd, tmp_path = tempfile.mkstemp(suffix=".png")
os.close(fd)
# 2. 使用 fig.savefig 写入文件
fig.savefig(tmp_path, dpi=150, bbox_inches="tight")
# 3. 读入内存
with open(tmp_path, "rb") as f:
    img_bytes = f.read()
# 4. 从内存加载到 QPixmap
pixmap = QPixmap()
pixmap.loadFromData(img_bytes)
# 5. 显示
label.setPixmap(pixmap)
# 6. 安全删除文件
os.remove(tmp_path)

5. 为什么这种方式是"稳妥解方案"

项目 结果
Windows 文件锁 完全规避
Qt 文件句柄 不再占用磁盘
多次刷新 稳定
后端依赖
GUI 响应 正常

这是 PySide / PyQt 在 Windows 下加载临时图像的标准工程写法

6. 常见错误总结(避坑清单)

× 不推荐写法

QPixmap("xxx.png")

  • NamedTemporaryFile(delete=False) 不关闭

  • plt.savefig() 混用 pyplot 状态

  • 绘图后立即 os.unlink()

√ 推荐写法

  • fig.savefig()

  • mkstemp + os.close(fd)

  • QPixmap.loadFromData(bytes)

  • 文件仅作为中转

7. 总结

本次问题并非 Matplotlib 绘图错误,而是:

Windows 文件锁机制 + Qt 图像加载方式 + 临时文件管理不当共同导致的典型 GUI 工程级问题。

通过将 Qt 图像加载从"文件路径"切换为"内存数据",问题得以彻底解决。

该经验适用于:

  • PySide6 / PyQt5 / PyQt6
  • Matplotlib / Pillow / OpenCV 生成的临时图像
  • 所有 Windows 桌面 GUI 项目
相关推荐
林瞅瞅6 分钟前
PowerShell 启动卡顿?内存飙升?原来是 800MB 的历史记录在作祟!
windows
Shepherd061937 分钟前
【Windows Server 实战】WAC 反向代理配置
windows
云小逸1 小时前
【windows系统编程】第一章 Windows 系统核心架构与基础概念
windows·架构
怣疯knight2 小时前
Docker Desktop 4.55.0版本安装成功教程
windows·docker
liulilittle4 小时前
VEthernet 框架实现 tun2socks 的技术原理
网络·windows·c#·信息与通信·通信
独钓寒江雨4 小时前
win11在安全模式下删除360tray.exe
windows·电脑
PieroPc5 小时前
Windows 远程到 PVE 9.X Mac os (像window远程桌面)
windows·mac·远程桌面
海雅达手持终端PDA6 小时前
海雅达HDT500手持终端PDA:2026新一代物流仓储、零售电商移动wms管理方案推荐
能源·健康医疗·制造·零售·iot·教育电商·交通物流
吾心不朽6 小时前
PowerPoint无法从所选的文件中插入视频,验证此媒体格式所必需的64位编码解码器是否已安装,然后重试
windows
lowhot6 小时前
C语言UI框架
c语言·开发语言·笔记·ui