【编程实践】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 项目
相关推荐
怣501 天前
Windows 11 临时文件清理完全指南:释放宝贵磁盘空间
windows·清理c盘
北极糊的狐1 天前
光标放在引入的xxx组件行(import { xxx } from ‘element-ui‘;)出现标黄,显示报错:无法解析符号 ‘xxx‘ 解决办法
ui
热爱生活的五柒1 天前
WebDAV如何使用?
windows
子春一1 天前
Flutter for OpenHarmony:构建一个 Flutter 习惯打卡应用,深入解析周视图交互、连续打卡逻辑与状态驱动 UI
flutter·ui·交互
面对疾风叭!哈撒给1 天前
Windows 系统使用NSSM创建 Windows服务
windows
我的xiaodoujiao1 天前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 44--将自动化测试结果自动推送至钉钉工作群聊
前端·python·测试工具·ui·pytest
MyBFuture1 天前
C#数组详解:一维二维与交错数组
开发语言·windows·c#·visual studio·vision pro
生活很暖很治愈1 天前
GUI自动化测试[3]——控件&数鼠标操作
windows·python·功能测试·测试工具
HAPPY酷1 天前
构建即自由:一份为创造者设计的 Windows C++ 自动化构建指南
开发语言·c++·ide·windows·python·策略模式·visual studio
忘忧记1 天前
某小说数据分析过程
windows·数据挖掘·数据分析