2 回答
TA贡献1784条经验 获得超2个赞
我的问题的解决方案是GroupedDragging
在setDockOptions
. QMainWindow
我设法通过下面的代码获得了非常漂亮的外观和行为,就像我想要的那样。
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_()
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_()
添加回答
举报