Home > Net >  Unable to completely remove QWidget
Unable to completely remove QWidget

Time:01-16

I am using PyQt6. My QMainWindow class uses to middle click of the mouse to perform an action. The app can launch a little QWidget that also uses the middle click to perform an action. When this widget is open it disables the middle click from the main window. When closing the widget, the main window enables its ability to use the middle click again but I noticed that it raises errors as it is still trying to call the function connected to middle click inside the widget.

I am trying to completely delete the QWidget so that this doesn't happen anymore.

I have tried: del(widget) widget.destroy() widget.deleteLater() widget.close() widget = None

None of these work as it still raises RuntimeError: wrapped C/C object of type <widget> has been deleted

If it doesn't delete it properly, it simply calls both middle click connections.

How do I completely remove the widget so that nothing can refer to the widget anymore?

Example:

# app.py

import sys

from PyQt6.QtWidgets import QApplication

from main_window import MainWindow


class App(QApplication):
    def __init__(self, argv: list) -> None:
        super().__init__(argv)

        self.main_window = MainWindow()

        self.main_window.show()


app = App(sys.argv)

sys.exit(app.exec())
# main_window.py

import mouse
from PyQt6.QtWidgets import (
    QMainWindow,
    QPushButton,
    QWidget,
)

from test_widget import TestWidget

class MainWindow(QMainWindow):
    def __init__(self) -> None:
        super().__init__()

        self.button = QPushButton("Open Widget", self)

        self.test_widget = None

        self.button.clicked.connect(self.open_widget)

        mouse.on_middle_click(self.test_function)

    def open_widget(self) -> None:
        self.test_widget = TestWidget(self)

        self.test_widget.show()

    def close_widget(self, widget: QWidget) -> None:
        widget.deleteLater()

        self.test_widget = None

    def test_function(self) -> None:
        if self.test_widget is not None:
            return

        print("Main Window")
# test_widget

import mouse
from PyQt6.QtWidgets import (
    QLineEdit,
    QWidget,
)

class TestWidget(QWidget):
    def __init__(self, main_window) -> None:
        super().__init__()

        self.main_window = main_window

        self.line_edit = QLineEdit(self)

        mouse.on_middle_click(self.test_function)

    def closeEvent(self, _) -> None:
        self.main_window.close_widget(self)

    def test_function(self) -> None:
        print(self.line_edit.text())

I cannot share the original code as it is sensitive, but in the example it follows the same process

CodePudding user response:

I've been most successful in deleting PyQT objects by just setting their parent to None. Try

def close_widget(self, widget: QWidget) -> None:
        widget.deleteLater()
        self.test_widget.parent = None
        self.test_widget = None

CodePudding user response:

Thanks to @musicamante for the tip in the right direction.

I solved the issue by unbinding the mouse module from all hooks, deleting the window, and then re-assigning the desired hooks. The reason I unbind all of them is because mouse raises an error if I just unbind the one so I just made a simple workaround.

Code:

# app.py

import sys

from PyQt6.QtWidgets import QApplication

from main_window import MainWindow


class App(QApplication):
    def __init__(self, argv: list) -> None:
        super().__init__(argv)

        self.main_window = MainWindow()

        self.main_window.show()


app = App(sys.argv)

sys.exit(app.exec())
# main_window.py

import mouse
from PyQt6.QtWidgets import (
    QMainWindow,
    QPushButton,
    QWidget,
)

from test_widget import TestWidget

class MainWindow(QMainWindow):
    def __init__(self) -> None:
        super().__init__()

        self.button = QPushButton("Open Widget", self)

        self.test_widget = None

        self.button.clicked.connect(self.open_widget)

        mouse.on_middle_click(self.test_function)

    def open_widget(self) -> None:
        self.test_widget = TestWidget(self)

        self.test_widget.show()

    def close_widget(self, widget: QWidget) -> None:
        widget.deleteLater()

        mouse.unhook_all()
        mouse.on_middle_click(self.test_function)

        self.test_widget = None

    def test_function(self) -> None:
        if self.test_widget is not None:
            return

        print("Main Window")
# test_widget.py

import mouse
from PyQt6.QtWidgets import (
    QLineEdit,
    QWidget,
)

class TestWidget(QWidget):
    def __init__(self, main_window) -> None:
        super().__init__()

        self.main_window = main_window

        self.line_edit = QLineEdit(self)

        mouse.on_middle_click(self.test_function)

    def closeEvent(self, _) -> None:
        # mouse.unhook(self.test_function) - this doesn't work

        self.main_window.close_widget(self)

    def test_function(self) -> None:
        print(self.line_edit.text())
  • Related