项目场景:
使用 PySide6(PyQt 应该类似) 开发 GUI 界面,主界面分为很多个板块(使用 QDockWidget),想实现每个 QDockWidget 在 floating 弹出时,默认最大化 floating 窗口,便于用户操作。
但是 QDockWidget 默认只有 close、float 两个按钮,且单击 float 按钮或双击标题栏,QDockWidget 只会简单地弹出,标题栏按钮均消失不见,且无法最大化。
希望增加 QDockWidget 功能,实现 floating 弹出后,QDockwidget 标题栏有最大化、最小化按钮,且支持自动最大化窗口。
解决方案(初)
参考博客 Qt实战10.支持最小化和最大化的QDockWidget,主题思路为创建一个新类继承 QDockWidget 并重写方法,即
def event(self, event: QEvent):
if event.type() == QEvent.ZOrderChange:
if self.isFloating():
w = QWidget(self)
self.setMaximumSize(w.maximumSize())
self.setWindowFlags(Qt.Dialog | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint)
self.show()
return super(DockWidget, self).event(event)
为了防止用户手残将 QDockWidget 窗口关掉没法恢复,
self.setWindowFlags
不添加Qt.WindowCloseButtonHint
,取消关闭按钮功能。
但该方法仍然存在不足:
- 若要恢复窗口,只能双击标题栏,点击最小化按钮会使 QDockWidget 收起。希望点击最小化后实现恢复窗口功能。
- 窗口 floating 弹出时,只能由用户手动点击最大化按钮实现窗口最大化,无法自动实现最大化功能。
解决方案(终)
经过一顿修改,完整代码如下:
from PySide6.QtCore import Qt, QEvent
from PySide6.QtWidgets import QWidget, QDockWidget
class DockWidget(QDockWidget):
def __init__(self, parent=None, need_maximize=False):
super(DockWidget, self).__init__(parent)
self.window_flags = self.windowFlags()
self.maximum_size = self.maximumSize()
self.need_maximize = need_maximize
self.show_flag = False
def event(self, event: QEvent):
if event.type() == QEvent.ZOrderChange:
if self.isFloating():
w = QWidget(self)
self.setMaximumSize(w.maximumSize())
self.setWindowFlags(Qt.Dialog | Qt.WindowMinimizeButtonHint)
self.show()
self.show_flag = True
return super(DockWidget, self).event(event)
def changeEvent(self, event: QEvent):
if event.type() == QEvent.WindowStateChange:
if self.isMinimized():
self.setFloating(False)
self.setMaximumSize(self.maximum_size)
self.setWindowFlags(self.window_flags)
self.setWindowState(Qt.WindowNoState)
self.show()
if self.need_maximize and (self.windowState() & Qt.WindowNoState == Qt.WindowNoState) and self.show_flag:
self.showMaximized()
self.show_flag = False
return super(DockWidget, self).changeEvent(event)
class DockMaximizeWidget(DockWidget):
def __init__(self, parent=None):
super(DockMaximizeWidget, self).__init__(parent, need_maximize=True)
逐段代码分析
-
最小化按钮功能更改:
changeEvent
def changeEvent(self, event: QEvent): if event.type() == QEvent.WindowStateChange: if self.isMinimized(): self.setFloating(False) self.setMaximumSize(self.maximum_size) self.setWindowFlags(self.window_flags) self.setWindowState(Qt.WindowNoState) self.show() ...
- 使用
event.type() == QEvent.WindowStateChange
和self.isMinimized()
检测窗口是否被最小化; self.setFloating(False)
取消窗口浮动状态;self.setMaximumSize(self.maximum_size) self.setWindowFlags(self.window_flags)
用于恢复窗口默认属性;self.setWindowState(Qt.WindowNoState)
将 WindowState 状态清空,防止后续检测不到最小化行为;self.show()
显示 floating 窗口。
上述代码用于更改最小化按钮的行为,实现 docker 窗口恢复。
... if self.need_maximize and (self.windowState() & Qt.WindowNoState == Qt.WindowNoState) and self.show_flag: self.showMaximized() self.show_flag = False return super(DockWidget, self).changeEvent(event) ...
self.need_maximize
控制窗口是否要默认最大化;self.windowState() & Qt.WindowNoState == Qt.WindowNoState
确保窗口处于默认状态;self.show_flag
记录窗口的最大化行为;self.showMaximized()
最大化窗口。
重要:不能在
event
事件中执行self.showMaximized()
,否则最大化无效。上述代码效果为,当 docker 窗口从 non-floating 状态变成 floating 弹出状态时,自动最大化窗口。
... return super(DockWidget, self).changeEvent(event)
一定要调用
super(DockWidget, self).changeEvent(event)
,否则会出现 docker 标题消失等迷之 bug。 - 使用
-
自定义弹出窗口:
event
def event(self, event: QEvent): if event.type() == QEvent.ZOrderChange: if self.isFloating(): w = QWidget(self) self.setMaximumSize(w.maximumSize()) self.setWindowFlags(Qt.Dialog | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint) self.show() self.show_flag = True return super(DockWidget, self).event(event)
- 增加
self.show_flag = True
记录窗口从 non-floating 状态变成 floating 弹出状态; - 其余与前文博客内容相同。
- 增加
-
类初始化:
__init__
def __init__(self, parent=None, need_maximize=False): super(DockWidget, self).__init__(parent) self.window_flags = self.windowFlags() self.maximum_size = self.maximumSize() self.need_maximize = need_maximize self.show_flag = False
need_maximize
设置弹出时窗口是否默认最大化;window_flags
和maximum_size
记录窗口默认状态;self.show_flag = False
清空窗口弹出记录。
-
再包装一下
class DockMaximizeWidget(DockWidget): def __init__(self, parent=None): super(DockMaximizeWidget, self).__init__(parent, need_maximize=True)
DockWidget
支持最大、最小化按钮,DockMaximizeWidget
窗口弹出时默认最大化,在QtDesigner
中可以直接对QDockWidget
进行类提升,使用方便。
站在巨人的肩膀上+自己动手丰衣足食,完美解决问题,mark 一下。图懒得放了。