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

PyQt6中通过label.pixmap()创建QPainter引发绘图设备销毁错误

PyQt6中QPainter操作QLabel Pixmap报错的原因分析

问题描述

使用PyQt6开发自定义UI组件时,尝试通过QPainter绘图,运行官方示例代码时抛出错误:QPaintDevice: Cannot destroy paint device that is being painted。排查发现:

  • 只要通过self.label.pixmap()获取pixmap并传入QPainter构造函数,就会触发该错误,即使注释绘图代码和painter.end()也无法解决。
  • 直接将canvas对象传入QPainter构造函数,再将canvas赋值给label则能正常运行,但每次更新绘图都需要重新给label赋值pixmap。

官方示例报错代码

import sys
from PyQt6 import QtCore, QtGui, QtWidgets, uic
from PyQt6.QtCore import Qt


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        # create widget containing the pixmap
        self.label = QtWidgets.QLabel()

        # create the pixmap
        canvas = QtGui.QPixmap(400, 300)

        # set the pixmap to the label
        self.label.setPixmap(canvas)

        # i dont really know what this does but it was in the example code
        self.setCentralWidget(self.label)

        self.draw_something()

    def draw_something(self):
        # create the painter and tell it what pixmap to draw on
        painter = QtGui.QPainter(self.label.pixmap())

        # draw a line
        painter.drawLine(10, 10, 300, 200)

        # end / delete the printer
        painter.end()



app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

可行代码版本

import sys
from PyQt6 import QtCore, QtGui, QtWidgets, uic
from PyQt6.QtCore import Qt


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        # create widget containing the pixmap
        self.label = QtWidgets.QLabel()

        # create the pixmap
        self.canvas = QtGui.QPixmap(400, 300)

        # this was not in the example code but without it the background is just black and the line therefore not visible
        self.canvas.fill(QtGui.QColor("white"))

        # i dont really know what this does but it was in the example code
        self.setCentralWidget(self.label)

        self.draw_something()

        # set the pixmap to the label
        self.label.setPixmap(self.canvas)

    def draw_something(self):
        # create the painter and tell it what pixmap to draw on (in this case directly to canvas obj)
        painter = QtGui.QPainter(self.canvas)

        # draw a line
        painter.drawLine(10, 10, 300, 200)

        # end / delete the printer
        painter.end()

         

app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

原因解析

这不是PyQt6的bug,核心是对QLabel的pixmap()返回值生命周期的理解偏差:

  • 调用self.label.setPixmap(canvas)后,QLabel内部会维护Pixmap的引用,但self.label.pixmap()返回的是一个临时引用对象。在Python中,这个临时对象没有被持久持有,会被垃圾回收机制快速销毁。
  • 当把这个临时对象传入QPainter构造函数时,QPainter会尝试操作该paint device,但此时该Pixmap已经被销毁,从而触发"正在被绘制的paint device无法销毁"的错误——本质是QPainter操作了一个已失效的对象。
  • 而可行代码中,self.canvas作为类成员变量被持久持有,QPainter操作的是生命周期稳定的Pixmap对象,因此不会出现销毁冲突。

另外,官方示例未填充Pixmap背景,导致默认黑色背景下线条不可见,可行代码中添加的self.canvas.fill(QtGui.QColor("white"))是必要的补充。

正确处理方式

  1. 始终持有Pixmap的持久引用(如类成员变量),避免直接使用QLabel.pixmap()返回的临时对象进行绘图。
  2. 每次完成绘图后,调用self.label.setPixmap(self.canvas)更新QLabel显示,确保界面刷新最新的绘图内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 14:20:24