0

I have developed a widget that draws a circle using QPainter. The test program creates the widget and then deletes it after 5 seconds. But the circle it drew remains. Shouldn't it disappear, or if not, how do I remove it (calling update() on the parent window has no effect)?

I expected the circle to disappear, but it doesn't. Here is the widget and test-code:

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
        self.update()

    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.begin(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)
        painter.end()
        painter = None

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):
            self.playerToken = None
            del self.playerToken
            self.update()
            print('Remove exiting')
            pass

    app = QApplication([])
    mainWindow = MainWindow()
    mainWindow.show()
    retCode = app.exec()

AndyW
  • 1
  • 1
  • Setting the reference to `None` and using `del` is completely useless when a widget is *parented*: it will always exist as long as the parent is. And relying on `del` to destroy the widget is wrong because `del` does ***NOT*** destroy the object, but its given reference: if you do `a = [0, 1]`, `b = a` and then `del b`, the list will still exist. If you want to delete a QObject, use [`deleteLater()`](https://doc.qt.io/qt-6/qobject.html#deleteLater). – musicamante May 17 '23 at 17:34
  • Also: https://stackoverflow.com/q/7988578 https://stackoverflow.com/q/14848660 https://stackoverflow.com/q/30241684 https://stackoverflow.com/q/57281848 – musicamante May 17 '23 at 17:37
  • Also: 1. calling `painter.begin(self)` is useless, since it's automatically done when doing `QPainter(self); 2. setting a minimum size doesn't ensure that the widget will respect that size, especially if it's not added to a layout manager: if you want to explicitly set a fixed size, use `setFixedSize()`; 3. if QPainter has not a persistent reference (and it shouldn't be), and if called within a `paintEvent()` `painter.end()` is unnecessary; 4. since `painter` is a local variable, doing `painter = None` at the end of a function is also pointless; 5. your imports are inconsistent/redundant; – musicamante May 17 '23 at 17:48
  • 6. accepting a paint event is useless within `paintEvent()`; 7. `QPointF(0, 0)` is exactly the same as `QPointF()`; 8. only constants and classes should have capitalized names, not variables or functions/methods (use `remove`, not `Remove`); 9. calling `self.show()` within the `__init__` is discouraged, as it should always be done externally ([here is why](https://stackoverflow.com/a/75431775); 10. ensure that your imports are consistent and not redundant. – musicamante May 17 '23 at 17:57
  • Thanks for your help, @musicamante. It's clear now that that the fact the object has a parent is what stopped it being deleted. And thanks for your other comments from which I learned a lot. – AndyW May 18 '23 at 16:18
  • You're very welcome (but please accept the duplicate proposal). Also read more about [Qt object trees & ownership](//doc.qt.io/qt-6/objecttrees.html) and remember that PyQt (as PySide) are just *bindings* around a C++ library (Qt). The lifespan of objects and their references might not be consistent: deleting a Python reference does not automatically destroy the C++ counterpart, and vice versa; just like trying to remove a Python reference of a QObject may not be sufficient to delete it, deleting a QObject will not automatically destroy the Python reference that "wraps" it. – musicamante May 19 '23 at 02:54

0 Answers0