diff --git a/magicgui/backends/_qtpy/widgets.py b/magicgui/backends/_qtpy/widgets.py index 4dc552bf2..3921d69a9 100644 --- a/magicgui/backends/_qtpy/widgets.py +++ b/magicgui/backends/_qtpy/widgets.py @@ -84,6 +84,9 @@ def _mgui_set_parent(self, widget: Widget): def _mgui_get_native_widget(self) -> QtW.QWidget: return self._qwidget + def _mgui_get_root_native_widget(self) -> QtW.QWidget: + return self._qwidget + def _mgui_get_width(self) -> int: """Return the current width of the widget.""" return self._qwidget.width() @@ -428,7 +431,11 @@ def __init__(self, layout="vertical", scrollable: bool = False): def _is_scrollable(self) -> bool: return isinstance(self._qwidget, QtW.QScrollArea) + def _mgui_get_root_native_widget(self): + return self._qwidget + def _mgui_get_native_widget(self): + # Return widget with the layout set return self._qwidget.widget() if self._is_scrollable else self._qwidget def _mgui_get_visible(self): diff --git a/magicgui/widgets/_bases/widget.py b/magicgui/widgets/_bases/widget.py index eefb6ccf2..b59b923ef 100644 --- a/magicgui/widgets/_bases/widget.py +++ b/magicgui/widgets/_bases/widget.py @@ -149,9 +149,26 @@ def options(self) -> dict: @property def native(self): - """Return native backend widget.""" + """ + Return native backend widget. + + Note this is the widget that contains the layout, and not any + parent widgets of this (e.g. a parent widget that is used to + enable scroll bars) + """ return self._widget._mgui_get_native_widget() + @property + def root_native_widget(self): + """ + Return the root native backend widget. + + This can be different from the ``.native`` widget if the layout + is a child of some other widget, e.g. a widget used to enable + scroll bars. + """ + return self._widget._mgui_get_root_native_widget() + @property def enabled(self) -> bool: """Whether widget is enabled (editable).""" diff --git a/magicgui/widgets/_protocols.py b/magicgui/widgets/_protocols.py index b50eb2247..06c4ebb1b 100644 --- a/magicgui/widgets/_protocols.py +++ b/magicgui/widgets/_protocols.py @@ -81,6 +81,10 @@ def _mgui_set_parent(self, widget: Widget) -> None: def _mgui_get_native_widget(self) -> Any: raise NotImplementedError() + @abstractmethod + def _mgui_get_root_native_widget(self) -> Any: + raise NotImplementedError() + @abstractmethod def _mgui_bind_parent_change_callback( self, callback: Callable[[Any], None] diff --git a/tests/test_magicgui.py b/tests/test_magicgui.py index 1f9a689e9..0d1f4949f 100644 --- a/tests/test_magicgui.py +++ b/tests/test_magicgui.py @@ -812,9 +812,13 @@ def test_scrollable(): def test_scrollable(a: int = 1, y: str = "a"): ... + assert test_scrollable.native is not test_scrollable.root_native_widget + assert not isinstance(test_scrollable.native, QScrollArea) + assert isinstance(test_scrollable.root_native_widget, QScrollArea) + @magicgui(scrollable=False) def test_nonscrollable(a: int = 1, y: str = "a"): ... - assert isinstance(test_scrollable.native.parent().parent(), QScrollArea) - assert not test_nonscrollable.native.parent() + assert test_nonscrollable.native is test_nonscrollable.root_native_widget + assert not isinstance(test_nonscrollable.native, QScrollArea) diff --git a/tests/test_widgets.py b/tests/test_widgets.py index 4249f20a2..5a50d21e3 100644 --- a/tests/test_widgets.py +++ b/tests/test_widgets.py @@ -82,6 +82,7 @@ def _mgui_set_enabled(self, enabled): ... # noqa def _mgui_get_parent(self): ... # noqa def _mgui_set_parent(self, widget): ... # noqa def _mgui_get_native_widget(self): return MagicMock() # noqa + def _mgui_get_root_native_widget(self): ... # noqa def _mgui_bind_parent_change_callback(self, callback): ... # noqa def _mgui_render(self): ... # noqa def _mgui_get_width(self): ... # noqa