I am unable to remove PySide6 widgets in Unreal 5 python. Will describe the code first:
I have my ArtToolsUI class inheriting from QMainWindow. In this class I set some basic stuff like groupboxes, layouts etc.:
class ArtToolsUI(QMainWindow):
def __init__(self):
super().__init__()
self.setAttribute(Qt.WA_DeleteOnClose, True)
self._app = self._get_qt_app()
self.resize(600,400)
self.editor_tools_buttons = [] #for showcase this has no widgets in it
self._main_widget = self._set_layouts()
def _get_qt_app(self):
qt_app = QApplication.instance()
qt_app.setQuitOnLastWindowClosed(True)
return qt_app
def get_v_layout(widgets):
widgets = make_list(widgets)
layout = QVBoxLayout()
layout.setObjectName("vert_layout")
for widget in widgets:
layout.addWidget(widget)
return layout
def _set_layouts(self):
default_grpbox_names = {"tools":self.editor_tools_buttons}
all_grp_boxes = []
for key in default_grpbox_names:
layout = get_v_layout(default_grpbox_names[key]) # right now this just returns empty QVBoxLayout
new_grp_box = QGroupBox(title=key)
new_grp_box.setAttribute(Qt.WA_DeleteOnClose, True)
new_grp_box.setLayout(layout)
all_grp_boxes.append(new_grp_box)
main_layout = get_v_layout(all_grp_boxes)
main_widget = QWidget()
main_widget.setObjectName("tat_main_widget")
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
return main_widget
I also implemented function for removing all widgets in this unreal python session. This method is called from different module.
def _remove_widgets():
qt_app = QApplication.instance()
if qt_app != None:
all_qt_widgets = qt_app.allWidgets()
for widget in all_qt_widgets:
widget.setParent(None)
widget.close()
widget.deleteLater()
This _remove_widgets() method goes through all existing widgets, which should be destroyed, but for some reason only my ArtToolsUI main window is getting destroyed and all other widgets are still hanging around in the memory. On the other side when I manually click on the X button to close the window it closes everything.
Does anyone know what might be the problem?
Ok I think I figured it out.
When running PySide6 on unreal you actualy cannot start your own QT event loop ( if you do, Unreal Editor will freeze and wait till you end your window). QT somehow finds unreal GUI event loop, which is responsible for everything .. except answering deleteLater().
Only two ways ( I found) for deleting UI are:
QApplication.closeAllWindows()
-> This calls all windows, but definitelly better than if they stay in memory.Both ways seem to bypass deleteLater()
functionality, as documentation for deleteLater()
says:
The object will be deleted when control returns to the event loop.
At the end I ended up with this functionality:
close()
.This will prevent spawning multiple widgets ( 10k widgets is aprox. 1.2GB RAM)
ADD: There is also possibility to use self.setAttribute(Qt.WA_DeleteOnClose, True)
on closing. This will delete dialog from memory as well.