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"))是必要的补充。
正确处理方式
- 始终持有Pixmap的持久引用(如类成员变量),避免直接使用
QLabel.pixmap()返回的临时对象进行绘图。 - 每次完成绘图后,调用
self.label.setPixmap(self.canvas)更新QLabel显示,确保界面刷新最新的绘图内容。
内容的提问来源于stack exchange,提问作者NoWayOut8344
相关产品推荐
相关产品推荐

