Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access QDockWidget instances from dock widgets #3659

Closed
jwindhager opened this issue Nov 19, 2021 · 5 comments
Closed

Access QDockWidget instances from dock widgets #3659

jwindhager opened this issue Nov 19, 2021 · 5 comments
Labels
feature New feature or request

Comments

@jwindhager
Copy link
Contributor

馃殌 Feature

Expose QDockWidget instances to dock widgets

Motivation

The original motivation for this was to adapt a widget's layout upon changing its dock location (e.g. QVBoxLayout for left/right, QHBoxLayout for top/bottom). This would require listening to QDockWidget.dockLocationChanged. However, currently, dock widgets inherit from QWidget and are "only" children of QDockWidget containers, without access to the "parent" QDockWidget instances.

Pitch

Provide a mechanism to subscribe to QDockWidget signals from within dock widgets inheriting from QWidget. This could be done by passing the corresponding QDockWidget instance (or a thin wrapper exposing, for encapsulation reasons) as argument to the dock widget constructor, similar to what's being done with the Viewer instance.

Alternatives

Implement custom events for dock location changes and anything else QDockWidget-related that might come up in the future.

Additional context

While the QDockWidget instance is returned by Window.add_dock_widget, this approach is not applicable in situations where the user opens the dock widget via the GUI menu.

@jwindhager jwindhager added the feature New feature or request label Nov 19, 2021
@tlambert03
Copy link
Member

tlambert03 commented Nov 19, 2021

Howdie @jwindhager 馃憢

However, currently, dock widgets inherit from QWidget and are "only" children of QDockWidget containers,

can you clarify what you mean there? There's a little understandable semantic confusion here, I think of "dock widget" as actually the QDockWidget... but do you mean, "the QWidget that a plugin developer might make", before it gets added to napari?

without access to the "parent" QDockWidget instances.

what about parent()? wondering again whether you mean that you don't have the parent until it gets docked?

Provide a mechanism to subscribe to QDockWidget signals from within dock widgets inheriting from QWidget. This could be done by passing the corresponding QDockWidget instance (or a thin wrapper exposing, for encapsulation reasons) as argument to the dock widget constructor, similar to what's being done with the Viewer instance.

A QWidget can already connect to it's parent's events, for example: self.parent().dockLocationChanged.connect(...), so if your main issue here is that self.parent() is None in your widget __init__ ... then perhaps you're looking to get notified when your QWidget gains a parent? If so, you can do that with an EventFilter. here's an example:

from qtpy.QtWidgets import QWidget, QMainWindow, QApplication, QDockWidget
from qtpy.QtCore import QObject, QEvent, Qt


class MyWidget(QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)
        self.installEventFilter(self)
        print("during init, parent is", self.parent())

    def eventFilter(self, obj: QObject, event: QEvent):
        if event.type() == QEvent.ParentChange:
            parent = self.parent()
            print('parent Changed!, now:', parent)
            if isinstance(parent, QDockWidget):
                parent.dockLocationChanged.connect(
                    lambda area: print("changed location to", area)
                )
        return super().eventFilter(obj, event)


if __name__ == '__main__':
    app = QApplication([])

    wdg = MyWidget()
    win = QMainWindow()
    win.setCentralWidget(QWidget())
    dock_widget = QDockWidget()
    dock_widget.setWidget(wdg)
    win.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, dock_widget)
    win.show()

    app.exec_()

@tlambert03
Copy link
Member

this approach is not applicable in situations where the user opens the dock widget via the GUI menu.

if the approach above doesn't work, all dock widgets are accessible in the private attribute viewer.window._dock_widgets ... not immediately sure we want to expose/promise that publicly, so let me know if the approach above isn't what you wanted

@jwindhager
Copy link
Contributor Author

Hi @tlambert03, thanks so much for the extensive reply!

but do you mean, "the QWidget that a plugin developer might make", before it gets added to napari?

Indeed, that's precisely what I meant - sorry for the confusion.

what about parent()? wondering again whether you mean that you don't have the parent until it gets docked?

Yes, I ran in to the issue that parent() was None in __init__(). Your example was super-helpful! I wasn't aware of eventFilter() and that this could be used to "catch" the parent. This now solved the problem for me. Thanks a lot!

@imagesc-bot
Copy link

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/composing-workflows-in-napari/61222/2

@imagesc-bot
Copy link

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/access-viewer-object-within-magicgui-widget-wrapper/61366/5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants