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())