|
8 | 8 | from typing import TYPE_CHECKING, Any |
9 | 9 |
|
10 | 10 | from guidata.configtools import get_icon |
11 | | -from guidata.qthelpers import win32_fix_title_bar_background |
| 11 | +from guidata.qthelpers import is_qobject_valid, win32_fix_title_bar_background |
12 | 12 | from qtpy import QtCore as QC |
13 | 13 | from qtpy import QtGui as QG |
14 | 14 | from qtpy import QtWidgets as QW |
@@ -827,7 +827,9 @@ def closeEvent(self, event) -> None: |
827 | 827 | # parent widget: otherwise, this panel will stay open after the main |
828 | 828 | # window has been closed which is not the expected behavior) |
829 | 829 | for panel in self.manager.panels: |
830 | | - self.manager.get_panel(panel).close() |
| 830 | + panel_widget = self.manager.get_panel(panel) |
| 831 | + if is_qobject_valid(panel_widget): |
| 832 | + panel_widget.close() |
831 | 833 | QW.QMainWindow.closeEvent(self, event) |
832 | 834 |
|
833 | 835 |
|
@@ -903,16 +905,30 @@ def __init__( |
903 | 905 | ) -> None: |
904 | 906 | self.manager = PlotManager(None) |
905 | 907 | self.manager.set_main(self) |
906 | | - self.subplotwidget = SubplotWidget(self.manager, parent=self, options=options) |
| 908 | + # Note: parent is not set here and widget operations on `self` are |
| 909 | + # deferred to _finalize_init() because PySide6 requires the subclass's |
| 910 | + # __init__ to have fully completed before widget methods can be called. |
| 911 | + self.subplotwidget = SubplotWidget(self.manager, parent=None, options=options) |
| 912 | + self._toolbar_visible = toolbar |
| 913 | + self.auto_tools = auto_tools |
| 914 | + self._rescale_timer: QC.QTimer | None = None |
| 915 | + self._init_title = title |
| 916 | + self._init_icon = icon |
| 917 | + self._init_size = size |
| 918 | + |
| 919 | + def _finalize_init(self) -> None: |
| 920 | + """Finalize initialization after Qt widget __init__ has completed. |
| 921 | +
|
| 922 | + This is called by subclasses in their __init__ after calling both |
| 923 | + QMainWindow/QDialog.__init__ and BaseSyncPlot.__init__. |
| 924 | + """ |
907 | 925 | self.toolbar = QW.QToolBar(_("Tools"), self) |
908 | | - self.toolbar.setVisible(toolbar) |
| 926 | + self.toolbar.setVisible(self._toolbar_visible) |
909 | 927 | self.manager.add_toolbar(self.toolbar, "default") |
910 | 928 | self.toolbar.setMovable(True) |
911 | 929 | self.toolbar.setFloatable(True) |
912 | | - self.auto_tools = auto_tools |
913 | | - self._rescale_timer: QC.QTimer | None = None |
914 | | - set_widget_title_icon(self, title, icon, size) |
915 | | - # Note: setup_layout() is called by subclasses after Qt widget initialization |
| 930 | + set_widget_title_icon(self, self._init_title, self._init_icon, self._init_size) |
| 931 | + # Note: setup_layout() is called by subclasses after _finalize_init() |
916 | 932 |
|
917 | 933 | def setup_layout(self) -> None: |
918 | 934 | """Setup the layout - to be implemented by subclasses""" |
@@ -1048,8 +1064,9 @@ def __init__( |
1048 | 1064 | ) -> None: |
1049 | 1065 | self.subplotwidget: SubplotWidget |
1050 | 1066 | self.toolbar: QW.QToolBar |
1051 | | - QW.QMainWindow.__init__(self, parent) |
1052 | 1067 | BaseSyncPlot.__init__(self, toolbar, options, auto_tools, title, icon, size) |
| 1068 | + QW.QMainWindow.__init__(self, parent) |
| 1069 | + self._finalize_init() |
1053 | 1070 | self.setup_layout() |
1054 | 1071 |
|
1055 | 1072 | def showEvent(self, event): # pylint: disable=C0103 |
@@ -1107,8 +1124,9 @@ def __init__( |
1107 | 1124 | ) -> None: |
1108 | 1125 | self.subplotwidget: SubplotWidget |
1109 | 1126 | self.toolbar: QW.QToolBar |
1110 | | - QW.QDialog.__init__(self, parent) |
1111 | 1127 | BaseSyncPlot.__init__(self, toolbar, options, auto_tools, title, icon, size) |
| 1128 | + QW.QDialog.__init__(self, parent) |
| 1129 | + self._finalize_init() |
1112 | 1130 | self.setup_layout() |
1113 | 1131 | self.setWindowFlags(QC.Qt.Window) |
1114 | 1132 |
|
|
0 commit comments