PyQt5通过拖动选项卡移动QDockWidget

下面的剪辑显示了QDockWidget通过拖动选项卡(而不是标题栏)在停靠区域之间拖动 - 但当我使用 PyQt 5.15.0 尝试此操作时,它不起作用,选项卡不会分离。我怎样才能启用这种行为?


我的代码:

from PyQt5 import QtCore, QtGui, QtWidgets

from PyQt5.QtCore import Qt


if __name__ == "__main__":

    app = QtWidgets.QApplication([])


    main = QtWidgets.QMainWindow()


    dock1 = QtWidgets.QDockWidget("Blue")

    dock2 = QtWidgets.QDockWidget("Green")

    dock3 = QtWidgets.QDockWidget("Red")


    content1 = QtWidgets.QWidget()

    content1.setStyleSheet("background-color:blue;")


    content2 = QtWidgets.QWidget()

    content2.setStyleSheet("background-color:green;")


    content3 = QtWidgets.QWidget()

    content3.setStyleSheet("background-color:red;")


    dock1.setWidget(content1)

    dock2.setWidget(content2)

    dock3.setWidget(content3)


    dock1.setAllowedAreas(Qt.AllDockWidgetAreas)

    dock2.setAllowedAreas(Qt.AllDockWidgetAreas)

    dock3.setAllowedAreas(Qt.AllDockWidgetAreas)


    main.addDockWidget(Qt.LeftDockWidgetArea, dock1)

    main.tabifyDockWidget(dock1, dock2)

    main.addDockWidget(Qt.RightDockWidgetArea, dock3)


    main.resize(400, 200)

    main.show()


    app.exec_()


慕容森
浏览 246回答 2
2回答

一只斗牛犬

我的问题的解决方案是GroupedDragging在setDockOptions. QMainWindow我设法通过下面的代码获得了非常漂亮的外观和行为,就像我想要的那样。from PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import Qtclass DockWidget(QtWidgets.QDockWidget):    def __init__(self, title: str):        super().__init__(title)        self.setTitleBarWidget(QtWidgets.QWidget())        self.dockLocationChanged.connect(self.on_dockLocationChanged)    def on_dockLocationChanged(self):        main: QtWidgets.QMainWindow = self.parent()        all_dock_widgets = main.findChildren(QtWidgets.QDockWidget)        for dock_widget in all_dock_widgets:            sibling_tabs = main.tabifiedDockWidgets(dock_widget)            # If you pull a tab out of a group the other tabs still see it as a sibling while dragging...            sibling_tabs = [s for s in sibling_tabs if not s.isFloating()]            if len(sibling_tabs) != 0:                # Hide title bar                dock_widget.setTitleBarWidget(QtWidgets.QWidget())            else:                # Re-enable title bar                dock_widget.setTitleBarWidget(None)    def minimumSizeHint(self) -> QtCore.QSize:        return QtCore.QSize(100, 100)if __name__ == "__main__":    app = QtWidgets.QApplication([])    main = QtWidgets.QMainWindow()    dock1 = DockWidget("Blue")    dock2 = DockWidget("Green")    dock3 = DockWidget("Red")    content1 = QtWidgets.QWidget()    content1.setStyleSheet("background-color:blue;")    content1.setMinimumSize(QtCore.QSize(50, 50))    content2 = QtWidgets.QWidget()    content2.setStyleSheet("background-color:green;")    content2.setMinimumSize(QtCore.QSize(50, 50))    content3 = QtWidgets.QWidget()    content3.setStyleSheet("background-color:red;")    content3.setMinimumSize(QtCore.QSize(50, 50))    dock1.setWidget(content1)    dock2.setWidget(content2)    dock3.setWidget(content3)    dock1.setAllowedAreas(Qt.AllDockWidgetAreas)    dock2.setAllowedAreas(Qt.AllDockWidgetAreas)    dock3.setAllowedAreas(Qt.AllDockWidgetAreas)    main.addDockWidget(Qt.LeftDockWidgetArea, dock1)    main.tabifyDockWidget(dock1, dock2)    main.addDockWidget(Qt.RightDockWidgetArea, dock3)    main.setDockOptions(main.GroupedDragging | main.AllowTabbedDocks | main.AllowNestedDocks)    main.setTabPosition(Qt.AllDockWidgetAreas, QtWidgets.QTabWidget.North)    main.resize(400, 200)    main.show()    app.exec_()

LEATH

将其发布为已接受答案的一点额外内容。该版本适用于 Qt5 和 Qt6,并且能够检测极端情况,例如拉出选项卡并将其放入同一组中或将浮动选项卡组与停靠窗口合并:from PySide6 import QtCore, QtWidgetsfrom PySide6.QtCore import Qtfrom typing import TypeVar, List, OptionalTDockWidget = TypeVar('TDockWidget', bound='DockWidget')class DockWidget(QtWidgets.QDockWidget):    def __init__(self: TDockWidget, title: str, parent: Optional[QtWidgets.QWidget] = None) -> None:        super(_DockWidget, self).__init__(title, parent)        self.setTitleBarWidget(QtWidgets.QWidget())        self.visibilityChanged.connect(self.on_visibility_changed)        self.dockLocationChanged.connect(self.on_dock_location_changed)    @QtCore.Slot(bool)    def on_visibility_changed(self: TDockWidget, is_visible: bool) -> None:        # this visibility monitor is really only needed to detect merges of        # tabbed, floating windows with existing docked windows        if not is_visible and isinstance(self.parent(), QtWidgets.QMainWindow):            main_window: QtWidgets.QMainWindow = self.parent()            all_dockwidgets: List[QtWidgets.QDockWidget] = main_window.findChildren(QtWidgets.QDockWidget)            for dockwidget in all_dockwidgets:                if hasattr(dockwidget, 'on_dock_location_changed'):                    dockwidget.on_dock_location_changed(main_window.dockWidgetArea(dockwidget), False)    @QtCore.Slot(Qt.DockWidgetArea)    def on_dock_location_changed(self: TDockWidget, area: Qt.DockWidgetArea, update_others: bool = True) -> None:        if not isinstance(self.parent(), QtWidgets.QMainWindow):            # mysterious parents call for a title            self.setTitleBarWidget(None)            return        main_window: QtWidgets.QMainWindow = self.parent()        if not main_window.tabifiedDockWidgets(self):            # if there's no siblings we ain't a tab!            self.setTitleBarWidget(None)            if not update_others:                # prevent infinite recursion                return            # force an update to all other docks that may now no longer be tabs            all_dockwidgets: List[QtWidgets.QDockWidget] = main_window.findChildren(QtWidgets.QDockWidget)            for dockwidget in all_dockwidgets:                if dockwidget != self and hasattr(dockwidget, 'on_dock_location_changed'):                    dockwidget.on_dock_location_changed(main_window.dockWidgetArea(dockwidget), False)            return        # at this point the dockwidget is either a resting tab or a tab        # that is being dragged and hasn't been dropped yet (siblings are updated post-drop)        # collect all siblings of this dockwidget...        tab_siblings: List[QtWidgets.QDockWidget] = main_window.tabifiedDockWidgets(self)        # and filter for non-floating siblings in the same area        tab_siblings = [x for x in tab_siblings if main_window.dockWidgetArea(x) == area and not x.isFloating()]        if tab_siblings:            if self.titleBarWidget() is not None:                # no changes needed, prevent infinite recursion                return            # show a title if we're not floating (this tab is settled),            # hide it otherwise (this tab just became floating but wasn't dropped)            self.setTitleBarWidget(QtWidgets.QWidget() if not self.isFloating() else None)            # in this case it's also a good idea to tell to reconsider their situation            # since Qt won't notify them separately            for sibling in tab_siblings:                if hasattr(sibling, 'on_dock_location_changed'):                    sibling.on_dock_location_changed(main_window.dockWidgetArea(sibling), True)        else:            self.setTitleBarWidget(None)if __name__ == "__main__":    app = QtWidgets.QApplication([])    main = QtWidgets.QMainWindow()    dock1 = DockWidget("Blue")    dock2 = DockWidget("Green")    dock3 = DockWidget("Red")    content1 = QtWidgets.QWidget()    content1.setStyleSheet("background-color:blue;")    content1.setMinimumSize(QtCore.QSize(50, 50))    content2 = QtWidgets.QWidget()    content2.setStyleSheet("background-color:green;")    content2.setMinimumSize(QtCore.QSize(50, 50))    content3 = QtWidgets.QWidget()    content3.setStyleSheet("background-color:red;")    content3.setMinimumSize(QtCore.QSize(50, 50))    dock1.setWidget(content1)    dock2.setWidget(content2)    dock3.setWidget(content3)    dock1.setAllowedAreas(Qt.AllDockWidgetAreas)    dock2.setAllowedAreas(Qt.AllDockWidgetAreas)    dock3.setAllowedAreas(Qt.AllDockWidgetAreas)    main.addDockWidget(Qt.LeftDockWidgetArea, dock1)    main.tabifyDockWidget(dock1, dock2)    main.addDockWidget(Qt.RightDockWidgetArea, dock3)    main.setDockOptions(main.GroupedDragging | main.AllowTabbedDocks | main.AllowNestedDocks)    main.setTabPosition(Qt.AllDockWidgetAreas, QtWidgets.QTabWidget.North)    main.resize(400, 200)    main.show()    app.exec_()
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python