为了账号安全,请及时绑定邮箱和手机立即绑定

PyQt5通过拖动选项卡移动QDockWidget

PyQt5通过拖动选项卡移动QDockWidget

慕容森 2023-06-27 17:58:41
下面的剪辑显示了QDockWidget通过拖动选项卡(而不是标题栏)在停靠区域之间拖动 - 但当我使用 PyQt 5.15.0 尝试此操作时,它不起作用,选项卡不会分离。我怎样才能启用这种行为?我的代码:from PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import Qtif __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_()
查看完整描述

2 回答

?
一只斗牛犬

TA贡献1784条经验 获得超2个赞

我的问题的解决方案是GroupedDraggingsetDockOptionsQMainWindow我设法通过下面的代码获得了非常漂亮的外观和行为,就像我想要的那样。

from PyQt5 import QtCore, QtGui, QtWidgets

from PyQt5.QtCore import Qt



class 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_()


查看完整回答
反对 回复 2023-06-27
?
LEATH

TA贡献1936条经验 获得超6个赞

将其发布为已接受答案的一点额外内容。该版本适用于 Qt5 和 Qt6,并且能够检测极端情况,例如拉出选项卡并将其放入同一组中或将浮动选项卡组与停靠窗口合并:


from PySide6 import QtCore, QtWidgets

from PySide6.QtCore import Qt


from typing import TypeVar, List, Optional


TDockWidget = 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_()


查看完整回答
反对 回复 2023-06-27
  • 2 回答
  • 0 关注
  • 168 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信