多文档区QMdiArea和子窗口QMdiSubWindow
用QMainWindow 建立的主界面,通常会同时建立或打开多个相互独立的文档,这些文档共享主界面的菜单、工具栏和停靠控件,多文档中只有一个文档是活跃的文档,菜单和工具栏的操作只针对当前活跃的文档。
主界面要实现多文档操作需要用QMdiArea控件,通常把QMdiArea 定义成中心控件。
可以在QMdiArea 控件中添加多个子窗口QMdiSubWindow,通常每个子窗口都有相同的控件,当然控件也可以不相同,这时代码会比较复杂。
QMdiArea 是从抽象类QAbastractScrollArea 继承而来的
from PySide6.QtWidgets import QMdiArea
QMdiArea(parent: Union[PySide6.QtWidgets.QWidget,NoneType]=None)-> None
多文档区QMdiArea的属性
常量 | 描述 | 访问功能 |
---|---|---|
QMdiArea.activationOrder: WindowOrder | 此属性保存子窗口列表的排序条件。 此属性指定subWindowList()返回的子窗口列表的排序条件。默认情况下,它是窗口创建顺序。 | activationOrder() setActivationOrder(order) |
QMdiArea.background: PySide6.QtGui.QBrush | 此属性保存工作区的背景画笔。 此属性设置工作区区域本身的背景画笔。默认情况下,它是灰色,但可以是任何画笔(例如,颜色、渐变或像素图)。 | background() setBackground(background) |
QMdiArea.documentMode: bool | 此属性保存选项卡栏是否在选项卡式视图模式下设置为文档模式。 默认情况下禁用文档模式。 | documentMode() setDocumentMode(enabled) |
tabPosition: TabPosition | 此属性在选项卡式视图模式下保存选项卡的位置。 TabPosition枚举描述了此属性的可能值。 | tabPosition() setTabPosition(position) |
QMdiArea.tabShape: TabShape | 此属性在选项卡式视图模式下保存选项卡的形状。 此属性的可能值为四舍五入(默认)或三角形。 | tabShape() setTabShape(shape) |
QMdiArea.tabsClosable: bool | 此属性保存选项卡栏是否应在选项卡式视图模式下在每个选项卡上放置关闭按钮。 默认情况下,选项卡不可关闭。 | tabsClosable() setTabsClosable(closable) |
QMdiArea.tabsMovable: bool | 此属性保存用户是否可以在选项卡式视图模式下移动选项卡栏区域内的选项卡。 默认情况下,选项卡不可移动。 | tabsMovable() setTabsMovable(movable) |
QMdiArea.viewMode: ViewMode | 此属性支持子窗口在QMdiArea中的显示方式。 默认情况下,SubWindowView用于显示子窗口。 | viewMode() setViewMode(mode) |
多文档区QMdiArea的枚举值
-
PySide6.QtWidgets.QMdiArea.AreaOption
(继承枚举.标志)此枚举描述自定义QMdiArea行为的选项。
Constant Description QMdiArea.DontMaximizeSubWindowOnActivation 当活动子窗口最大化时,默认行为是最大化激活的下一个子窗口。如果不希望出现此行为,请设置此选项。 -
PySide6.QtWidgets.QMdiArea.WindowOrder
指定用于对subWindowList()返回的子窗口列表进行排序的标准。配置窗口时,cascadeSubWindows()和tileSubWindows()函数遵循此顺序。
Constant Description QMdiArea.CreationOrder 窗口按其创建顺序返回。 QMdiArea.StackingOrder 窗口按照堆叠的顺序返回,最上面的窗口是列表中的最后一个。 QMdiArea.ActivationHistoryOrder 窗口按照激活的顺序返回。 -
PySide6.QtWidgets.QMdiArea.ViewMode
该枚举描述了该区域的视图模式; 即子窗口将如何显示。
Constant Description QMdiArea.SubWindowView 显示带有窗口框架的子窗口(默认)。 QMdiArea.TabbedView 在选项卡栏中显示带有选项卡的子窗口。 -
PySide6.QtWidgets.QTabWidget.TabShape
此枚举类型定义选项卡的形状:
Constant Description QTabWidget.Rounded 标签是圆形的。这是默认形状。 QTabWidget.Triangular 标签以三角形的外观绘制。
多文档区QMdiArea的常用方法
多文档区QMdiArea常用方法方法介绍如下:
-
用QMdiArea 的addSubWindow(QWidget,Qt.WindowFlags)方法可以往多文档区中添加子窗口,并返回子窗口,参数QWidget 可以是子窗口,也可以是其他控件,如果是其他控件,则先创建其他控件,然后在子窗口上添加该控件;
-
QMdiArea中的子窗口类型是QMdiSubWindow的实例,但可以使用addSubWindow()方法将任何QWidget或其派生类的实例添加到MDI区域作为子窗口,此时QMdiArea会自动创建子窗口的QMdiSubWindow实例,并作为addSubWindow()方法的结果返回。
-
用removeSubWindow(QWidget)方法可以从多文档中移除子窗口或子窗口上的控件,使用该方法子窗口或控件并没有真正删除,其父窗口变成 None。如果移除的是控件,则控件所在的子窗口并没有被移除。
-
用QMdiArea 的setViewMode(QMdiArea.ViewMode)方法可以设置多文档区中子窗口的显示模式,其中参数 QMdiArea.ViewMode 可 以取:
- QMdiArea.SubWindowView(子窗口视图)
- QMdiArea.TabbedView(Tab标签视图),这两种视图的样式如图所示。
-
在子窗口视图模式下,可以随意缩放和拖动窗口,还可以设置子窗口的排列形式。
- 用cascadeSubWindows()方法可以设置子窗口为层叠排列显示,
- 用tileSubWindows()方法可以设置子窗口为平铺排列显示,这两种排列形式如图所示。
-
用QMdiArea 的currentSubWindow()方法可以获得当前子窗口,如果没有子窗口或活跃窗口,则返回值是 None;
- 用setActiveSubWindow(QMdiSubWindow)方法可以使某个子窗口变成活跃窗口。
-
如果用户在界面上单击某个子窗口,则单击的子窗口变成活跃窗口。如果用代码使某个窗口活跃,则要考虑子窗口的顺序。
- setActivationOrder(QMdiArea.WindowOrder)方法可以设置子窗口的活跃顺序的规则,其中参数QMdiArea.WindowOrder见枚举值
- 用activateNextSubWindow()方法和activatePreviousSubWindow()方法可以按照活跃顺序分别激活下一个子窗口和前一个子窗口
- subWindowList(QMdiArea.WindowOrder)方法可以按照指定的顺序获取子窗口的列表List[QMdiSubWindowJ。
-
用QMdiArea 的setOption(QMdiArea.AreaOption,bool)方法可以设置子窗口在活跃时的状态,其中参数QMdiArea.AreaOption 只有一个取值:
PySide6.QtWidgets.QMdiArea.AreaOption.DontMaximizeSubWindowOnActivation
,当活动子窗口被最大化时,默认行为是最大化下一个被激活的子窗口。如果您不希望出现这种行为,请设置此选项。
-
子窗口数量
- QMdiArea中的子窗口数量无法直接通过QMdiArea方法获取,必须先通过方法subWindowList()返回所有子窗口的列表,再通过Python的len函数获取子窗口的数量。
多文档区QMdiArea常用方法:
QMdiArea的方法及参数类型 | 返回值的类型 | 说明 |
---|---|---|
addSubWindow(widget[,flags=Qt.WindowFlags()]) | QMdiSubWindow | 用控件创建一个子窗口,并返回子窗口 将小部件作为新的子窗口添加到MDI区域。如果窗口标志不为零,它们将覆盖在小部件上设置的标志。 小部件可以是QMdiSubWindow或另一个QWidget(在这种情况下,MDI区域将创建一个子窗口并将小部件设置为内部小部件)。 添加子窗口后,其父窗口将是QMdiArea的视窗小部件。 mdiArea = QMdiArea() subWindow1 = QMdiSubWindow() subWindow1.setWidget(internalWidget1) subWindow1.setAttribute(Qt.WA_DeleteOnClose) mdiArea.addSubWindow(subWindow1) subWindow2 = mdiArea.addSubWindow(internalWidget2) 创建自己的子窗口时,如果希望在MDI区域中关闭窗口时删除该窗口,则必须设置WA_DeleteOnClose窗口属性。如果没有,窗口将被隐藏,MDI区域将不会激活下一个子窗口。 返回添加到MDI区域的QMdiSubWindow。 |
removeSubWindow(QWidget) | None | 移除控件所在的子窗口 从MDI区域中删除小部件。小部件必须是QMdiSubWindow或作为子窗口内部小部件的小部件。Note widget从未被QMdiArea实际删除。如果传入QMdiSubWindow,则其父窗口设置为None,并将其删除; 但是如果传入内部小部件,子小部件设置为None,并且不会删除QMdiSubWindow。 |
setViewMode(PySide6.QtWidgets.QMdiArea.ViewMode) | None | 设置子窗口在QMdiArea中的显示样式,ViewMode见枚举值 |
viewMode() | QMdiArea.ViewMode | 获取子窗口的显示样式 |
[slot]cascadeSubWindows() | None | 层叠显示子窗口 以级联模式排列所有子窗口。 |
[slot]tileSubWindows() | None | 平铺显示子窗口 |
[slot]closeActiveSubWindow() | None | 关闭活跃的子窗口 |
[slot]closeAllSubWindows() | None | 关闭所有的子窗口 通过向每个窗口发送qcloseevent关闭所有子窗口。在子窗口关闭之前,您可能会收到子窗口激活()信号(如果MDI区域在另一个窗口关闭时激活子窗口)。 忽略关闭事件的子窗口将保持打开状态。 |
currentSubWindow() | QMdiSubWindow | 获取当前的子窗口 |
scrollContentsBy(dx: int,dy:int) | None | 移动子窗口中的控件 |
setActivationOrder(QMdiArea.WindowOrder) | None | 设置子窗口的活跃顺序,WindowOrder见枚举值 |
activationOrder() | QMdiArea.WindowOrder | 获取活跃顺序 |
subWindowList(QMdiArea.WindowOrder=QMdiArea. | List[QMdiSubWindowJ | 按照指定的顺序获取子窗口列表 返回MDI区域中所有子窗口的列表。如果order为CreationOrder(默认值),则按照将窗口插入工作区的顺序对窗口进行排序。如果order为StackingOrder,则窗口按其堆叠顺序列出,最顶层的窗口作为列表中的最后一项。如果order是activationhistory order,则根据其最近的激活历史记录列出窗口。 |
[slot]activateNextSubWindow() | None | 激活下一个子窗口 将键盘焦点放在子窗口列表中的另一个窗口上。激活的窗口将是由当前激活顺序确定的下一个窗口。 |
[slot]activatePreviousSubWindow() | None | 激活前一个子窗口 将键盘焦点放在子窗口列表中的另一个窗口上。激活的窗口将是由当前激活顺序确定的前一个窗口。 |
[slot]setActiveSubWindow(PySide6.QtWidgets.QMdiSubWindow) | None | 设置活跃的子窗口 激活子窗口。如果窗口为None,则任何当前活动窗口将被停用。 |
activeSubWindow() | QMdiSubWindow | 获取活跃的子窗口 返回指向当前活动子窗口的指针。如果当前没有窗口处于活动状态,则返回None。 就窗口状态而言,子窗口被视为顶级窗口,即,如果MDI区域之外的小部件是活动窗口,则不会激活子窗口。请注意,如果MDI区域所在窗口中的小部件获得焦点,则该窗口将被激活。 |
setBackground(Union[QBrush,QColor,Qt.GlobalColor,QGradient]) | None | 设置背景颜色,默认是灰色 |
background() | QBrush | 获取背景色画刷 |
setOption(QMdiArea.AreaOption,bool) | None | 设置子窗口的模式,AreaOption见枚举值 |
testOption(QMdiArea.AreaOption) | bool | 获取是否设置了选项 |
setTabPosition(QTabWidget.TabPosition) | None | 设置Tab 标签的位置 |
tabPosition() | QTabWidget.TabPosition | 获取 Tab标签的位置 |
setTabShape(PySide6.QtWidgets.QTabWidget.TabShape) | None | 设置Tab标签的形状,TabShape见枚举值 |
tabShape() | QTabWidget.TabShape | 获取 Tab标签的形状 |
setTabsClosable(bool) | None | Tab 模式时设置Tab 标签是否有关闭按钮 |
tabsClosable() | bool | 获取 Tab标签上是否有关闭按钮 |
setTabsMovable(bool) | None | Tab 模式时设置Tab 标签是否可移动 |
tabsMovable() | bool | 获取 Tab标签是否可移动 |
setDocumentMode(bool) | None | Tab 模式时设置Tab 标签是否文档模式 |
documentMode() | bool | Tab 模式时获取Tab 标签是否文档模式 |
多文档区 QMdiArea 的信号
多文档区QMdiArea只有一个信号 subWindowActivated(PySide6.QtWidgets.QMdiSubWindow)
窗口激活后,QMdiArea会发出此信号。当窗口为None时,QMdiArea刚刚停用了其最后一个活动窗口,并且工作区中没有活动窗口。
子窗口QMdiSubWindow
QMdiSubWindow 表示 QMdiArea 中的顶级窗口,由带有窗口装饰的标题栏、内部小部件以及(取决于当前样式)窗口框架和大小夹点组成。QMdiSubWindow 有自己的布局,该布局由标题栏和内部小部件的中心区域组成。
构造 QMdiSubWindow 的最常见方法是调用 addSubWindow()并将内部小部件作为参数。也可以自己创建一个子窗口,并通过调用 setWidget()来设置内部小部件。
在使用子窗口编程时,您可以使用与常规顶级窗口相同的 API(例如,您可以调用 show()、hide()、showMaximized()和 setWindowTitle()等函数)。
QMdiSubWindow是从QWidget类继承而来的。
from PySide6.QtWidgets import QMdiSubWindow
QMdiSubWindow(parent: Union[PySide6.QtWidgets.QWidget,NoneType]=None,flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags))-> None
QMdiSubWindow 还支持特定于 MDI 区域中子窗口的行为。
默认情况下,每个 QMdiSubWindow 在移动时在 MDI 区域视口内可见,但也可以指定透明窗口移动和调整大小行为,在这些操作期间仅更新子窗口的轮廓。setOption()函数用于启用此行为。
isShaded()函数检测子窗口当前是否着色(即,窗口已折叠,以便只有标题栏可见)。要进入着色模式,请调用 showShaded()。
每当窗口状态发生变化时(例如,当窗口最小化或恢复时),QMdiSubWindow 都会发出 windowStateChanged()信号。它还会在激活之前发出 aboutToActivate()。
在键盘交互模式下,窗口会随着键盘移动和调整大小。可以通过窗口的系统菜单进入此模式。键盘单步和键盘页面步属性控制每个按键事件的小组件移动或调整大小的距离。当按下移位时,使用页面步骤;否则使用单步。
您还可以使用键盘更改活动窗口。通过同时按下 Control 和 Tab 键,将激活下一个(使用当前)子窗口。通过按 控制、转移和选项卡,您将激活上一个窗口。这相当于调用 activateNextSubWindow()和 activatePreviousSubWindow()。请注意,这些快捷方式会覆盖全局快捷方式,但不会覆盖 QMdiArea 的快捷方式。WindowOrder
子窗口QMdiSubWindow的属性
属性 | 描述 | 访问功能 |
---|---|---|
keyboardPageStep: int | 此属性用于设置小部件在使用键盘页面键时应移动或调整大小的距离。。 在键盘交互模式下,可以使用箭头和页面键移动窗口或调整窗口大小。此属性控制页面键。进入键盘交互模式的常见方法是进入子窗口菜单,然后选择"调整大小"或"移动"。 默认的键盘页面步长值为20像素。 | keyboardPageStep() setKeyboardPageStep(step) |
keyboardSingleStep: int | 此属性用于设置使用键盘箭头键时小部件应移动或调整大小的距离。。 在键盘交互模式下,可以使用箭头和页面键移动窗口或调整窗口大小。此属性控制箭头键。进入键盘交互模式的常见方法是进入子窗口菜单,然后选择"调整大小"或"移动"。 默认的键盘单步值为5个像素。 | keyboardSingleStep() setKeyboardSingleStep(step) |
子窗口QMdiSubWindow 的常用方法
-
用QMdiSubWindow 的setWidget(QWidget)方法可以往子窗口上添加控件;用widget()方法可以获取子窗口上的控件。
-
用QMdiSubWindow 的 showShaded()方法可以把子窗口折叠起来,只显示标题栏。
-
用QMdiSubWindow 的 setOption(QMdiSubWindow.SubWindowOption,bool)方法可以设置子窗口缩放或移动时只显示外轮廓,参数 QMdiSubWindow.SubWindowOption 可以取:
PySide6.QtWidgets.QMdiSubWindow.SubWindowOption(继承enum.Flag)此枚举描述了自定义QMdiSubWindow行为的选项。
Constant Description QMdiSubWindow.RubberBandResize 缩放时只显示外轮廓.如果启用此选项,则会使用橡皮筋控件来表示子窗口的轮廓,并且用户会调整其大小,而不是子窗口本身。因此,子窗口将保持其原始位置和大小,直到调整大小操作完成,此时它将接收一个QResizeEvent。默认情况下,此选项处于禁用状态。 QMdiSubWindow.RubberBandMove 移动时只显示外轮廓.如果启用此选项,则会使用一个橡皮筋控件来表示子窗口的轮廓,并且用户会移动它,而不是子窗口本身。因此,子窗口保持在其原始位置,直到移动操作完成,此时QMoveEvent被发送到窗口。默认情况下,此选项处于禁用状态。
子窗口QMdiSubWindow 的常用方法:
QMdiSubWindow的方法及参数类型 | 返回值的类型 | 说明 |
---|---|---|
setWidget(QWidget) | None | 将QWidget设置为此子窗口的内部小部件。内部小部件显示在标题栏下方子窗口的中心。 QMdiSubWindow获得小部件的临时所有权;您不必删除它。任何现有的内部小部件都将被删除并重新发送到根窗口。 |
widget() | QWidget | 获取子窗口中的控件 |
[slot]showShaded() | None | 只显示标题栏 调用此函数会使子窗口进入着色模式。当子窗口着色时,只有标题栏可见。 尽管并非所有样式都支持着色,但无论是否支持着色,此函数仍会将子窗口显示为着色。但是,当与不支持着色的样式一起使用时,用户将无法通过用户界面(例如,通过标题栏中的着色按钮)从着色模式返回。 |
isShaded() | bool | 如果此窗口被着色,则返回true;否则返回false。 如果窗口被折叠,则该窗口将被着色,从而仅显示标题栏。 |
mdiArea() | QMdiArea | 返回包含此子窗口的区域,如果没有,则返回"None"。 |
setSystemMenu(QMenu:QtWidgets.QMenu) | None | 将systemMenu设置为此子窗口的当前系统菜单。 默认情况下,每个QMdiSubWindow都有一个标准的系统菜单。 QMdiSubWindow创建的系统菜单的Q操作将根据当前窗口状态自动更新;例如,最小化操作将在窗口最小化之后被禁用。 QMdiSubWindow不会更新用户添加的Q操作。 QMdiSubWindow拥有systemMenu的所有权;您不必删除它。任何现有的菜单都将被删除。 |
systemMenu() | QMenu | 返回指向当前系统菜单的指针,如果未设置系统菜单,则返回零。QMdiSubWindow提供了默认的系统菜单,但您也可以使用setSystemMenu()设置菜单。 |
[slot]showSystemMenu() | None | 在标题栏中的系统菜单图标下方显示系统菜单。 |
setKeyboardPageStep(step:int) | None | 设置用键盘Page 键控制子窗口移动或缩放时的增量步 |
keyboardPageStep() | int | 获取用键盘Page键控制子窗口移动或缩放时的增量步 |
setKeyboardSingleStep(step:int) | None | 设置用键盘箭头键控制子窗口移动或缩放时的增量步 |
keyboardSingleStep() | int | 获取用键盘箭头键控制子窗口移动或缩放时的增量步 |
setOption(option:QMdiSubWindow.SubWindowOption[,on=true]) | None | 如果on为true,则在子窗口上启用选项;否则它将被禁用。有关每个选项的效果,请参见子窗口选项。 |
maximizedButtonsWidget() | QWidget | 最大化按钮小工具 |
maximizedSystemMenuIconWidget() | QWidget | 最大化系统菜单图标桥 |
testOption(arg__1:QMdiSubWindow.SubWindowOption) | bool | 如果选项已启用,则返回true;否则返回false。 |
子窗口QMdiSubWindow的信号
信号 | 描述 |
---|---|
aboutToActivate() | QMdiSubWindow在激活之前立即发出此信号。子窗口激活后,管理子窗口的QMdiArea也将发出subWindowActivated()信号。 |
windowStateChanged(oldState:PySide6.QtCore.Qt.WindowState,newState:PySide6.QtCore.Qt.WindowState) | QMdiSubWindow在窗口状态改变后发出此信号。oldState是更改之前的窗口状态,newState是新的当前状态。 PySide6.QtCore.Qt.WindowState(继承enum.Flag)此枚举类型用于指定顶级窗口的当前状态。详见下表 |
Constant | Description |
---|---|
Qt.WindowNoState | 该窗口没有设置状态(处于正常状态)。 |
Qt.WindowMinimized | 窗口最小化(即图标化)。 |
Qt.WindowMaximized | 窗口被最大化,周围有一个框架。 |
Qt.WindowFullScreen | 该窗口填充整个屏幕,周围没有任何边框。 |
Qt.WindowActive | 该窗口是活动窗口,即它具有键盘焦点。 |
实例
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 22:59
# File_name: demo.py
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
class MainWindow(QMainWindow):
count = 0
def __init__(self,parent=None):
super(MainWindow,self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
# 添加菜单栏
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
file.addAction("cascade")
file.addAction("Tiled")
file.triggered[QAction].connect(self.windowaction)
self.setWindowTitle("MDI 示例")
def windowaction(self,q):
# 通过点击不同的按钮实现不同布局的显示方式
if q.text()=="New":
MainWindow.count = MainWindow.count + 1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow"+ str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()
if q.text()=="cascade":
self.mdi.cascadeSubWindows()
if q.text()=="Tiled":
self.mdi.tileSubWindows()
if __name__ =='__main__':
app = QApplication(sys.argv)
demo = MainWindow()
demo.show()
sys.exit(app.exec())