PyQt6中删除QPainter绘制图形的Widget后图形未消失的问题
问题解决:删除QWidget后绘制内容未消失
问题根源
你当前删除PlayerToken的方式有误:
- Qt的父子对象机制中,当QWidget有父对象时,父窗口会维护子对象的引用,仅通过
self.playerToken = None和del self.playerToken无法真正销毁该Widget,它仍然存在于父窗口的子对象列表中,所以绘制的圆形不会消失。 - 调用父窗口的
update()无效,因为Widget本身还没被销毁,父窗口重绘时依然会绘制这个未被移除的子Widget。
正确解决方案
要彻底销毁Qt Widget,需调用Widget的deleteLater()方法,该方法会告知Qt事件循环在合适的时机销毁Widget,同时将其从父窗口的子对象列表中移除,自动触发界面重绘。
修改MainWindow的Remove方法如下:
def Remove(self): if self.playerToken: self.playerToken.deleteLater() self.playerToken = None # 清空本地引用 print('Remove exiting')
额外优化点
- 你的
PlayerToken的paintEvent存在冗余代码:painter = QPainter(self)已经完成了painter的初始化,不需要再调用painter.begin(self),而且painter = None是多余的(Python会自动管理内存)。修改后的paintEvent更简洁:
def paintEvent(self, event : QPaintEvent) -> None: event.accept() painter = QPainter(self) painter.translate(self.SIZE, self.SIZE) painter.setBrush(QBrush(QColor(self.colour), Qt.BrushStyle.SolidPattern)) painter.drawEllipse(QPointF(0, 0), self.SIZE, self.SIZE)
- 初始化时的
self.update()可以去掉,Widget显示时会自动触发paintEvent。
修改后的完整代码
from __future__ import annotations import typing from PyQt6.QtGui import QPaintEvent, QPainter, QColor, QBrush from PyQt6.QtWidgets import QWidget from PyQt6.QtCore import Qt, QPoint, QPointF, QSize class PlayerToken(QWidget): SIZE = 12 def __init__(self, parent, colour): super(PlayerToken, self).__init__(parent) self.setMinimumSize(QSize(self.SIZE*2, self.SIZE*2)) self.colour = colour def move(self, where : QPoint): centrePos = QPoint(where.x() - self.SIZE, where.y() - self.SIZE) super().move(centrePos) def paintEvent(self, event : QPaintEvent) -> None: event.accept() painter = QPainter(self) painter.translate(self.SIZE, self.SIZE) painter.setBrush(QBrush(QColor(self.colour), Qt.BrushStyle.SolidPattern)) painter.drawEllipse(QPointF(0, 0), self.SIZE, self.SIZE) if __name__ == "__main__": from PyQt6.QtWidgets import QApplication, QMainWindow from PyQt6.QtCore import QSize, QTimer class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__( *args, **kwargs) self.setMinimumSize(QSize(400, 500)) self.playerToken = PlayerToken(self, 'red') self.playerToken.move(QPoint(100, 300)) self.playerToken.show() QTimer.singleShot(5*1000, self.Remove) def Remove(self): if self.playerToken: self.playerToken.deleteLater() self.playerToken = None print('Remove exiting') app = QApplication([]) mainWindow = MainWindow() mainWindow.show() retCode = app.exec()
内容的提问来源于stack exchange,提问作者AndyW
相关产品推荐
相关产品推荐

