2024-06-13-Pyside6窗口控件

1.主窗口控件

1.1 主窗口控件

之前,我们使用可视控件创建具体的实例时都选择了一个父窗体,将控件放到这个窗体上,即使在创建实例时没有选择父窗体,也可以用控件的 setParent() 方法将控件放到父窗体上。如果一个控件没有放到任何窗体上,则这个控件可以单独成为窗口,并且可以作为父窗口来使用,可在其上面添加其他控件,这种控件可以称为程序的独立窗口(independent widget)。

QWidget 可以当作普通的容器控件使用,也可以当作独立的窗口来使用。当一个控件有父窗口时,不显示该控件的标题栏;当控件没有父窗口时,会显示标题栏。

QMainWindow 窗口与 QWidget 窗口的最大区别在于窗口上的控件和控件的布局。QMainWindow 窗口通常当作主窗口使用,在它上面除了可以添加菜单栏、工具栏、状态栏外,还可以建立可浮动和可停靠的窗口(QDockWidget)、中心控件(CentralWidget)、多文档区(QMdiArea)和子窗口(QMdiSubWindow)。

QMainWindow窗口的布局如下所示:

image-20240615155022896

一般在顶部放置菜单栏,在底部放置状态栏,在中心位置放置一个控件,控件类型任意,在中心控件的四周可以放置可停靠控件 QDockWidget,在可停靠控件的四周是工具栏放置区。需要注意的是,QMainWindow 窗口需要有个中心控件。 QMainWindow 的中心窗口可以是单窗口,也可以是多窗口,多窗口需要把 QMdiArea 控件作为中心控件。中心控件为主显示区,工具栏和可停靠控件可以用鼠标进行拖拽、悬浮和停靠操作。

QMainWindow 主窗口是从 QWidget 类继承而来的。用 QMainWindow 创建主窗口实例的方法如下所示,其中参数 parent 通常不用设置,当作独立窗口使用。

QMainWindow(parent:QWidget=None)
QMainWindow(parent:QWidget=None, flags:Qt.WindowFlags=Default(Qt.WindowFlags))

主窗口 QMainWindow 的方法主要针对中心控件、菜单栏、状态栏、停靠控件、工具栏进行设置,主要方法介绍如下。

# 实例方法
setCentralWidget(widget:QWidget) -> None                                                            # 设置中心控件
centralWidget() -> QWidget                                                                          # 获取中心控件
takeCentralWidget() -> QWidget                                                                      # 移除中心控件

setMenuBar(menubar:QMenuBar) -> None                                                                # 设置菜单栏
menuBar() -> QMenuBar                                                                               # 获取菜单栏
setMenuWidget(menubar:QWidget) -> None                                                              # 设置菜单栏控件
menuWidget() -> QWidget                                                                             # 获取菜单栏控件
createPopupMenu() -> QMenu                                                                          # 创建弹出菜单

setStatusBar(statusbar:QStatusBar) -> None                                                          # 设置状态栏
statusBar() -> QStatusBar                                                                           # 获取状态栏

addToolBar(title:str) -> QToolBar                                                                   # 添加工具栏,并返回新创建的工具栏
addToolBar(toolbar:QToolBar) -> None                                                                # 在顶部添加工具栏
addToolBar(area:Qt.ToolBarArea, toolbar:QToolBar) -> None                                           # 在指定区域添加工具栏
insertToolBar(before:QToolBar, toolbar:QToolBar) -> None                                            # 在第一个工具条前插入工具条
removeToolBar(toolbar:QToolBar) -> None                                                             # 移除工具栏

addToolBarBreak(area:Qt.ToolBarArea=Qt.TopToolBarArea) -> None                                      # 添加工具条放置区域,两个工具栏可以并排或者并列显示
insertToolBarBreak(before:QToolBar) -> None                                                         # 在指定工具栏前插入工具栏放置区域
removeToolBarBreak(before:QToolBar) -> None                                                         # 移除工具栏前插入放置区域

toolBarArea(toolbar:QToolBar) -> Qt.ToolBarArea                                                     # 获取工具栏的停靠区
toolBarBreak(toolbar:QToolBar) -> bool                                                              # 获取工具栏是否分割

setToolButtonStyle(toolButtonStyle:Qt.ToolButtonStyle) -> None                                      # 设置工具栏按钮样式
toolButtonStyle() -> Qt.ToolButtonStyle                                                             # 获取工具栏按钮样式

addDockWidget(area:Qt.DockWidgetArea, dockwidget:QDockWidget) -> None                               # 在指定停靠区域添加停靠控件
addDockWidget(area:Qt.DockWidgetArea, dockwidget:QDockWidget, orientation:Qt.Orientation) -> None   # 在指定停靠区域添加停靠控件,并指定停靠方向
removeDockWidget(dockwidget:QDockWidget) -> bool                                                    # 移除停靠控件
dockWidgetArea(dockwidget:QDockWidget) -> Qt.DockWidgetArea                                         # 获取停靠控件的停靠区域
isDockNestingEnabled() -> bool                                                                      # 获取停靠区是否可放一个控件

restoreDockWidget(dockwidget:QDockWidget) -> bool                                                   # 恢复停靠控件
restoreState(state:QByteArray, version:int=0) -> bool                                               # 恢复停靠控件的状态
saveState(version:int=0)  -> QByteArray                                                             # 保存停靠控件的状态

isAnimated() -> bool                                                                                # 获取停靠控件是否使用动画效果

setCorner(corner:Qt.Corner, area:Qt.DockWidgetArea) -> None                                         # 设置某个角落属于停靠区的哪一部分
corner(corner:Qt.Corner) -> Qt.DockWidgetArea                                                       # 获取某个角落属于停靠区的哪一部分

setDocumentMode(enabled:bool) -> None                                                               # 设置Tab标签是否是文档模式
documentMode() -> bool                                                                              # 获取Tab标签是否是文档模式

setIconSize(iconSize:QSize) -> None                                                                 # 设置Tab标签的图标大小
iconSize() -> QSize                                                                                 # 获取Tab标签的图标大小

setTabPosition(areas:Qt.DockWidgetArea, tabPosition:Qt.TabPosition) -> None                         # 多个停靠控件重叠时,设置Tab标签的位置,默认在底部
setTabShape(tabShape:Qt.TabShape) -> None                                                           # 多个停靠控件重叠时,设置Tab标签的形状

splitDockWidget(after:QDockWidget, dockwidget:QDockWidget, orientation:Qt.Orientation) -> None      # 将被挡住的停靠控件分为两部分


tabifyDockWidget(first:QDockWidget, second:QDockWidget) -> None                                     # 将第二个停靠控件放在第一个停靠控件的上部,通常创建停靠控件
tabifiedDockWidgets(dockwidget:QDockWidget) -> List[QDockWidget]                                    # 获取停靠区中停靠控件列表

# 槽方法
setDockNestingEnabled(enabled:bool) -> None                                                         # 设置停靠区是否可容纳多个控件
setAnimated(enabled:bool) -> None                                                                   # 设置停靠控件是否使用动画效果

主窗口 QMainWindow 的常用信号如下:

iconSizeChanged(iconSize:QSize)                                 # 当工具栏按钮的尺寸发生变化时发射信号
tabifiedDockWidgetActivated(dockWidget:QDockWidget)             # 重叠的停靠控件激活时发射信号
toolButtonStyleChanged(toolButtonStyle:Qt.ToolButtonStyle)      # 当工具栏按钮的样式发生变化时发射信号

1.2 菜单和动作

​ 一般菜单栏由多个菜单构成,菜单下面又有动作、子菜单和分隔条,子菜单下面又有动作,还可以有子菜单,动作上有图标和快捷键。

建立一个菜单分为 3 步:

  1. 需要建立放置菜单的容器,即菜单栏;
  2. 在菜单栏上添加菜单,或者在菜单上添加子菜单;
  3. 在菜单栏、菜单或子菜单下面添加动作,并为动作编写槽函数。

建立菜单的步骤

菜单一般不执行命令,其作用类似于标签,只有动作才可以发送信号,执行关联的槽函数。

1.2.1 菜单栏

QMenuBar 类是所有窗口的菜单栏,用户需要再次基础上添加不同的 QMenu 和 QAction 类,创建菜单栏有两种方法,分别是 QMenuBar 类的构造方法QMainWindow 对象的 menuBar() 方法。

menuBar = QMenuBar(parent:QWidget=None)

menuBar = mainWindow.menuBar()

QMenuBar 类的常用方法如下:

addMenu(menu:QMenu) -> QAction                                              # 添加已经存在的菜单
addMenu(title:str) -> QMenu                                                 # 用字符串添加菜单,并返回菜单
addMenu(icon:QIcon, title:str) -> QMenu                                     # 用图标和字符串添加菜单,并返回菜单
addAction(action:QAction) -> None                                           # 添加已经存在的动作
addAction(text:str) -> QAction                                              # 用字符串添加动作,并返回动作
insertMenu(before:QAction, menu:QMenu) -> QAction                           # 在指定的动作之前插入菜单
addSeparator() -> QAction                                                   # 添加分隔符
insertSeparator(before:QAction) -> QAction                                  # 在指定的动作之前插入分隔符
clear() -> None                                                             # 清空菜单
setCornerWidget(w:QWidget, corner:Qt.Corner=Qt.TopRightCorner) -> None      # 在菜单栏的角落位置添加控件
cornerWidget(corner:Qt.Corner=Qt.TopRightCorner) -> QWidget                 # 获取角落位置的控件
setActiveAction(action:QAction) -> None                                     # 设置高亮显示的动作
actionAt(arg__1:QPoint) -> QAction                                          # 获取指定位置的动作
actionGeometry(arg__1:QAction) -> QRect                                     # 获取动作的矩形

菜单栏上可以添加菜单、动作和分隔条,用 addMenu(QMenu) 方法和 addAction(QAction) 方法可以添加已经提前定义好的菜单和动作;用 addMenu(str) 方法和 addMenu(QIcon,str) 方法可以创建并添加菜单,并返回新建立的菜单;用 addAction(str) 方法可以用字符串创建并添加动作,并返回动作;用 setCornerWidget(QWidget,Qt.Corner=Qt.TopRightCorner) 方法可以在菜单栏的角落位置添加控件,位置可取值如下:

Qt.TopLeftCorner
Qt.TopRightCorner
Qt.BottomLeftCorner
Qt.BottomRightCorner

QMenuBar 类的常用信号如下:

hovered(action:QAction)         # 当光标划过控件时发射信号
triggered(action:QAction)       # 当单击菜单栏上的菜单或动作时发射信号

1.2.2 菜单

​ 菜单 QMenu 用于放置动作和子菜单,通常将动作分类放到不同的菜单中。菜单 QMenu 继承自 QWidget。用 QMenu 类创建菜单实例的方法如下所示:

QMenu(parent:QWidget=None)
QMenu(title:str, parent:QWidget=None)

QMenu 类表示菜单栏中的菜单,可以显示文本和图标,但是并不负责执行操作,类似于 QLable 的作用。

QMenu 类的常用方法如下:

# 实例方法
addMenu(menu:QMenu) -> QAction                                                      # 在菜单中添加子菜单
addMenu(title:str) -> QMenu                                                         # 在菜单中添加新子菜单
addMenu(icon:QIcon, title:str) -> QMenu                                             # 在菜单中添加新子菜单
insertMenu(before:QAction, menu:QMenu) -> QAction                                   # 在指定的动作之前插入菜单

addAction(action:QAction) -> None                                                   # 在菜单中添加已经存在的动作
addAction(text:str) -> QAction                                                      # 在菜单中添加新动作
addAction(icon:QIcon, title:str) -> QAction                                         # 在菜单中添加新动作

addSeparator() -> QAction                                                           # 添加分隔符
addSection(text:str) -> QAction                                                     # 添加分隔符
addSection(icon:QIcon, text:str) -> QAction                                         # 添加分隔符
insertSeparator(before:QAction) -> QAction                                          # 在指定的动作之前插入分隔符
insertSection(before:QAction, text:str) -> QAction                                  # 在指定的动作之前插入分隔符
insertSection(before:QAction, icon:QIcon, text:str) -> QAction                      # 在指定的动作之前插入分隔符
removeAction(action:QAction) -> None                                                # 从菜单中删除动作

clear() -> None                                                                     # 清空菜单
actions() -> List[QAction]                                                          # 获取动作列表
isEmpty() -> bool                                                                   # 判断菜单是否为空
actionAt(arg__1:int) -> QAction                                                     # 获取指定位置的动作
columnCount() -> int                                                                # 获取列数
menuAction() -> QAction                                                             # 获取菜单动作

setSeparatorsCollapsible(collapse:bool) -> None                                     # 设置是否可以折叠分隔符
setTearOffEnabled(arg__1:bool) -> None                                              # 设置是否可以拖动分隔符
showTearOffMenu() -> None                                                           # 以拖动方式显示菜单
showTearOffMenu(pos:QPoint) -> None                                                 # 以拖动方式显示菜单
hideTearOffMenu() -> None                                                           # 隐藏拖动菜单
isTearOffEnabled() -> bool                                                          # 判断是否可以拖动分隔符
isTearOffMenuVisible() -> bool                                                      # 判断是否显示拖动菜单

setTitle(title:str) -> None                                                         # 设置菜单标题
title() -> str                                                                      # 获取菜单标题
setIcon(icon:QIcon) -> None                                                         # 设置菜单图标
icon() -> QIcon                                                                     # 获取菜单图标

setActiveAction(action:QAction) -> None                                             # 设置活跃的动作高亮显示
activeAction() -> QAction                                                           # 获取活跃的动作
setDefaultAction(arg__1:QAction) -> None                                            # 设置默认动作
defaultAction() -> QAction                                                          # 获取默认动作

popup(pos:QPoint, at:QAction=None) -> None                                          # 弹出菜单

# 静态方法
exec(actions:Sequence[QAction], pos:QPoint, at:QAction=None, parent:QWidget=None)   # 在指定位置显示菜单,当pos无法确定位置时,用父控件的parent辅助确定位置

QMenu 类常用的信号及其说明如下:

aboutToHide()                   # 窗口即将隐藏时发射信号
aboutToShow()                   # 窗口即将显示时发射信号
hovered(action:QAction)         # 鼠标悬停时发射信号
triggered(action:QAction)       # 鼠标单击时发射信号

1.2.3 动作

动作 QAction 是定义菜单和工具栏的基础,单击菜单或工具栏上的动作可以触发动作的 triggered() 信号,执行动作关联的槽函数,完成需要完成的工作。动作在菜单中以项(item)的形式显示,在工具栏中以按钮的形式显示。

动作 QAction 继承自 QObject,位于 QtGui 模块中。用 QAction创建动作对象的方法如下所示:

QAction(parent:QObject=None)
QAction(text:str, parent:QObject=None)
QAction(icon:Union[QIcon, QPixmap], text:str, parent:QObject=None)

其中 parent 通常是 窗口工具栏菜单栏菜单text显示的文字,如果将动作放到菜单或工具栏上,text将成为菜单或工具栏中按钮的文字;icon图标,将成为菜单或工具栏中按钮的图标。

QAction 类的常用方法如下:

# 实例方法
setText(text:str) -> None                               # 设置菜单项文本
text() -> str                                           # 获取菜单项文本
setIcon(icon:QIcon) -> None                             # 设置菜单项的图标
icon() -> QIcon                                         # 获取菜单项图标
setIconVisibleInMenu(visible:bool) -> None              # 设置图标是否显示在菜单中
isIconVisibleInMenu() -> bool                           # 获取图标是否显示在菜单中
setData(var:Any) -> None                                # 设置菜单项数据
data() -> Any                                           # 获取菜单项数据

setToolTip(tip:str) -> None                             # 设置菜单项提示
setStatusTip(statusTip:str) -> None                     # 设置状态提示
setWhatsThis(what:str) -> None                          # 设置按Shift+F1键时的提示

setCheckable(arg__1:bool) -> None                       # 设置菜单项是否可选
isCheckable() -> bool                                   # 获取菜单项是否可选
isChecked() -> bool                                     # 获取菜单项是否选中
isEnabled() -> bool                                     # 获取菜单项是否可用
isVisible() -> bool                                     # 获取菜单项是否可见

setShortcutVisibleInContextMenu(show:bool) -> None      # 设置快捷键是否显示在右键菜单中
setShortcuts(arg__1:QKeySequence) -> None               # 设置快捷键
setShortcuts(shortcuts:QKeySequence.StandardKey)        # 设置快捷键

setFont(font:QFont) -> None                             # 设置菜单项字体
font() -> QFont                                         # 获取菜单项字体
setMenu(arg__1:QMenu) -> None                           # 设置菜单项的子菜单
menu() -> QMenu                                         # 获取菜单项的子菜单

setActionGroup(group:QActionGroup) -> None              # 设置菜单项的动作组

setSeparator(b:bool) -> None                            # 设置菜单项是否为分隔符

setAutoRepeat(arg__1:bool) -> None                      # 设置菜单项是否自动重复
autoRepeat() -> bool                                    # 获取菜单项是否自动重复

# 槽方法
setChecked(arg__1:bool) -> None                         # 设置菜单项是否选中
setEnabled(arg__1:bool) -> None                         # 设置菜单项是否可用
setDisabled(b:bool) -> None                             # 设置菜单项是否失效
setVisible(arg__1:bool) -> None                         # 设置菜单项是否可见
resetEnabled() -> None                                  # 重置菜单项是否可用
hover() -> None                                         # 发送hover()信号
trigger() -> None                                       # 发送tigger(bool)信号
toggle() -> None                                        # 发送toggle(bool)信号

QAction 类常用信号及其说明如下:

changed()                            # 改变时发射信号
checkableChanged(checkable:bool)     # 可选状态改变时发射信号
enabledChanged(enabled:bool)         # 启用状态改变时发射信号
hovered()                            # 鼠标悬停时发射信号
toggled(arg__1:bool)                 # 状态翻转时发射信号
triggered(checked:bool=false)        # 鼠标单击时发射信号
visibleChanged()                     # 可见状态改变时发射信号
import sys

from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWidgets import QMenuBar, QMenu
from PySide6.QtWidgets import QMessageBox
from PySide6.QtGui import QAction, QPixmap

class MyWidget(QMainWindow):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.1.创建一个菜单栏
        menuBar = QMenuBar(self)
        # 2.2.将菜单栏添加到窗口中
        self.setMenuBar(menuBar)

        # 3.1.添加文件菜单
        file_menu = QMenu()
        # 3.2.设置文件菜单的文本
        file_menu.setTitle("文件")
        # 3.3.将文本菜单添加到菜单栏中
        menuBar.addMenu(file_menu)

        # 4.1.添加编辑菜单,并设置文本
        edit_menu = QMenu("编辑")
        # 4.2.将编辑菜单添加到菜单栏中
        menuBar.addMenu(edit_menu)

        # 5.1.为文件菜单项添加新建菜单
        new_action = QAction(menuBar)
        # 5.2.设置菜单项是否可用
        new_action.setEnabled(True)
        # 5.3.设置菜单项文本
        new_action.setText("新建(&N)")
        # 5.4.设置菜单项快捷键
        new_action.setShortcut("Ctrl+N")
        # 5.5.设置打开菜单项的图标
        new_action.setIcon(QPixmap("new.ico"))
        # 5.6.将新建菜单项添加到文件菜单中
        file_menu.addAction(new_action)

        # 6.添加间隔线
        file_menu.addSeparator()

        # 7.1.为文件菜单项添加打开菜单,并设置文本和图标
        open_action = QAction(QPixmap("open.ico"), "打开(&O)", file_menu)
        # 7.2.设置打开菜单项的快捷键
        open_action.setShortcut("Ctrl+O")
        # 7.3.将打开菜单项添加到文件菜单中
        file_menu.addAction(open_action)

        # 8.打开菜单绑定triggered信号
        menuBar.triggered.connect(self.get_menu)

    def get_menu(self, menu):
        QMessageBox.information(self, "提示信息", f"你选择的是{menu.text()}", QMessageBox.StandardButton.Ok)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

在使用 PySide6 中的菜单时,只有 QAction 菜单项可以执行操作,QMenuBar 菜单栏和 QMenu 菜单都是不会执行任何操作的。

image-20240615155731084

1.2.4 工具栏

与菜单类似,工具栏也是一组命令的集合地。菜单上放置的动作也可放到工具栏上,实现工具栏和菜单的同步。工具栏上除了放置动作外,还可以放置其他控件等。在 QMainWindow 窗口中,工具栏还可以拖动和悬浮。

工具栏 QToolBar 用于存放动作,动作在工具栏中一般呈现按钮状态。QToolBar 继承自 QWidget。用 QToolBar 类创建工具栏实例的方法如下:

QToolBar(parent:QWidget=None)
QToolBar(title:str, parent:QWidget=None)

其中 title 是工具栏控件的 标题名称,可通过 setWindowTitle(str) 方法修改;parent 是工具栏所在的 窗口

QToolBar 类常用方法如下:

# 实例方法
addAction(action:QAction) -> None                                                   # 添加已经存在的动作到工具栏
addAction(text:str) -> QAction                                                      # 创建并添加动作,返回新建立的动作
addAction(icon:QIcon, title:str) -> QAction                                         # 创建并添加动作,返回新建立的动作

addSeparator() -> QAction                                                           # 添加分隔符
insertSeparator(before:QAction) -> QAction                                          # 在指定的动作之前插入分隔符

addWidget(widget:QWidget) -> QAction                                                # 添加控件,并返回与控件关联的动作
insertWidget(before:QAction, widget:QWidget) -> QAction                             # 在指定的动作之前插入控件,并返回与控件关联的动作

clear() -> None                                                                     # 清空菜单

widgetForAction(action:QAction) -> QWidget                                          # 返回与动作关联的控件

actionAt(x:int, y:int) -> QAction                                                   # 返回指定位置处的动作
actionAt(p:QPoint) -> QAction                                                       # 返回指定位置处的动作
actionGeometry(action:QAction) -> QRect                                             # 返回指定动作的矩形区域

setFloatable(floatable:bool) -> None                                                # 设置动作是否可以浮在其他窗口上
isFloatable() -> bool                                                               # 返回动作是否可以浮在其他窗口上
isFloating() -> bool                                                                # 返回动作是否浮在其他窗口上
setMovable(movable:bool) -> None                                                    # 设置动作是否可以移动
isMovable() -> bool                                                                 # 返回动作是否可以移动

iconSize () -> QSize                                                                # 返回动作图标大小

setOrientation(orientation:Qt.Orientation) -> None                                  # 设置动作的方向
orientation() -> Qt.Orientation                                                     # 返回动作的方向

toolButtonStyle() -> Qt.ToolButtonStyle                                             # 返回动作样式

setAllowedAreas(areas:Qt.ToolButtonArea) -> None                                    # 设置可停靠的区域
allowedAreas() -> Qt.ToolButtonArea                                                 # 获取可停靠的区域
isAreaAllowed(area:Qt.ToolButtonArea) -> bool                                       # 获取指定的区域是否可以停靠
toggleViewAction() -> QAction                                                       # 切换停靠窗口的可见状态

# 槽函数
setIconSize(iconSize:QSize) -> None                                                 # 设置动作图标大小
setToolButtonStyle(toolButtonStyle:Qt.ToolButtonStyle) -> None                      # 设置动作样式

setOrientation(Qt.Orientation) 方法可以设置工具栏的方向,其中 Qt.Orientation可以取值如下:

Qt.Orientation.Horizontal    # 水平
Qt.Orientation.Vertical      # 竖直

setToolButtonStyle(Qt.ToolButtonStyle) 方法可以设置工具栏上按钮的风格,其中Qt.ToolButtonStyle 可以取值如下:

Qt.ToolButtonStyle.ToolButtonIconOnly              # 只显示图标
Qt.ToolButtonStyle.ToolButtonTextOnly              # 只显示文字
Qt.ToolButtonStyle.ToolButtonTextBesideIcon        # 文字在图标的旁边)
Qt.ToolButtonStyle.ToolButtonTextUnderIcon         # 文字在图标的下面)
Qt.ToolButtonStyle.ToolButtonFollowStyle           # 遵循风格设置

在 QMainWindow 窗口中,用 setAllowedAreas(Qt.ToolBarArea) 方法可以设置工具栏的停靠区域,其中Qt.ToolBarArea 参数指定可以停靠的区域,可以取值如下:

Qt.ToolBarArea.LeftToolBarArea     # 左侧
Qt.ToolBarArea.RightToolBarArea    # 右侧)
Qt.ToolBarArea.TopToolBarArea      # 顶部,菜单栏下部
Qt.ToolBarArea.BottomToolBarArea   # 底部,状态栏上部
Qt.ToolBarArea.AllToolBarAreas     # 所有区域都可以停靠
Qt.ToolBarArea.NoToolBarArea       # 不可停靠

如果工具栏是可移动的,则无论 allowedAreas 设置何值都可以移动,但只有在进入 toolBar 的 allowedAreas 范围内时才会自动显示 toolBar 停靠区域范围,并在鼠标释放后自动在该范围内缩放,否则将保持最适合的大小浮动在窗口之上。

toggleViewAction() 方法返回一个动作对象,通过单击该动作对象可以切换停靠窗口的可见状态,即该动作是一个对停靠控件窗口进行显示或关闭的开关,如果将该动作加到菜单上,对应菜单栏的文字即为停靠窗口的标题名称,这样就可以在菜单上单击对应菜单项进行停靠窗口的关闭和显示。

QToolBar 类常用信号及其说明如下:

actionTriggered(action:QAction)                                # 工具栏按钮被触发时发射信号
allowedAreasChanged(allowedAreas:Qt.ToolBarArea)               # 工具栏按钮显示区域改变时发射信号
iconSizeChanged(iconSize:QSize)                                # 工具栏按钮图标大小改变时发射信号
movableChanged(movable:bool)                                   # 工具栏移动时发射信号
orientationChanged(orientation:Qt.Orientation)                 # 工具栏按钮显示的方向改变时发射信号
toolButtonStyleChanged(toolButtonStyle:Qt.ToolButtonStyle)     # 文本显示样式改变时发射信号
topLevelChanged(topLevel:bool)                                 # 工具栏浮动属性改变时发射信号
visibilityChanged(visible:bool)                                # 工具栏按钮是否可见改变时发射信号

工具按钮控件 QToolButton 常放在工具栏中,显示图标而不显示文字。通常为工具按钮设置弹出式菜单,用于选择之前的操作。

QToolButton 继承自 QAbstractButton。用 QToolButton 类创建工具按钮实例的方法如下:

QToolButton(parent:QWidget=None)

其中 parent 参数一般是工具按钮所在的 窗口工具栏

QToolButton 类的常用方法如下:

# 实例方法
setMenu(menu:QMenu) -> None                             # 设置菜单
setPopupMode(mode:QToolButton.PopupMode) -> None        # 设置弹出模式
setArrowType(type:Qt.ArrowType) -> None                 # 设置箭头类型
setAutoExclusive(arg__1:bool) -> None                   # 设置是否互斥
setShortcut(key:str) -> None                            # 设置快捷键
setText(text:str) -> None                               # 设置文本
setIcon(icon:QIcon) -> None                             # 设置图标
setCheckable(arg__1:bool) -> None                       # 设置是否可选
setAutoRaise(enable:bool) -> None                       # 设置是否自动弹起

# 槽函数
showMenu() -> None                                      # 显示菜单
setDefaultAction(arg__1:QAction) -> None                # 设置默认动作
setToolButtonStyle(style:Qt.ToolButtonStyle) -> None    # 设置工具按钮样式
setIconSize(size:QSize) -> None                         # 设置图标大小
setChecked(arg__1:bool) -> None                         # 设置是否选中
click() -> None                                         # 鼠标单击事件

setPopupMode(QToolButton.ToolButtonPopupMode) 方法可以设置菜单的弹出方式。其中参数 QToolButton.ToolButtonPopupMode 取值如下:

QToolButton.ToolButtonPopupMode.DelayedPopup     # 用鼠标按下按钮并保持一会儿后弹出菜单
QToolButton.ToolButtonPopupMode.MenuButtonPopup  # 在工具按钮的右下角上出现一个向下的黑三角,单击这个黑三角,弹出菜单
QToolButton.ToolButtonPopupMode.InstantPopup     # 立即弹出菜单

在 QMainWindow 的 QToolBar 中使用工具按钮时,按钮会自动调节尺寸来适应 QMainWindow 的设置。按钮的外观和尺寸可通过 setToolButtonStyle(Qt.ToolButtonStyle) 方法和 setIconSize(QSize) 方法来设置,其中参数 Qt.ToolButtonStyle 可以取值如下:

Qt.ToolButtonStyle.ToolButtonIconOnly
Qt.ToolButtonStyle.ToolButtonTextOnly
Qt.ToolButtonStyle.ToolButtonTextBesideIcon
Qt.ToolButtonStyle.ToolButtonTextUnderIcon
Qt.ToolButtonStyle.ToolButtonFollowStyle

setArrowType(Qt.ArrowType) 方法可以设置工具按钮上的箭头形状,其中 Qt.ArrowType可以取值如下:

Qt.NoArrow
Qt.UpArrow
Qt.DownArrow
Qt.LeftArrow
Qt.RightArrow

QToolButton 类的常用信号如下:

triggered(arg__1:QAcion)    # 激活动作时发射信号
clicked(checked=false)      # 点击按钮时发射信号
pressed()                   # 按下按钮时发射信号
released()                  # 释放按钮时发射信号
import sys

from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWidgets import QToolBar, QToolButton, QMenu
from PySide6.QtWidgets import QMessageBox, QComboBox
from PySide6.QtGui import Qt, QAction, QIcon

class MyWidget(QMainWindow):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个工具栏
        toolBar = QToolBar(self)

        # 3.将工具栏添加到窗口中
        self.addToolBar(toolBar)

        # 4.设置工具栏是否可以移动
        toolBar.setMovable(True)

        # 5.设置工具栏的显示样式
        toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)

        # 6.设置工具栏的方向
        toolBar.setOrientation(Qt.Orientation.Horizontal)

        # 7.添加图标按钮
        toolBar.addAction(QIcon("1.ico"), "新建")

        action_new = QAction(QIcon("1.ico"), "打开", self)
        action_open = QAction(QIcon("1.ico"), "打开", self)
        action_close = QAction(QIcon("1.ico"), "关闭", toolBar)
        toolBar.addAction(action_new)
        toolBar.addActions([action_open, action_close])

        # 8.添加其它组件
        comboBox = QComboBox()
        names = ["木之本樱", "御坂美琴", "夏娜"]
        comboBox.addItems(names)
        toolBar.addWidget(comboBox)

        # 9.添加工具按钮
        toolButton = QToolButton(self)
        # 创建菜单
        menu = QMenu("文件", self)
        # 往菜单中添加动作
        menu.addActions([action_new, action_open, action_close])
        # 为按钮控件添加菜单
        toolButton.setMenu(menu)
        # 设置工具按钮的箭头样式
        toolButton.setArrowType(Qt.ArrowType.DownArrow)
        # 设置工具按钮的样式
        toolButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
        # 工具栏中添加工具按钮
        toolBar.addWidget(toolButton)

        # 9.为工具栏绑定actionTriggered信号
        toolBar.actionTriggered.connect(self.get_tooBar)

    def get_tooBar(self, toolBar):
        QMessageBox.information(self, "提示信息", f"你选择的是{toolBar.text()}", QMessageBox.StandardButton.Ok)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

如果设置垂直工具栏没有效果,那可能是你先调用 setOrientation(orientation) 设置工具栏方向,在将工具栏添加到窗体中。

单击工具栏中的 QAction 对象默认会发送 actionTriggered 信号,但是如果为工具栏添加了其它控件,并不会发射 actionTriggered 信号,而是会发射它们自己的特有信号。

image-20240615155918184

1.2.5 状态栏

状态栏 QStatusBar 一般放在独立窗口的底部,用于显示程序运行过程中的程序状态信息、提示信息、简要说明信息等,这些信息经过一小段时间后会自动消失。状态栏上也可以放置一些小控件等,用于显示永久信息,永久信息不会被实时信息遮挡住。

状态栏 QStatusBar 继承自 QWidget。用 QStatusBar 类创建状态栏实例的方法如下:

QStatusBar(parent:QWidget=None)

其中 parent 是状态的 父窗口,一般是独立窗口。

QStatusBar 类常用方法及其说明如下:

# 实例方法
urrentMessage() -> str                                                      # 获取当前显示的信息
addWidget(widget:QWidget, stretch:int=0) -> None                            # 在状态栏的左侧添加临时的控件,stretch是拉伸比例
insertWidget(index:int, widget:QWidget, stretch:int=0) -> None              # 在状态栏的左侧插入临时的控件,stretch是拉伸比例
removeWidget(widget:QWidget) -> None                                        # 从状态栏中移除控件
addPermanentWidget(widget:QWidget, stretch:int=0) -> None                   # 在状态栏的右侧添加永久性的控件,stretch是拉伸比例
insertPermanentWidget(index:int, widget:QWidget, stretch:int=0) -> None     # 在状态栏的右侧插入永久性的控件,stretch是拉伸比例
setSizeGripEnabled(arg__1:bool) -> None                                     # 设置在右下角是否有三角形
isSizeGripEnabled() -> bool                                                 # 获取右下角是否有三角形
hideOrShow() -> None                                                        # 确保右边的控件可见

# 槽函数
showMessage(text:str, timeout:int=0) -> None                                # 显示信息,timeout是显示时间
clearMessage() -> None                                                      # 清空信息

showMessage(text:str,timeout:int=0) 方法设置状态栏要显示的信息,显示的信息从状态的左侧开始,其中参数 timeout 的单位是毫秒,设置信息显示的时间,经过 timeout 毫秒后信息自动消失,如果 timeout=0,则显示的信息一直保留到调用 clearMessage() 方法或再次调用 showMessage() 方法;用 clearMessage() 方法清除显示的信息;用 currentMessage() 方法获取当前显示的信息。

addPermanentWidget(QWidget,stretch:int=0) 方法或 insertPermanentWidget(index:int,widget:QWidget,stretch:int=0) 方法可以把其他控件添加到状态栏的右侧,用于显示一些永久的信息。其中参数 stretch 用于指定控件的相对缩放系数,index 是控件的索引号。

addtWidget(widget:QWidget,stretch:int=0) 方法或 insertWidget(index:int,QWidget,stretch:int=0) 方法可以把其他控件添加到状态栏的左侧,用于显示正常的信息,这些信息会被状态栏的信息遮挡住。

removeWidget(QWidget) 方法可以把控件从状态栏上移除,但控件并没有被真正删除,可以用 addWidget() 方法和 show() 方法将控件重新添加到状态栏中。

setSizeGripEnabled(bool) 方法可以设置状态栏的右侧是否有一个小三角形标识。

QStatusBar 类常用信号及其说明如下:

messageChanged(text:str)            # 消息改变时发送信号
import sys

from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWidgets import QStatusBar
from PySide6.QtWidgets import QComboBox
from PySide6.QtCore import QTimer, QDateTime

class MyWidget(QMainWindow):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个状态栏
        self.statusBar = QStatusBar(self)

        # 3.将状态栏添加到窗口中
        self.setStatusBar(self.statusBar)

        # 4.向状态栏中添加控件
        comboBox = QComboBox()
        names = ["木之本樱", "御坂美琴", "夏娜"]
        comboBox.addItems(names)
        self.statusBar.addPermanentWidget(comboBox)

        # 5.1.创建一个QTime定时器对象
        timer = QTimer(self)
        # 5.2.发射timeout信号
        timer.timeout.connect(self.show_time)
        # 5.3.启动定时器
        timer.start()

    def show_time(self):
        # 获取当前日期时间
        datatime = QDateTime.currentDateTime()
        # 对日期时间进行格式化
        text = datatime.toString("yyyy_MM-dd HH:mm:ss")
        # 在状态栏中显示一条临时消息
        self.statusBar.showMessage(f"当前日期时间: {text}")

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

默认情况下,状态栏中的临时消息和添加的控件不能同时显示,否则会发生覆盖重合的情况。此时,我们可以使用 addPermanentWidget(widget, stretch=0) 添加永久性控件来解决;

image-20240615160030351

1.2.6 停靠控件

​ 停靠控件 QDockWidget 主要应用在主窗口中,用鼠标可以将其拖拽到不同的停靠区域中。停靠控件通常作为容器来使用,需要在其内部添加一些常用控件。停靠控件由标题栏和内容区构成,标题栏上显示窗口标题,还有浮动按钮和关闭按钮。

停靠控件 QDockWidget 继承自 QWidget。用 QDockWidget 类创建停靠控件实例的方法如下所示:

QDockWidget(parent:QWidget=None, flags:Qt.WindowFlags=Default(Qt.WindowFlags))
QDockWidget(title:str, parent:QWidget=None, flags:Qt.WindowFlags=Default(Qt.WindowFlags))

其中 title 是停靠控件的 窗口标题parent 是停靠控件所在的 窗口

停靠控件 QDockWidget 类常用的方法如下:

setAllowedAreas(areas:Qt.DocksWidthArea) -> None            # 设置可停靠区域
isAreaAllowed(area:Qt.DocksWidthArea) -> bool               # 获取区域是否允许停靠
allowedAreas() -> Qt.DocksWidthArea                         # 获取可停靠区域

setFeatures(features:Qt.DocksWidthFeatures) -> None         # 设置特征
setFloating(floating:bool) -> None                          # 设置是否浮动状态

setTitleBarWidget(widget:QWidget) -> None                   # 设置标题栏控件
titleBarWidget() -> QWidget                                 # 获取标题栏控件

setWidget(widget:QWidget) -> None                           # 添加控件
widget() -> QWidget                                         # 获取控件

toggleViewAction() -> QAction                               # 获取隐藏或显示的动作

setFeatures(QDockWidget.DockWidgetFeatures) 方法设置停靠控件的特征,其中参数 QDockWidget.DockWidgetFeature 可以取值如下:

QDockWidget.DockWidgetFeature.DockWidgetClosable           # 可关闭
QDockWidget.DockWidgetFeature.DockWidgetMovable            # 可移动
QDockWidget.DockWidgetFeature.DockWidgetFloatable          # 可悬停
QDockWidget.DockWidgetFeature.DockWidgetVerticalTitleBar   # 有竖向标题
QDockWidget.DockWidgetFeature.NoDockWidgetFeatures         # 没有以上特征

toggleViewAction() 方法返回一个 QAction 动作对象,单击该动作对象可以切换停靠窗口的可见状态,即该动作是一个对停靠控件窗口进行显示或关闭的开关。如果将该动作加到菜单上,对应菜单栏的文字即为停靠窗口的 title 文字,这样就可以在菜单上单击对应菜单项进行停靠窗口的关闭和显示。

停靠控件 QDockWidget 类常用的信号如下:

allowedAreasChanged(allowedAreas:Qt.DockWidgetAreas)        # 允许停靠的区域发生改变时发射信号
dockLocationChanged(area:Qt.DockWidgetArea)                 # 停靠的区域发生改变时发射信号
featuresChanged(features:QDockWdget.DockWidgetFeature)      # 特征改变时发射信号
topLevelChanged(topLevel:bool)                              # 悬浮和停靠状态转换时发射信号
visibilityChanged(visible:bool)                             # 可见性改变时发射信号
import sys

from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWidgets import QDockWidget
from PySide6.QtWidgets import QFontComboBox
from PySide6.QtCore import Qt

class MyWidget(QMainWindow):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建停靠控件
        dock_font = QDockWidget("字体", self)
        dock_font.setObjectName("字体")
        dock_color = QDockWidget("颜色", self)
        dock_color.setObjectName("颜色")

        # 3.在主窗口中添加停靠控件
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, dock_font)
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, dock_color)

        # 4.设置停靠控件的特征
        dock_font.setFeatures(
            QDockWidget.DockWidgetFeature.DockWidgetFloatable |
            QDockWidget.DockWidgetFeature.DockWidgetMovable |
            QDockWidget.DockWidgetFeature.DockWidgetClosable)
        dock_font.setFeatures(
            QDockWidget.DockWidgetFeature.DockWidgetFloatable |
            QDockWidget.DockWidgetFeature.DockWidgetMovable |
            QDockWidget.DockWidgetFeature.DockWidgetClosable)

        # 5.两个悬停控件层叠
        self.tabifyDockWidget(dock_font, dock_color)

        # 6.创建字体组合框框控件对象
        fontComboBox = QFontComboBox()

        # 7.往停靠控件中添加控件
        dock_font.setWidget(fontComboBox)

        # 8.定义信号与槽的连接
        self.tabifiedDockWidgetActivated.connect(self.choose_dock_widget)

    def choose_dock_widget(self, dockWidget):
        print(f"你选择了【{dockWidget.objectName()}】停靠控件")

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615160250254

2 MDI窗口设计

MDI 窗口(Multiple-Document Interface),又称多文档界面,它主要用于同时显示多个文档,每个文档显示在各自的窗口中。MDI 窗口中通常包含子菜单和窗口菜单,用于在窗口或文档之间进行切换。

用 QMainWindow 建立的主界面,通常会同时建立或打开多个相互独立的文档,这些文档共享主界面的菜单、工具栏和停靠控件,多文档中只有一个文档是活跃的文档,菜单和工具栏的操作只针对当前活跃的文档。主界面要实现多文档操作需要用 QMdiArea 控件,通常把 QMdiArea 定义成中心控件。可以在 QMdiArea 控件中添加多个子窗口 QMdiSubWindow,通常每个子窗口都有相同的控件,当然控件也可以不相同。

多文档区 QMdiArea 和子窗口 QMdiSubWindow 的继承关系如下所示:

QMdiArea与QMdiSubWindow的继承关系

用 QMdiArea 类和 QMdiSubWindow 类创建多文档实例和子窗口实例的方法如下。

QMdiArea(parent:QWidget=None)
QMdiSubWindow(parent:QWidget=None, flags:Qt.WindowFlags=Default(Qt.WindowFlags))

QMidArea 类常用的方法及其说明如下:

# 实例方法
addSubWindow(widget:QWidget, flags:Qt.WindowFlags=Qt.WindowFlags()) -> QMdiSubWindow                    # 添加子窗口
removeSubWindow(widget:QWidget) -> None                                                                 # 删除子窗口

setViewMode(mode:QMdiArea.ViewMode) -> None                                                             # 设置MDI区域的视图模式
viewMode() -> QMdiArea.ViewMode                                                                         # 获取MDI区域的视图模式

currentSubWindow() -> QMdiSubWindow                                                                     # 获取当前子窗口

scrollContentsBy(dx:int, dy:int) -> None                                                                # 移动子窗口中的控件
setActivationOrder(order:QMdiArea.WindowOrder) -> None                                                  # 设置子窗口的活跃顺序
activationOrder() -> QMdiArea.WindowOrder                                                               # 获取子窗口的活跃顺序
subWindowList(order:QMdiArea.WindowOrder=QMdiArea.WindowOrder.CreationOrder) -> List[QMdiSubWindow]     # 按照指定顺序获取子窗口列表
activeSubWindow() -> QMdiSubWindow                                                                      # 获取活跃的子窗口

setBackground(background:Union[QBrush, QColor, Qt.GlobalColor, QGradient]) -> None                      # 设置背景,默认是灰色
background() -> QBrush                                                                                  # 获取背景色画刷
setOption(option:QMdiArea.Option, on:bool=True) -> None                                                 # 设置子窗口选项
testOption(opton:QMdiArea.Option) -> bool                                                               # 获取子窗口是否设置了选项

setTabPosition(position:QTabWidget.TabPosition) -> None                                                 # 设置Tab标签的位置
tabPosition() -> QTabWidget.TabPosition                                                                 # 获取Tab标签的位置
setTabShape(shape:QTabWidget.TabShape) -> None                                                          # 设置Tab标签的形状
tabShape() -> QTabWidget.TabShape                                                                       # 获取Tab标签的形状
setTabsClosable(closable:bool) -> None                                                                  # 设置Tab标签是否可关闭
tabsClosable() -> bool                                                                                  # 获取Tab标签是否可关闭
setTabsMovable(movable:bool) -> None                                                                    # 设置Tab标签是否可移动
tabsMovable() -> bool                                                                                   # 获取Tab标签是否可移动
setDocumentMode(enabled:bool) -> None                                                                   # 设置Tab标签是否为文档模式
documentMode() -> bool                                                                                  # 获取Tab标签是否为文档模式

# 槽函数
cascadeSubWindows() -> None                                                                             # 层叠显示子窗口
tileSubWindows() -> None                                                                                # 平铺显示子窗口
closeActiveSubWindow() -> None                                                                          # 关闭正在活动状态的子窗口
closeAllSubWindows() -> None                                                                            # 关闭全部子窗口
activatePreviousSubWindow() -> None                                                                     # 激活上一个子窗口
activateNextSubWindow() -> None                                                                         # 激活下一个子窗口
setActiveSubWindow(window:QMdiSubWindow) -> None                                                        # 设置活跃的窗口

QMidArea 类常用的信号及其说明如下:

subWindowActivated(arg__1:QMdiSubWindow)   # 当子窗口活跃时发射信号

QMdiSubWindow 类常用的方法及其说明如下:

# 实例方法
setWidget(widget:QWidget) -> None                                       # 设置子窗口的控件
widget() -> QWidget                                                     # 获取子窗口的控件
isShaded() -> bool                                                      # 获取子窗口是否处于只显示标题栏状态
mdiArea() -> QMdiArea                                                   # 返回子窗口所在的多文档区域
setSystemMenu(systemMenu:QMenu) -> None                                 # 设置系统菜单
systemMenu() -> QMenu                                                   # 获取系统菜单
setKeyboardPageStep(step:int) -> None                                   # 设置用键盘的Page键控制子窗口移动或缩放时的步长
keyboardPageStep() -> int                                               # 获取用键盘的Page键控制子窗口移动或缩放时的步长
setKeyboardSingleStep(step:int) -> None                                 # 设置用键盘的方向键控制子窗口移动或缩放时的步长
keyboardSingleStep() -> int                                             # 获取用键盘的方向键控制子窗口移动或缩放时的步长
setOption(option:QMdiSubWindow.SubWindowOption, on:bool=true) -> None   # 设置选项

# 槽函数
showShaded() -> None                                                    # 只显示标题
showSystemMenu() -> None                                                # 在标题栏的系统菜单图标下显示系统菜单

QMdiSubWindow 类常用的信号及其说明如下:

aboutToActivate()                                                       # 当子窗口活跃时发射信号
windowStateChanged(oldState:Qt.WindowState, newState:Qt.WindowState)    # 窗口状态改变时发射信号
import sys

from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWidgets import QMdiArea, QMdiSubWindow
from PySide6.QtWidgets import QLabel
from PySide6.QtWidgets import QMenuBar, QMenu
from PySide6.QtGui import QAction

class MyWidget(QMainWindow):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建MDI窗口
        self.mdiArea = QMdiArea(self)
        self.mdiArea.setGeometry(0, 0, 700, 500)

        # 3.创建菜单栏
        self.menuBar = QMenuBar(self)
        self.setMenuBar(self.menuBar)

        # 4.设置菜单
        self.menu = QMenu("子窗体操作", self)
        self.menuBar.addMenu(self.menu)

        # 5.设置菜单项
        self.new_action = QAction("新建", self.menu)
        self.tile_action = QAction("平铺显示", self.menu)
        self.cascade_action = QAction("级联显示", self.menu)
        self.menu.addActions([self.new_action, self.tile_action, self.cascade_action])

        # 6.为菜单关联信号
        self.menuBar.triggered[QAction].connect(self.action)

        # 7.记录子窗口的个数
        self.count = 0

    def action(self, msg):
        if msg.text() == "新建":
            # 创建子窗口对象
            sub = QMdiSubWindow()
            self.count += 1

            # 设置子窗口的标题
            sub.setWindowTitle(f"子窗口{self.count}")

            # 在子窗口中添加一个标签,并设置文本
            label = QLabel(f"这是第{self.count}个子窗口")
            sub.setWidget(label)
            self.mdiArea.addSubWindow(sub)
            sub.show()
        elif msg.text() == "平铺显示":
            self.mdiArea.tileSubWindows()
        elif msg.text() == "级联显示":
            self.mdiArea.cascadeSubWindows()

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615160715904

3.对话框应用

对话框窗口是一个用来完成简单任务或者和用户进行临时交互的顶层窗口,通常用于输入信息、确认信息或者提示信息。QDialog 类是所有对话框窗口类的基类。

对话框控件

​ 按照运行时是否可以和其他窗口进行交互操作,对话框分为模式(或模态)对话框和非模式对话框。对于带有模式的对话框,只有在关闭该对话框的情况下才可以对其他窗口进行操作;而对于非模式对话框,在没有关闭对话框的情况下,既可以对该对话框进行操作,也可以对其他窗口进行操作。

对话框在操作系统的管理器中没有独立的任务栏,而是共享父窗口的任务栏,无论对话框是否处于活跃状态,对话框都将位于父窗口之上,除非关闭或隐藏对话框。

QDialog 是从 QWidget 类继承而来的,用 QDialog 类创建一般对话框实例的方法如下:

QDialog(parent:QWidget=None, f:Qt.WindowFlags=Default(Qt.WindowFlags))

其中 parentQDialog 对话框的 父窗口Qt.WindowFlags 的取值参考 QWidget 窗口部分。通常将 QDialog 对话框作为顶层窗口使用,在主程序界面中进行调用。

QDialog 类的常用方法如下:

open() -> None                              # 以模式方法显示对话框
exec() -> int                               # 以模式方法显示对话框,并返回对话框的值
accept() -> None                            # 隐藏对话框,并将返回值设置成QDialog.Accepted,同时发送accepted()和finished(int)信号
done(arg__1:int) -> None                    # 隐藏对话框,并将返回值设置成arg__1,同时发送finished(int)信号
reject() -> None                            # 隐藏对话框,并将返回值设置成QDialog.Rejected,同时发送rejected()和finished(int)信号
setModal(modal:bool) -> None                # 设置对话框为模式对话框
setResult(result:int) -> None               # 设置对话框的返回值
result() -> int                             # 返回对话框的返回值
setSizeGripEnabled(arg__1:bool) -> None     # 设置对话框的右下角是否有三角形
isSizeGripEnabled() -> bool                 # 返回对话框的右下角是否有三角形
setVisible(visible:bool) -> None            # 设置对话框是否可见

对话框的模式特性可以用 setModal(bool)setWindowModality(Qt.WindowModality) 方法设置,其中枚举参数 Qt.WindowModality 可以取值如下:

Qt.WindowModality.NonModal           # 非模式,可以和程序的其他窗口进行交互操作
Qt.WindowModality.WindowModal        # 窗口模式,在未关闭当前对话框时,将阻止该窗口与父窗口的交互操作
Qt.WindowModality.ApplicationModal   # 应用程序模式,在未关闭当前对话框时,将阻止与任何其他窗口的交互操作

显示对话框的方法有 show()、open() 和 exec() 三种。如果对话框已经有模式特性,则用 show() 方法显示的对话框具有模式特性,如果对话框没有模式特性,则用 show() 方法显示的对话框没有模式特性;无论对话框是否有模式特性,用 open() 或 exec() 方法显示的对话框都是模式对话框,其中用 open() 方法显示的对话框默认是窗口模式,用 exec() 方法显示的对话框默认是应用程序模式。当程序执行到 show() 或 open() 方法时,显示对话框后,会继续执行后续的代码,而用 exec() 方法显示对话框时,需关闭对话框后才执行 exec() 语句的后续代码。show()、open()和exec()三种显示对话框的方法不会改变对话框的模式属性的值。

这里所说的对话框的返回值不是在对话框的控件中输入的值,而是指对话框被隐藏或删除时返回的一个整数,用这个整数表示用户对对话框的操作。

通常对话框上有 “确定” 按钮(或 OK 按钮)、“应用” 按钮(或 Apply 按钮)和 “取消” 按钮(或 Cancel 按钮)。单击 “确定” 按钮表示接受和使用对话框中输入的值,单击 “取消” 按钮表示放弃或不使用对话框中输入的值。为了区分客户选择了哪个按钮,可以为对话框设个返回值,例如用 1 表示单击 “确定” 按钮,用 0 表示单击 “放弃” 按钮,用 2 表示单击 “应用” 按钮。

QDialog 定义了两个枚举类型常量 QDialog.Accepted 和 QDialog.Rejected,这两个常量的值分别是 1 和 0。可以用 setResult(result:int) 方法为对话框设置一个返回值,用 result() 方法获取对话框的返回值,例如单击 “确认” 按钮时,隐藏对话框,并把对话框的返回值设置成 setResult(QDialog.Accepted);单击 “取消” 按钮时,隐藏对话框,并把对话框的返回值设置成 setResult(QDialog.Rejected)。

QDialog的 accept() 方法可以隐藏对话框,并把对话框的返回值设置成 QDialog.Accepted;reject() 方法会隐藏对话框,并把对话框的返回值设置成 QDialog.Rejected;用 done(arg_1) 方法会隐藏对话框,并把对话框的返回值设置成 arg_1。其实 accept() 方法调用的就是 done(QDialog.Accepted) 方法,reject() 方法调用的就是 done(QDialog.Rejected) 方法。如果对话框是用 exec() 方法显示的,则 exec() 方法会返回对话框的值,而 show() 和 open() 方法不会返回对话框的值。

QDialog 类的常用信号如下:

accepted()                  # 执行accept()和done(int)方法时发射信号
finished(result:int)        # 执行accept()、reject()和done(int)方法时发射信号
rejected()                  # 执行reject()和done(int)方法时发射信号
import sys

from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWidgets import QDialog
from PySide6.QtWidgets import QLineEdit, QPushButton
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QFormLayout

class MyWidget(QMainWindow):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建对话框控件
        dialog = QDialog(self)

        # 3.创建对话框的整体布局
        layout_V = QVBoxLayout(dialog)

        # 4.创建表单布局,并添加控件
        form = QFormLayout()
        layout_V.addLayout(form)

        line_name = QLineEdit()
        line_name.setPlaceholderText("请输入姓名")
        form.addRow("姓名:", line_name)

        line_gender = QLineEdit()
        line_gender.setPlaceholderText("请输入性别")
        form.addRow("性别:", line_gender)

        line_age = QLineEdit()
        line_age.setPlaceholderText("请输入年龄")
        form.addRow("年龄:", line_age)

        # 5.创建水平布局,添加按钮控件
        layout_H = QHBoxLayout()
        layout_V.addLayout(layout_H)

        button_apply = QPushButton("应用")
        layout_H.addWidget(button_apply)

        button_ok = QPushButton("确定")
        layout_H.addWidget(button_ok)

        button_cancel = QPushButton("取消")
        layout_H.addWidget(button_cancel)

        # 6.打开对话框
        dialog.open()

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615161005952

3.1 信息对话框

在 PySide6 中,使用 QMessageBox 类表示对话框,PySide 中内置了 5 种不同类型的对话框,分别是消息对话框、问答对话框、警告对话框、错误对话框和关于对话框。它们的主要区别在于弹出的对话框的图标不同。

信息对话框 QMessageBox 用于向用户提供一些信息,或者询问用户如何进行下一步操作。信息对话框由 文本(text、informativeText、detailedText)、图标按钮 3 部分构成,因此在建立信息对话框时,主要设置这 3 部分的参数。

用 QMessageBox 类创建信息对话框的方法如下:

QMessageBox(parent:QWidget=None)
QMessageBox(icon:QMessageBox.Icon, title:str, buttons:QMessageBox.StandardButtons=QMessageBox.StandardButton.NoButton, parent:QWidget=None, flags:Qt.WindowFlags=Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)

其中 icon对话框中的图标title对话框的标题text对话框中显示的文本buttons 设置 对话框中的按钮,;flags 设置 窗口的类型,使用默认值即可。

用 QMessageBox 类常用方法如下:

# 实例方法
setText(text:str) -> None                                                   # 设置信息对话框的文本
text() -> str                                                               # 获取信息对话框的文本
setInformativeText(text:str) -> None                                        # 设置对话框的信息文本
informativeText() -> str                                                    # 获取对话框的信息文本
setDetailedText(text:str) -> None                                           # 设置对话框的详细文本
detailedText() -> str                                                       # 获取对话框的详细文本
setTextFormat(format:Qt.TextFormat) -> None                                 # 设置文本格式

setIcon(icon:QMessageBox.Icon) -> None                                      # 设置对话框的标准图标
setIconPixmap(pixmap:QPixmap) -> None                                       # 设置对话框的自定义图标
icon() -> QIcon                                                             # 获取对话框的标准图标
iconPixmap() -> QPixmap                                                     # 获取对话框的自定义图标

setCheckBox(cb:QCheckBox) -> None                                           # 信息对话框中添加QCheckBox控件
checkBox() -> QCheckBox                                                     # 获取信息对话框中的QCheckBox控件

addButton(button:QMessBox.StandardButton) -> QPushButton                    # 对话框中添加标准按钮
addButton(text:str, role:QMessageBox.ButtonRole) -> QPushButton             # 对话框中添加新建按钮,并返回新建按钮
addButton(button:QAbstractButton, role:QMessageBox.ButtonRole) -> None      # 对话框中添加按钮,并设置按钮的作用
button(which:QMessageBox.StandardButton) -> QAbstractButton                 # 获取对话框中的标准按钮
buttons() -> List[QAbstractButton]                                          # 获取对话框中按钮列表
buttonText(button:int) -> str                                               # 获取按钮上的文本
buttonRole(button:QAbstractButton) -> QMessageBox.ButtonRole                # 获取按钮的角色
removeButton(button:QAbstractButton) -> None                                # 删除对话框中的按钮
setDefaultButton(button:QPushButton) -> None                                # 设置默认按钮
setDefaultButton(button:QMessageBox.StandardButton) -> None                 # 将某一标准按钮设置为默认按钮
defaultButton() -> QPushButton                                              # 获取默认按钮

setEscapeButton(button:QAbstractButton) -> None                             # 设置Esc键关闭对话框的按钮
setEscapeButton(button:QMessageBox.StandardButton) -> None                  # 将某一标准按钮设置为Esc键关闭对话框的按钮
escapeButton() -> QAbstractButton                                           # 获取Esc键关闭对话框的按钮

clickedButton() -> QAbstractButton                                          # 获取用户点击的按钮

# 静态方法

# 用于快速构建信息对话框,除about()函数外,其它函数返回值是被单击的按钮或按钮的角色识别号

# 关于对话框
about(parent:QWidget, title:str, text:str) -> None

# 消息对话框
information(parent:QWidget, title:str, text:str, buttons:QMessageBox.StandardButton=QMessageBox.StandardButton.Ok, defaultButton:QMessageBox.StandardButton=QMessageBox.StandardButton.NoButton) -> QMessageBox.StandardButton

# 问答对话框
question(parent:QWidget, title:str, text:str, buttons:QMessageBox.StandardButton=QMessageBox.StandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No), defaultButton:QMessageBox.StandardButton=QMessageBox.StandardButton.NoButton) -> QMessageBox.StandardButton

# 警告对话框
warning(parent:QWidget, title:str, text:str, buttons:QMessageBox.StandardButton=QMessageBox.StandardButton.Ok, defaultButton:QMessageBox.StandardButton=QMessageBox.StandardButton.NoButton) -> QMessageBox.StandardButton

# 错误对话框
critical(parent:QWidget, title:str, text:str, buttons:QMessageBox.StandardButton=QMessageBox.StandardButton.Ok, defaultButton:QMessageBox.StandardButton=QMessageBox.StandardButton.NoButton) -> QMessageBox.StandardButton

信息对话框的创建方法有两种:一种是先创建信息对话框的实例对象,然后往实例对象中添加文本、图标和按钮,最后用 show()、open() 或 exec() 方法把信息对话框显示出来;另一种是用 QMessageBox 提供的静态函数来创建信息对话框。

信息对话框上显示的文本分为 text、informativeText 和 detailedText,如果设置了 detailedText,会出现 “Show Details...” 按钮,这 3 个文本分别用 setText(str)setInformativeText(str)setDetailedText(str) 方法设置。detailedText 文本只能以 纯文本 形式显示,textinformativeText 文本可以用 纯文本富文本 的形式显示。用 setTextFormat(Qt.TextFormat) 方法设置是用纯文本还是富文本显示,其中参数 Qt.TextFormat 可以取值如下:

Qt.TextFormat.PlainText       # 纯文本
Qt.TextFormat.RichText        # 富文本
Qt.TextFormat.AutoText        # 由系统决定
Qt.TextFormat.MarkdownText    # Markdown文本

信息对话框的图标可以由用户自己定义,也可以使用 QMessageBox 提供的标准图标。自定义图标需要用 setIconPixmap(QPixmap) 方法定义,标准图标用 setIcon(QMessageBox.Icon) 方法设置,其中 QMessageBox.Icon 可以取值如下:

QMessageBox.Icon.NoIcon
QMessageBox.Icon.Question
QMessageBox.Icon.Information
QMessageBox.Icon.Warning
QMessageBox.Icon.Critical

这几种图标的样式如下所示:

标准图标样式

​ 信息对话框的按钮分为自定义按钮和标准按钮,不论哪种按钮都要赋予角色,按钮的角色用来说明按钮的作用。按钮的角色由枚举类型 QMessageBox.ButtonRole 确定,QMessageBox.ButtonRole 可以取的值下所示:

QMessageBox.ButtonRole.InvalidRole          # 不起作用的按钮
QMessageBox.ButtonRole.AcceptRole           # 接受对话框内的信息,例如OK按钮
QMessageBox.ButtonRole.RejectRole           # 拒绝对话框内的信息,例如Cancel按钮
QMessageBox.ButtonRole.DestructiveRole      # 重构对话框
QMessageBox.ButtonRole.ActionRole           # 使对话框内的控件产生变化
QMessageBox.ButtonRole.HelpRole             # 显示帮助的按钮
QMessageBox.ButtonRole.YesRole              # Yes按钮
QMessageBox.ButtonRole.NoRole               # No按钮
QMessageBox.ButtonRole.ResetRole            # 重置按钮,恢复对话框的默认值
QMessageBox.ButtonRole.ApplyRole            # 确认当前的设置,例如Apply按钮

在信息对话框中添加的按钮可以是自定义的按钮,也可以是标准按钮。用 addButton(button:QAbstractButton,role:QMessageBox.ButtonRole) 方法或 addButton(text:str,QMessageBox.ButtonRole) 方法自定义按钮,前者将一个已经存在的按钮加入到对话框中,后者创建名称是 text 的按钮,同时返回该按钮;用 addButton(QMessageBox.StandardButton) 方法可以添加标准按钮,并返回按钮,添加按钮后可以为按钮设置槽函数。标准按钮已经有角色,参数 QMessageBox.StandardButton 用于设置标准按钮,标准按钮与其对应的角色如下所示。

QMessageBox.StandardButton.Ok                   # AcceptRole
QMessageBox.StandardButton.Open                 # AcceptRole
QMessageBox.StandardButton.Save                 # AcceptRole
QMessageBox.StandardButton.SaveAll              # AcceptRole
QMessageBox.StandardButton.Retry                # AcceptRole
QMessageBox.StandardButton.Ignore               # AcceptRole

QMessageBox.StandardButton.Cancel               # RejectRole
QMessageBox.StandardButton.Close                # RejectRole
QMessageBox.StandardButton.Abort                # RejectRole

QMessageBox.StandardButton.Discard              # DestructiveRole

QMessageBox.StandardButton.Apply                # ApplyRole

QMessageBox.StandardButton.Reset                # ResetRole
QMessageBox.StandardButton.RestoreDefaults      # ResetRole

QMessageBox.StandardButton.Help                 # HelpRole

QMessageBox.StandardButton.Yes                  # YesRole
QMessageBox.StandardButton.YesToAll             # YesRole

QMessageBox.StandardButton.No                   # NoRole
QMessageBox.StandardButton.NoToAll              # NoRole

默认按钮是按 Enter 键时执行动作的按钮,默认按钮用 setDefaultButton(QPushButton) 方法或 setDefaultButton(QMessageBox.StandardButton) 方法设置,若未指定,则根据按钮的角色来确定默认按钮。Esc 按钮是按 Esc 键时执行动作的按钮,Esc 按钮用 setEscapeButton(QAbstractButton) 方法或 setEscapeButton(QMessageBox.StandardButton) 方法设置。如果没有设置 Esc 按钮,则将角色是 CancelRole 的按钮作为 Esc 按钮;如果只有一个按钮,则将这个按钮作为 Esc 按钮。

对话框上被单击的按钮可以用 clickedButton() 方法获得,也可通过信号 buttonClicked(QAbstractButton) 获得,单击按钮后发送该信号,并传递被单击的按钮。

我们可以用静态函数快速构建信息对话框,这些静态函数的格式如下。除 about() 函数外,其他函数返回值是被单击的按钮或按钮的角色识别号。

PySide 中内置的 5 种不同类型的对话框在使用时是类似的,这里以消息对话框为例。

information(parent:QWidget, title:str, text:str, buttons:QMessageBox.StandardButton=QMessageBox.StandardButton.Ok, defaultButton:QMessageBox.StandardButton=QMessageBox.StandardButton.NoButton) -> Union[int, QMessageBox.StandardButton]
  • parent:表示该窗口所属的窗口;
  • title:字符串,表示对话框的标题;
  • text:字符串,表示对话框中的提示内容;
  • buttons:对话框上要添加的按钮,多个按钮之间用 "|" 来连接。没有指定该值是,默认为 OK 按钮;
  • defaultButton:默认选中的按钮,没有指定该值时,默认为第一个按钮;

用 QMessageBox 类常用信号如下:

buttonClicked(button:QAbstractButton)     # 单击任意按钮时发射信号,参数是被单击的按钮

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QMessageBox
from PySide6.QtWidgets import QHBoxLayout, QPushButton

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建布局
        layout = QHBoxLayout(self)

        # 3.消息对话框
        button_1 = QPushButton("消息对话框")
        layout.addWidget(button_1)
        button_1.clicked.connect(self.info)

        # 4.问答对话框
        button_2 = QPushButton("问答对话框")
        layout.addWidget(button_2)
        button_2.clicked.connect(self.quesstion)

        # 5.警告对话框
        button_3 = QPushButton("警告对话框")
        layout.addWidget(button_3)
        button_3.clicked.connect(self.warning)

        # 6.错误对话框
        button_4 = QPushButton("错误对话框")
        layout.addWidget(button_4)
        button_4.clicked.connect(self.critical)

        # 7.关于对话框
        button_5 = QPushButton("关于对话框")
        layout.addWidget(button_5)
        button_5.clicked.connect(self.about)

    def info(self):
        select = QMessageBox.information(self, "消息", "这是一个消息对话框", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
        if select == QMessageBox.StandardButton.Yes:
            QMessageBox.information(self, "提醒", "你点击的确定按钮")
        elif select == QMessageBox.StandardButton.No:
            QMessageBox.information(self, "提醒", "你点击的取消按钮")

    def quesstion(self):
        QMessageBox.question(self, "问答", "这是一个问答对话框", QMessageBox.StandardButton.Ok)

    def warning(self):
        QMessageBox.warning(self, "警告", "这是一个警告对话框", QMessageBox.StandardButton.Ok)

    def critical(self):
        QMessageBox.critical(self, "错误", "这是一个错误对话框", QMessageBox.StandardButton.Ok)

    def about(self):
        QMessageBox.about(self, "关于", "这是一个关于对话框")

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

QMessageBox.about() 关于对话框不能指定按钮;

image-20240615161356364

3.2 错误对话框

错误信息对话框 QErrorMessage 用于将程序运行时出现的错误内容显示出来。错误信息对话框由一个显示信息的文本框和一个勾选按钮构成。

使用 QErrorMessage 类创建错误信息对话框实例的方法如下:

QErrorMessage(parent:QWidget=None)

错误信息对话框只有两个重载型槽函数 showMessage(message:str)showMessage(message:str,type:str) ,执行该方法后立即显示对话框,其中 message 参数是 错误信息type 参数指定 错误信息的类型。如果用户在对话框中不勾选 “Show this message again”,则遇到相同的错误信息或相同类型的错误信息时,将不再弹出对话框。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QErrorMessage

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建错误对话框
        errorMessage = QErrorMessage(self)

        # 3.错误对话框的显示信息
        errorMessage.showMessage("程序突然崩溃", "未知错误")

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615161441357

3.3 文件对话框

文件对话框 QFileDialog 用于打开或保存文件时获取文件路径和文件名。在文件对话框中可以根据文件类型对文件进行过滤,只显示具有某些扩展名的文件。文件对话框的界面分为两种,一种是 PySide6 提供的界面,另一种是本机操作系统提供的界面,可以通过文件对话框的 setOption(QFileDialog.DontUseNativeDialog,bool) 方法设置显示的是哪种界面。对话框上的标签和按钮名称都可以通过对话框的属性进行修改。

用 QFileDialog 类创建文件对话框实例的方法如下所示:

QFileDialog(parent:QWidget=None, f:Qt.WindowFlags)
QFileDialog(parent:QWidget=None, caption:str='', directory:str='', filter:str='')

其中,caption 用于设置 对话框的标题directory 设置 默认路径filter 设置 过滤方式,只显示具有某种扩展名的文件。

用 QFileDialog 类常用方法如下:

# 实例方法
setAcceptMode(mode:QFileDialog.AcceptMode) -> None                  # 设置是打开还是保存对话框
setDefaultSuffix(suffix:str) -> None                                # 设置默认的后缀名
defaultSuffix() -> str:                                             # 返回默认的后缀名

saveState() -> QByteArray:                                          # 保存对话框状态到QByteArray
restoreState(state:QByteArray) -> bool                              # 从QByteArray恢复对话框状态

setNameFilter(filter:str) -> None                                   # 根据文件的扩展名设置过滤器
setNameFilters(filters:Sequence[str]) -> None                       # 设置过滤器列表
nameFilters() -> List[str]:                                         # 获取过滤器列表

selectFile(filename:str) -> None                                    # 设置初始选中的文件,可当作默认文件
selectedFiles() -> List[str]:                                       # 获取被选中文件的绝对文件路径列表,如果没有选择文件,则返回值只有路径
selectNameFilter(filter:str) -> None                                # 设置对话框初始名称过滤器
selectedNameFilter() -> str:                                        # 获取被选中的名称过滤器
selectUrl(url:Union[QUrl, str]) -> None                             # 设置对话框初始选中的文件
selectedUrls() -> List[QUrl]:                                       # 获取被选中的文件的绝对文件路径列表,如果没有选择文件,则返回值只有路径

directory() -> QDir:                                                # 获取对话框的当前路径
directoryUrl() -> QUrl:                                             # 获取对话框的当前路径
setDirectory(directory:Union[QDir, str]) -> None                    # 设置对话框的初始路径

setFileMode(mode:QFileDialog.FileMode) -> None                      # 设置文件模式,对话框是用于选择路径、单选个文件还是多个文件

setHistory(paths:Sequence[str]) -> None                             # 设置对话框的浏览记录
history() -> List[str]                                              # 获取对话框的浏览记录

setLabelText(label:QFileDialog.DialogLabel, text:str) -> None       # 设置对话框上各标签或按钮的名称
labelText(label:QFileDialog.DialogLabel) -> str:                    # 获取对话框上标签或按钮的名称

setOption(option:QFileDialog.Option, on:bool=true) -> None          # 设置对话框选项
testOption(option:QFileDialog.Option) -> bool                       # 测试对话框选项

setViewMode(mode:QFileDialog.ViewMode) -> None                      # 设置视图模式,对话框是显示文件列表还是显示图标

# 静态方法

# 打开文件对话框,获取路径或文件及过滤器
# 其中,caption是对话框的标题,dir是初始路径,fiilter是对话框中可选的过滤器,selectedFilter是对话框中已经选中的过滤器
# 除了getExistingDirectory()和getExistingDirectoryUrl()外,其它方法都是返回元组,元组的第一个参数是文件名或文件名列表,第二个参数是选中的过滤器
getExistingDirectory(parent:QWidget=None, caption:str='', dir:str='', options:QFileDialog.Option=QFileDialog.Option.ShowDirsOnly) -> str

getExistingDirectoryUrl(parent:QWidget=None, caption:str='', dir:Union[QDir, str]=Default(QUrl), options:QFileDialog.Option=QFileDialog.Option.ShowDirsOnly) -> QUrl

getOpenFileName(parent:QWidget=None, caption:str='', dir:str='', filter:str='', selectedFilter:str='', options:QFileDialog.Options=QFileDialog.Options()) -> Tuple

getOpenFileNames(parent:QWidget=None, caption:str='', dir:str='', filter:str='', selectedFilter:str='', options:QFileDialog.Options=QFileDialog.Options()) -> Tuple

getOpenFileUrl(parent:QWidget=None, caption:str='', dir:Union[QDir, str]='', filter:str=Default(QUrl), selectedFilter:str='', options:QFileDialog.Options=QFileDialog.Options()) -> Tuple

getOpenFileUrls((parent:QWidget=None, caption:str='', dir:Union[QDir, str]='', filter:str=Default(QUrl), selectedFilter:str='', options:QFileDialog.Options=QFileDialog.Options()) -> Tuple

getSaveFileName(parent:QWidget=None, caption:str='', dir:str='', filter:str='', selectedFilter:str='', options:QFileDialog.Option=QFileDialog.Option.ShowDirsOnly) -> Tuple

getSaveFileUrl((parent:QWidget=None, caption:str='', dir:Union[QDir, str]='', filter:str=Default(QUrl), selectedFilter:str='', options:QFileDialog.Options=QFileDialog.Options()) -> Tuple

文件对话框也用 show()、open() 和 exec() 方法显示,最简便的方法是用 QFileDialog 提供的静态方法来打开文件对话框获取文件路径和文件名。

setFileMode(QFileDialog.FileMode) 方法可以设置对话框的文件模式,文件模式是指对话框显示的内容或允许选择的内容,其中参数 QFileDialog.FileMode 可以取值如下:

QFileDialog.FileMode.AnyFile        # 任意文件和文件夹,也可以输入不存在的文件或文件夹
QFileDialog.FileMode.ExistingFile   # 只能选择一个存在的文件,不能是文件夹或不存在的文件
QFileDialog.FileMode.Directory      # 只能选择文件夹
QFileDialog.FileMode.ExistingFiles  # 可以选择多个存在的文件

setOption(QFileDialog.Option,on=True) 方法设置文件对话框的外观选项,需在显示对话框之前设置,参数 QFileDialog.Option可以取值如下:

QFileDialog.Option.ShowDirsOnly                   # 只显示文件夹
QFileDialog.Option.DontResolveSymlinks            # 不解析链接
QFileDialog.Option.DontConfirmOverwrite           # 存盘时若选择了存在的文件,不提示覆盖信息
QFileDialog.Option.DontUseNativeDialog            # 不使用操作系统的对话框
QFileDialog.Option.ReadOnly                       # 只读
QFileDialog.Option.HideNameFilterDetails          # 隐藏名称过滤器的详细信息
QFileDialog.Option.DontUseCustomDirectoryIcons    # 不使用用户的目录图标,有些系统允许使用)。

setAcceptMode(QFileDialog.AcceptMode) 方法设置文件对话框是打开对话框还是保存对话框,参数 QFileDialog.AcceptMode可取值如下:

QFileDialog.AcceptMode.AcceptOpen    # 设置文件对话框为打开模式,这是默认值
QFileDialog.AcceptMode.AcceptSave    # 设置文件对话框为保存模式

setViewMode(QFileDialog.ViewMode) 方法设置对话框的视图模式,参数 QFileDialog.ViewMode 可取值如下:

QFileDialog.ViewMode.Detail    # 详细显示
QFileDialog.ViewMode.List      # 列表显示,只显示图标和名称

对话框上的标签和按钮的文字可以用 setLabelText(QFileDialog.DialogLabel,str) 方法重新设置,其中参数 QFileDialog.DialogLabel 可以取值如下:

QFileDialog.DialogLabel.LookIn
QFileDialog.DialogLabel.FileName
QFileDialog.DialogLabel.FileType
QFileDialog.DialogLabel.Accept
QFileDialog.DialogLabel.Reject

设置过滤器 filter。过滤器的作用是在文件对话框中只显示某些类型的文件,例如通过方法 setNameFilter("Picture(*.png*.bmp*.jpeg*.jpg") 设置过滤器后,对话框只显示扩展名为 png、bmp、jpeg 和 jpg的文件。创建过滤器时,过滤器之间用空格隔开,如果有括号,则用括号中的内容作为过滤器,多个过滤器用两个分号 ;;隔开,例如 setNameFilter("Picture(*.png*.bmp);;text(*.txt)")。用 setNameFilter(str) 方法或 setNameFilters(Sequence[str]) 方法设置对话框中的过滤器。

用 QFileDialog 类常用信号如下:

currentChanged(path:str)                # 在对话框中所选择的文件或路径发生改变时发射信号,参数是当前选择的文件或路径
currentUrlChanged(url:QUrl)             # 在对话框中所选择的文件或路径发生改变时发射信号,参数是当前选择的文件或路径的QUrl对象
directoryEntered(directory:str)         # 进入新路径时发射信号,参数是新路径的字符串
directoryUrlEntered(directory:QUrl)     # 进入新路径时发射信号,参数是新路径的QUrl对象
fileSelected(file:str)                  # 单击open或save按钮后发射信号,参数是选中的文件
filesSelected(files:List[str])          # 单击open或save按钮后发射信号,参数是选中的文件列表
urlSelected(url:QUrl)                   # 单击open或save按钮后发射信号,参数是选中的文件的QUrl对象
urlsSelected(urls:List[QUrl])           # 单击open或save按钮后发射信号,参数是选中的文件的QUrl对象列表
filterSelected(filter:str)              # 选择新的过滤器后发射信号,参数是新的过滤器

import sys

from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWidgets import QFileDialog
from PySide6.QtWidgets import QPushButton, QListWidget

class MyWidget(QMainWindow):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建一个按钮控件
        button = QPushButton("选择文件", self)
        button.setGeometry(0, 0, 100, 30)

        # 3.创建一个列表控件
        self.listWidget = QListWidget(self)
        self.listWidget.setGeometry(0, 50, 500, 300)

        # 4.为按钮的clicked信号绑定槽函数
        button.clicked.connect(self.bind_list)

    def bind_list(self):
        # 1.创建文件对话框
        fileDialog = QFileDialog()

        # 2.设置多选
        fileDialog.setFileMode(QFileDialog.FileMode.ExistingFiles)

        # 4.设置初始磁盘
        fileDialog.setDirectory("E:\\")

        # 5.设置文件过滤器
        fileDialog.setNameFilter("图片文件(*.jpg *.png);;视频文件(*.mp4 *.ts *.avi)")

        # 6.判断是否选择了文件
        if fileDialog.exec():
            # 向列表控件中添加项
            self.listWidget.addItems(fileDialog.selectedFiles())

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615184352364

3.4 输入对话框

输入对话框 QInputDialog 用于输入简单内容或选择内容,分为整数输入框、浮点数输入框、文本输入框、多行文本输入框和下拉列表输入框 5 种。输入对话框由一个标签、一个输入控件和两个按钮构成。如果是整数输入框,输入控件是 QSpinBox;如果是浮点数输入框,输入控件是 QDoubleSpinBox;如果是单行文本输入框,输入控件是 QLineEdit;如果是多行文本输入框,输入控件是 QPlainTextEdit;如果是下拉列表输入框,输入控件是 QComboBox 或 QListView。输入框的类型用 setInputMode(QInputDialog.InputMode) 方法设置。

使用 QInputDialog 类创建输入对话框实例的方法如下所示:

QInputDialog(parent:QWidget=None, flags:Qt.WindowFlags=Default(Qt.WindowFlags))

用 QInputDialog 类常用方法如下:

# 实例方法
setInputMode(mode:QInputDialog.Mode) -> None                    # 设置输入对话框的类型
setOption(option:QInputDialog.Option, on:bool=true) -> None     # 设置输入对话框的参数
testOption(option:QInputDialog.Option) -> bool                  # 测试输入对话框的参数
setLabelText(text:str) -> None                                  # 设置对话款中标签的名称给
setOkButtonText(text:str) -> None                               # 设置对话框中的确定按钮的名称
setCancelButtonText(text:str) -> None                           # 设置对话框中的取消按钮的名称

setIntValue(value:int) -> None                                  # 设置对话框中的整数输入框的值
intValue() -> int                                               # 获取对话框中的整数输入框的值
setIntMinimum(min:int) -> None                                  # 设置对话框中的整数输入框的最小值
setIntMaximum(max:int) -> None                                  # 设置对话框中的整数输入框的最大值
setIntRange(min:int, max:int) -> None                           # 设置对话框中的整数输入框的范围
setIntStep(step:int) -> None                                    # 设置对话框中的整数输入框的步长

setDoubleValue(value:float) -> None                             # 设置对话框中的浮点数输入框的值
doubleValue() -> float                                          # 获取对话框中的浮点数输入框的值
setDoubleDecimals(decimals:int) -> None                         # 设置对话框中的浮点数输入框的小数位数
setDoubleMinimum(min:float) -> None                             # 设置对话框中的浮点数输入框的最小值
setDoubleMaximum(max:float) -> None                             # 设置对话框中的浮点数输入框的最大值
setDoubleRange(min:float, max:float) -> None                    # 设置对话框中的浮点数输入框的范围
setDoubleStep(step:float) -> None                               # 设置对话框中的浮点数输入框的步长

setTextValue(text:str) -> None                                  # 设置对话框中的文本输入框的值
textValue() -> str                                              # 获取对话框中的文本输入框的值
setTextEchoMode(mode:QLineEdit.EchoMode) -> None                # 设置对话框中的文本输入框的输入方式

setComboBoxItems(items:Sequence[str]) -> None                   # 设置对话框中的下拉列表框的选项
comboBoxItems() -> List[str]                                    # 获取对话框中的下拉列表框的选项
setComboBoxEditable(editable:bool) -> None                      # 设置对话框中的下拉列表框是否可编辑

# 静态方法
# 显示输入对话框,并返回输入的值和单击按钮的类型
# 其中,title是设置对话框的标题名称,label是对话框中标签的名称
# 在对话框中点击OK按钮后,返回值是元组(输入值, True)
# 在对话框中点击Cancel按钮后,返回值是元组(0, False)或("", False)
getInt(parent:QWidget, title:str, label:str, value:int=0, minValue:int=-2147483647, maxValue:int=2147483647, step:int=1, flags:Qt.WindowFlags=Qt.WindowFlags()) -> Tuple[int, bool]

getDouble(parent:QWidget, title:str, label:str, value:float=0, minValue:float=-2147483647, maxValue:float=2147483647, decimals:int=1, flags:Qt.WindowFlags=Qt.WindowFlags(), step:float=1) -> Tuple[float, bool]

getText(parent:QWidget, title:str, label:str, echo:QLineEdit.EchoMode=QLineEdit.Normal, text:str="", flags:Qt.WindowFlags=Qt.WindowFlags(), inputMethodHints=Qt.ImhNone) -> Tuple[str, bool]

getMultiLineText(parent:QWidget, title:str, label:str, text:str="", flags:Qt.WindowFlags=Qt.WindowFlags(), inputMethodHints=Qt.ImhNone) -> Tuple[str, bool]

getItem(parent:QWidget, title:str, label:str, items:Sequence[str], current:int=0, editable:bool=true, flags:Qt.WindowFlags=Qt.WindowFlags(), inputMethodHints=Qt.ImhNone)

输入对话框分为 整数输入对话框浮点数输入对话框文本输入对话框,其中 文本输入对话框 又分为 单行文本输入对话框多行文本输入对话框列表输入对话框,列表输入对话框 通常是从 QComboBox 控件或 QListWiew 控件中选择内容。用 setInputMode(QInputDialog.InputMode) 方法设置输入对话框的类型,其中参数 QInputDialog.InputMode可以取值如下:

QInputDialog.InputMode.IntInput          # 整数输入对话框
QInputDialog.InputMode.Double            # 浮点数输入对话框
InputQInputDialog.InputMode.TextInput    # 文本输入对话框

对于整数输入对话框,用 setIntValue(int) 方法可以设置对话框初次显示时的值,用 intValue() 方法可以获取单击 OK 按钮后的整数值。整数输入对话框中允许输入值的范围用 setIntMinimum(int)setIntMaximum(int) 方法设置,或者用 setIntRange(int,int) 方法设置。整数输入对话框的输入控件是 QSpinBox,单击右侧上下箭头可微调整数,微调整数值变化的步长用 setIntStep(int) 方法设置。

对于浮点数输入对话框,用 setDoubleValue(float) 方法可以设置对话框初次显示时的值,用 doubleValue() 方法可以获取单击 OK 按钮后的浮点数值。浮点数对话框中允许输入值的范围用 setDoubleMinimum(float)setDoubleMaximum(float) 方法设置,或者用 setDoubleRange(float,float) 方法设置。浮点数对话框的输入控件是 QDoubleSpinBox,单击右侧上下箭头可微调数据,浮点数值变化的步长用 setDoubleStep(float) 方法设置。

对于文本输入对话框,默认的输入控件是 QLineEdit,用 setOption(QInputDialog.UsePlainTextEditForTextInput) 方法将 QLineEdit 控件替换成 QPlainTextEdit,当用 setComboBoxItems(Sequence[str]) 方法设置控件的项(item)时,输入控件替换成 QComboBox,如果设置成 setOption(QInputDialog.UseListViewForComboBoxItems),则输入控件替换成 QListView。

对于文本输入对话框,用 setTextValue(str) 方法可以设置对话框中初始文本,用 textValue() 方法获取单击 OK 按钮后输入对话框的值。当输入控件是 QLineEdit 时,用 setTextEchoMode(QLineEdit.EchoMode) 方法可以设置 QLineEidt 控件的输入模式,其中 QLineEdit.EchoMode 可以取值如下:

QLineEdit.EchoMode.Norma                 # 正常显示
QLineEdit.EchoMode.NoEcho                # 输入文字时,没有任何显示
QLineEdit.EchoMode.Password              # 输入文字时,按照密码方式显示
QLineEdit.EchoMode.PasswordEchoOnEdit    # 失去焦点时,密码显示状态,编辑文本时,正常显示

我们可以使用 getText() 方法显示一个用于输入字符串的文本框控件。

text, flag = getText(parent, title, label, echo=QLineEdit.Normal, text="", flags=Qt.WindowFlags(), inputMethodHints=Qt.ImhNone)

参数说明:

  • parent:父窗口对象
  • title:QInputDialog 的标题
  • label:QInputDialog 内部显示的文本
  • echo:文本编辑框内容的显示方式
  • text:默认显示文本

该方法返回一个元组,元组的第一个元素 text 表示文本编辑框内的字符串,第二个元素 flag 表示是否正常返回。

我们可以使用 getItem() 方法显示一个 ComboBox 下拉列表控件,用户可以从中选择数据。

text, flag = getItem(parent, title, label, items, current=0, editable=true, flags=Qt.WindowFlags(), inputMethodHints=Qt.ImhNone)

参数说明:

  • parent:父窗口对象
  • title:QInputDialog 的标题
  • label:QInputDialog 内部显示的文本
  • items:QComboBox 控件的内容列表
  • current:默认显示 QComboBox 组件中的某一个索引的内容
  • editable:QComboBox 是否可以被编辑

该方法返回一个元组,元组的第一个元素 text 表示从 QComboBox 下拉列表中选择的内容,第二个元素 flag 表示是否正常返回。

我们可以使用 getInt() 方法显示一个用于输入整数的编辑框,显示的是 QSnipBox 控件。

value, flag = getInt(parent, title, label, value=0, minValue=-2147483647, maxValue=2147483647, step=1, flags=Qt.WindowFlags())

参数说明:

  • parent:父窗口对象
  • title:QInputDialog 的标题
  • label:QInputDialog 内部显示的文本
  • value:QSnipBox 控件的默认值
  • minValue:QSnipBox 控件的最小值
  • maxValue:QSnipBox 控件的最大值
  • step:QSnipBox 控件的单步值

该方法返回一个元组,元组的第一个元素 value 表示从 QSnipBox 控件中选择的整数值,第二个元素 flag 表示是否正常返回。

我们可以使用 getDouble() 方法显示一个用于输入浮点数的编辑框,显示的是 QDoubleSnipBox 控件。

value, flag = getDouble(parent, title, label, value=0, minValue=-2147483647, maxValue=2147483647, decimals=1, flags=Qt.WindowFlags(), step=1)

参数说明:

  • parent:父窗口对象
  • title:QInputDialog 的标题
  • label:QInputDialog 内部显示的文本
  • value:QDoubleSnipBox 控件的默认值
  • minValue:QDoubleSnipBox 控件的最小值
  • maxValue:QDoubleSnipBox 控件的最大值
  • decimals:QDoubleSnipBox 控件的单步值

该方法返回一个元组,元组的第一个元素 value 表示从 QDoubleSnipBox 控件中选择的小数值,第二个元素 flag 表示是否正常返回。

用 QInputDialog 类常用信号如下:

intValueChanged(value:int)              # 输入对话框的整数值改变时发射信号
intValueSelected(value:int)             # 单击OK按钮后发射信号
doubleValueChanged(value:float)         # 输入对话框的浮点数值改变时发射信号
doubleValueSelected(value:float)        # 单击OK按钮后发射信号
textValueChanged(text:str)              # 输入对话框的文本改变时发射信号
textValueSelected(text:str)             # 单击OK按钮后发射信号

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QInputDialog
from PySide6.QtWidgets import QGridLayout
from PySide6.QtWidgets import QLabel, QLineEdit

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        layout = QGridLayout(self)

        # 添加姓名标签
        name_label = QLabel("姓名")
        layout.addWidget(name_label, 0, 0)

        # 添加姓名文本框
        self.name_text = QLineEdit()
        self.name_text.setPlaceholderText("请输入姓名")
        layout.addWidget(self.name_text, 0, 1)
        self.name_text.textEdited.connect(self.get_name)

        # 添加性别标签
        gender_label = QLabel("性别")
        layout.addWidget(gender_label, 1, 0)

        # 添加性别文本框
        self.gender_text = QLineEdit()
        self.gender_text.setPlaceholderText("请输入性别")
        layout.addWidget(self.gender_text, 1, 1)
        self.gender_text.textEdited.connect(self.get_gender)

        # 添加年龄标签
        age_label = QLabel("年龄")
        layout.addWidget(age_label, 2, 0)

        # 添加年龄文本框
        self.age_text = QLineEdit()
        self.age_text.setPlaceholderText("请输入年龄")
        layout.addWidget(self.age_text, 2, 1)
        self.age_text.textEdited.connect(self.get_age)

        # 添加分数标签
        score_label = QLabel("分数")
        layout.addWidget(score_label, 3, 0)

        # 添加分数文本框
        self.score_text = QLineEdit()
        self.score_text.setPlaceholderText("请输分数")
        layout.addWidget(self.score_text, 3, 1)
        self.score_text.textEdited.connect(self.get_score)

    def get_name(self):
        name, flag = QInputDialog.getText(self, "姓名", "请输入姓名", QLineEdit.EchoMode.Normal, "小樱")
        if flag:
            self.name_text.setText(name)

    def get_gender(self):
        gender, flag = QInputDialog.getItem(self, "性别", "请输入选择性别", ("男", "女"), 1, False)
        if flag:
            self.gender_text.setText(gender)

    def get_age(self):
        age, flag = QInputDialog.getInt(self, "年龄", "请输入年龄", 0, 0, 100, 1)
        if flag:
            self.age_text.setText(str(age))

    def get_score(self):
        scrore, flag = QInputDialog.getDouble(self, "分数", "请输入分数", 0, 0, 100, 1)
        if flag:
            self.score_text.setText(str(scrore))

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615184703908

3.5 字体对话框

字体对话框 QFontDialog 用于选择字体,其界面是 PySide6 已经编辑好的,用户可以直接在对话框中选择与字体有关的选项。

用 QFontDialog 类创建标准字体对话框的方法如下,其中 QFont 用于初始化对话框。

QFontDialog(parent:QWidget=None)
QFontDialog(font:QFont, parent:QWidget=None)

QFontDialog 类表示字体对话框,用户可以从中选择字体的大小、样式、格式等信息。QFontDialog 类中常用的方法如下:

# 实例方法
selectedFont() -> QFont                                                   # 获取在对话框中单击OK按钮后,最终选中的字体
setCurrentFont(font:QFont) -> None                                        # 设置字体对话框中当前的字体,用于初始化字体对话框
currentFont() -> QFont                                                    # 获取字体对话框中当前的字体
setOption(option:QFontDialog.FontDialogOption, on:bool=true) -> None      # 设置对话框的选项
testOption(option:QFontDialog.FontDialogOption) -> bool                   # 测试对话框的选项

# 静态方法
# 用模式方式初始化对话框,获取字体
# 参数initial是初始化字体,title是对话框标题
# 返回值是元组,第一个是是否成功,第二个是字体
# 如在对话框中单击OK按钮,bool为True,单击Cancel按钮,bool为False
getFont(parent:QWidget=None) -> Tuple[bool, QFont]
getFont(initial:QFont, parent:QWidget=None, title:str="", options:QFontDialog.FontDialogOption=QFontDialog.FontDialogOptions()) -> Tuple[bool, QFont]

创建字体对话框的一种方法是先创建对话框实例对象,设置对话框的属性,然后用 show()、open() 或 exec() 方法显示对话框;另一种方法是直接用 getFont() 方法,getFont() 方法是静态方法,可直接使用 类名.getFont() 方法调用,也可用实例对象调用。

setOption(QFontDialog.FontDialogOption,on=True) 方法设置字体对话框的选项,其中QFontDialog.FontDialogOption 可以取值如下:

QFontDialog.FontDialogOption.NoButtons               # 不显示OK和Cancel按钮
QFontDialog.FontDialogOption.DontUseNativeDialog     # 在Mac机上不使用本机字体对话框,使用PySide6的字体对话框
QFontDialog.FontDialogOption.ScalableFonts           # 显示可缩放字体
QFontDialog.FontDialogOption.NonScalableFonts        # 显示不可缩放字体
QFontDialog.FontDialogOption.MonospacedFonts         # 显示等宽字体
QFontDialog.FontDialogOption.ProportionalFonts       # 显示比例字体

selectedFont() 方法可以获取在单击 OK 按钮后,最终选中的字体。在对话框中单击 OK 按钮时,同时也发送信号 fontSelected(QFont),其中参数 QFont 是最后选中的字体。

setCurrentFont(QFont) 方法可以设置对话框显示时,初始选中的字体。在对话框中选择不同的字体时,会发送 currentFontChanged(QFont) 信号,其中参数 QFont 是当前选中的字体。

QFontDialog 类中常用的信号如下:

currentFontChanged(font:QFont)          # 在对话框中选择字体是发射信号
fontSelected(font:QFont)                # 在对话框中单击OK按钮是发射信号
import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QFontDialog
from PySide6.QtWidgets import QPushButton, QTextEdit

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建按钮控件,用于点击后弹出字体对话框
        font_button = QPushButton("选择字体", self)
        font_button.setGeometry(0, 0, 100, 30)
        font_button.clicked.connect(self.set_font)

        # 3.创建文本框控件,用于显示文本
        self.textEdit = QTextEdit(self)
        self.textEdit.setGeometry(0, 50, 500, 300)
        self.textEdit.setText("小樱")

    def set_font(self):
        flag, font = QFontDialog.getFont()
        if flag:
            self.textEdit.setFont(font)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615184810649

3.6 颜色对话框

颜色对话框 QColorDialog 和字体对话框 QFontDialog 类似,也是一种标准对话框,供用户选择颜色。在对话框中用户可以自己设定和选择颜色,还可使用标准颜色,另外用户也可保存自己设定的颜色。

用 QColorDialog 类创建标准颜色对话框的方法如下:

QColorDialog(parent:QWidget=None)
QColorDialog(color:QColor, parent:QWidget=None)

其中参数 QColor 用于 初始化对话框,还可以用 Qt.GlobalColor 和 QGradient 初始化颜色。

QColorDialog 类中常用的方法如下:

# 实例方法
selectedColor() -> QColor                                                   # 获取颜色对话框中单击OK按钮后选中的颜色
setCurrentColor(color: QColor) -> None                                      # 设置颜色对话框中当前选中的颜色,用于初始化对话框
currentColor() -> QColor                                                    # 获取颜色对话框中当前选中的颜色
setOption(option:QColorDialog.ColorDialogOption, on:bool=true) -> None      # 设置对话框的选项
testOption(option:QColorDialog.ColorDialogOption) -> bool                   # 测试对话框的选项

# 静态方法
setCustomColor(index:int, color:QColor) -> None                             # 设置用户颜色
customColor(index:int) -> QColor                                            # 获取用户颜色
customCount() -> int                                                        # 获取用户颜色数量
setStandardColor(index:int, color:QColor) -> None                           # 设置标准颜色
standardColor(index:int) -> QColor                                          # 获取标准颜色

# 显示对话框获取颜色
getColor(initial:QColor=Qt.white, parent:QWidget=None, title:str="", options:QColorDialog.ColorDialogOptions=QColorDialog.ColorDialogOptions()) -> QColor

颜色对话框的显示可以用 show()、open() 和 exec() 方法,也可以用 getColor() 方法。getColor() 方法是静态方法,直接使用 类名.getColor() 方法调用,也可用实例对象调用。

setOption(QColorDialog.ColorDialogOption,on=True) 方法设置颜色对话框的选项,其中 QColorDialog.ColorDialogOption 可以取值如下:

QColorDialog.ColorDialogOption.ShowAlphaChannel    # 在对话框上显示Alpha通道
QColorDialog.ColorDialogOption.NoButtons           # 不显示OK和Cancel按钮
QColorDialog.ColorDialogOption.DontUseNativeDialog # 不使用本机的对话框

颜色对话框中有标准的颜色,可以用 standardColor(index:int) 方法获取标准颜色,用 setStandardColor(index:int,QColor) 方法设置标准颜色。

颜色对话框可以存储用户指定的颜色,用 setCustomColor(index:int,QColor) 方法设置用户颜色,用 customColor(index:int) 方法获取用户颜色。

QColorDialog 类中常用的信号如下:

colorSelected(color:Color)                  # 在对话框中选择颜色是发射信号
currentColorChanged(color:Color)            # 在对话框中单击OK按钮是发射信号
import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QColorDialog
from PySide6.QtWidgets import QPushButton, QTextEdit

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建按钮控件,用于点击后弹出颜色对话框
        font_button = QPushButton("选择颜色", self)
        font_button.setGeometry(0, 0, 100, 30)
        font_button.clicked.connect(self.set_color)

        # 3.创建文本框控件,用于显示文本
        self.textEdit = QTextEdit(self)
        self.textEdit.setGeometry(0, 50, 500, 300)
        self.textEdit.setText("小樱")

    def set_color(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.textEdit.setTextColor(color)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

点击设置颜色之后,之前字体的颜色不会改变;

image-20240615184926888

3.7 进度对话框

进度对话框 QProgressDialog 用于表明某项任务正在进行及任务的完成进度。进度对话框由 1 个标签 QLabel、1 个进度条 QProgressBar 和 1 个按钮 QPushButton 构成。进度对话框可以与定时器一起工作,每隔一段时间获取一项任务的完成值,再设置进度条的当前值。当然,如果任务能自动输出其完成值,可直接与进度条的槽函数 setValue(int) 连接。

用 QProgressDialog 类创建进度对话框的方法如下所示:

QProgressDialog(parent:QWidget=None)
QProgressDialog(title:str, text:str, min:int, max:int, parent:QWidget=None)

QProgressDialog 类中常用的方法如下:

# 实例方法
minimumDuration() -> int                        # 获取从创建到显示时的时间
value() -> int                                  # 获取进度条的当前值
minimum() -> int                                # 获取进度条的最小值
maximum() -> int                                # 获取进度条的最大值
labelText() -> str                              # 获取对话框中标签的文本
wasCanceled() -> bool                           # 获取对话框是否被取消
setAutoClose(close:bool) -> None                # 调用reset()方法时,设置是否自动隐藏
autoClose() -> bool                             # 获取是否自动隐藏
setAutoReset(reset:bool) -> None                # 进度条的值达到最大时,设置是否自动重置
autoReset() -> bool                             # 获取进度条值达到最大时,是否自动重置
setBar(bar:QProgressBar) -> None                # 重新设置对话框中的设置进度条
setCancelButton(button:QPushButton) -> None     # 重新设置对话框中的取消按钮
setLabel(label:QLabel) -> None                  # 重新设置对话框中的标签

# 槽函数
setMinimumDuration(ms:int) -> None              # 设置对话框从创建到显示出来的过滤时间
setValue(progress:int) -> int                   # 设置进度条的当前值
setMinimum(minimum:int) -> None                 # 设置进度条的最小值
setMaximum(maximum:int) -> None                 # 设置进度条的最大值
setRange(minimum:int, maximum:int) -> None      # 设置进度条的最小值和最大值
setLabelText(text:str) -> None                  # 设置对话框中标签的文本
setCancelButtonText(text:str) -> None           # 设置取消按钮的文本
cancel() -> str                                 # 取消对话框
forceShow() -> None                             # 强制显示对话框
reset() -> None                                 # 重置对话框

进度对话框可以不用 show() 等方法来显示,在创建进度对话框后,经过某段时间后对话框会自动显示出来,这段时间是通过 setMinimumDuration(int) 来设置的。参数的单位是毫秒,默认是 4000 毫秒,如果设置为 0,则立即显示对话框。可以用 forceShow() 方法强制显示对话框。设置这个显示时间的目的是防止任务进展太快,进度对话框一闪而过。

对话框如果设置了 setAutoClose(True),调用 reset() 方法重置进度条时,会自动隐藏对话框。对话框如果设置了 setAutoReset(True),则进度条的值达到最大值时会调用 reset() 方法重置进度条;

当单击对话框中的 Cancel 按钮或执行 cancel() 方法时,会取消对话框,并且会重置和隐藏对话框,同时 wasCanceled() 的值为 True。

QProgressDialog 类中常用的信号如下:

canceled()       # 单击对话框中的Cancel按钮后,发射信号,进度条被隐藏和重置

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QProgressDialog
from PySide6.QtWidgets import QPushButton, QTextEdit
from PySide6.QtCore import QTimer

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

        self.count = 0
        # 3.创建一个定时器对象
        self.timer = QTimer()
        # 4.关联信号
        self.timer.timeout.connect(self.change_progress)

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建按钮控件,点击后弹出进度对话框
        button = QPushButton("点击弹出进度对话框", self)
        button.clicked.connect(self.popup_progressDialog)

    def popup_progressDialog(self):
        # 1.创建进度对话框控件
        self.progressDialog = QProgressDialog(self)

        # 2.设置进度对话框的范围
        self.progressDialog.setRange(0, 100)

        # 3.设置当前值为0
        self.progressDialog.setValue(0)

        # 4.设置对话款从创建到出来的过渡时间
        self.progressDialog.setMinimumDuration(0)

        # 5.设置进度对话框的标签文本
        self.progressDialog.setLabelText("任务正在进行中")

        # 6.设置进度对话框的取消按钮文本
        self.progressDialog.setCancelButtonText("终止任务")

        # 7.设置对话框调用reset()方法时自动隐藏
        self.progressDialog.setAutoClose(True)

        # 8.设置进度条的值到达最大值,自动重置
        self.progressDialog.setAutoReset(True)

        # 9.定义信号与槽的连接
        self.progressDialog.canceled.connect(self.cancel_task)

        # 8.启动定时器
        self.timer.start(1000)

    def change_progress(self):
        # 如果进度对话框没有关闭
        if not self.progressDialog.wasCanceled():
            self.count += 1
            if self.count <= 100:
                self.progressDialog.setValue(self.count)
            else:
                # 计数值清零
                self.count = 0
                # 关闭定时器
                self.timer.stop()
        else:
            # 计数值清零
            self.count = 0
            # 关闭定时器
            self.timer.stop()

    def cancel_task(self):
        print("你手动终止了任务")

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615185053382

3.8 向导对话框

向导对话框 QWizard 由多页构成,可以引导客户按步骤完成某项工作。对话框的顶部是横幅(banner),横幅中有标题、子标题和 logo,左侧是水印区(watermark),底部有一排按钮,右侧是向导页的内容;与其他对话框不同的是,向导对话框由多页构成,同一时间只能显示其中的一页,单击 Next 按钮或 Back 按钮可以向后或向前显示其他页。对话框中的页是向导页 QWizardPage,向导页有自己的布局和控件,向导会为向导页分配从 0 开始的 ID 号。

向导对话框 QWizard 是从 QDialog 类继承来的,QWizardPage 是从 QWidget 类继承来的,用 QWizard 类和 QWizardPage 类创建实例对象的方法如下所示。

QWizard(parent:QWidget=None, flags:Qt.WindowFlags=Default(Qt.WindowFlags))
QWizardPage(parent:QWidget=None)

QWizard 类常用方法:

# 实例方法
addPage(page:QWizardPage) -> int                                                    # 添加向导页,并返回ID
setPage(id:int, page:QWizardPage) -> None                                           # 用指定ID号添加向导页
removePage(id:int) -> None                                                          # 移除指定id的向导页
currentId() -> int                                                                  # 返回当前向导页的ID
currentPage() -> QWizardPage                                                        # 返回当前向导页
hasVisitedPage(id:int) -> bool                                                      # 获取向导页是否被访问过
visitedIds() -> List[int]                                                           # 获取访问过的页的ID列表
page(id:int) -> QWizardPage                                                         # 返回指定ID的向导页
pageIds() -> List[int]                                                              # 获取向导页的ID列表

setButton(which:QWizard.WizardButton, button:QAbstractButton) -> None               # 添加某种用途的按钮
button(which:QWizard.WizardButton) -> QAbstractButton                               # 获取某种用途的按钮
setButtonLayout(layout:Sequence[QWizard.WizardButton]) -> None                      # 设置按钮的布局(相对位置)
setButtonText(which:QWizard.WizardButton, text:str) -> None                         # 设置按钮的文本
buttonText(which:QWizard.WizardButton) -> str                                       # 获取按钮的文本

setField(name:str, value:Any) -> None                                               # 设置字段的值
field(name:str) -> Any                                                              # 获取字段的值

setOption(option:QWizard.WindowOption, on:bool=true) -> None                        # 设置向导对话框的选项
options() -> QWizard.QWizardOptions                                                 # 获取向导对话框的选项
testOption(option:QWizard.WindowOption) -> bool                                     # 测试是否设置了某个选项

setPixmap(which:QWizard.WizardPixmap, pixmap:Union[QPixmap, Qimage, str]) -> None   # 在对话框的指定区域设置图片
pixmap(which:QWizard.WizardPixmap) -> QPixmap                                       # 获取对话框的图片

setSideWidget(widget:QWidget) -> None                                               # 设置侧边栏

setStartId(id:int) -> None                                                          # 设置初始页
startId() -> int                                                                    # 获取初始页

setTitleFormat(format:Qt.TextFormat) -> None                                        # 设置标题的格式
setSubTitleFormat(format:Qt.TextFormat) -> None                                     # 设置子标题的格式

setWizardStyle(style:QWizard.WizardStyle) -> None                                   # 设置向导对话框的样式
wizardStyle() -> QWizard.WizardStyle                                                # 获取向导对话框的样式

cleanupPage(id:int) -> None                                                         # 清除内容,恢复默认值
initializePage(id:int) -> None                                                      # 初始化向导页
nextId() -> int                                                                     # 返回下一页的ID 
validateCurrentPage() -> bool                                                       # 验证当前页的输入是否合法

# 槽方法
restart() -> None                                                                   # 回到初始页
back() -> None                                                                      # 显示上一页
next() -> None                                                                      # 显示下一页

向导对话框的风格用 setWizardStyle(style:QWizard.WizardStyle) 方法设置,其中参数 style 是 QWizard.WizardStyle 的枚举值,可以取值如下:

QWizard.WizardStyle.ClassicStyle
QWizard.WizardStyle.ModernStyle
QWizard.WizardStyle.MacStyle
QWizard.WizardStyle.AeroStyle

向导对话框的标题和子标题由向导页的 setTitle(title:str) 方法和 setSubTitle(subTitle:str) 方法设置,虽然由向导页设置标题和子标题,但是它们会显示在向导对话框的横幅中。标题和子标题的格式由向导对话框的 setTitleFormat(format:Qt.TextFormat) 方法和 setSubTitleFormat(format:Qt.TextFormat) 方法设置,其中参数 format 的取值是 Qt.TextFormat 枚举值,可以取值如下:

Qt.TextFormat.PlainText      # 纯文本
Qt.TextFormat.RichText       # 富文本
Qt.TextFormat.AutoText       # 由系统决定
Qt.TextFormat.MarkdownText   # Markdown文本

向导对话框的选项由 setOption(QWizard.WizardOption,on=True) 方法设置,其中 QWizard.WizardOption 参数是枚举类型,可以取值如下:

QWizard.WizardOption.IndependentPages                   # 向导页之间是相互独立的,相互间不传递数据
QWizard.WizardOption.IgnoreSubTitles                    # 不显示子标题
QWizard.WizardOption.ExtendedWatermarkPixmap            # 将水印图片拓展到窗口边缘
QWizard.WizardOption.NoDefaultButton                    # 不将Next按钮和Finish按钮设置成默认按钮
QWizard.WizardOption.NoBackButtonOnStartPage            # 在起始页中不显示Back按钮
QWizard.WizardOption.NoBackButtonOnLastPage             # 在最后页中不显示Back按钮
QWizard.WizardOption.DisabledBackButtonOnLastPage       # 在最后页中Back按钮失效
QWizard.WizardOption.HaveNextButtonOnLastPage           # 在最后页中显示失效的Next按钮
QWizard.WizardOption.HaveFinishButtonOnEarlyPages       # 在非最后页中显示失效的Finsh按钮
QWizard.WizardOption.NoCancelButton                     # 不显示Cancel按钮
QWizard.WizardOption.CancelButtonOnLeft                 # 将Cancel按钮放到Back按钮的左边
QWizard.WizardOption.HaveHelpButton                     # 显示Help按钮
QWizard.WizardOption.HelpButtonOnRight                  # 将帮助按钮放到右边
QWizard.WizardOption.HaveCustomButton1                  # 显示用户自定义的第一个按钮
QWizard.WizardOption.HaveCustomButton2                  # 显示用户自定义的第二个按钮
QWizard.WizardOption.HaveCustomButton2                  # 显示用户自定义的第二个按钮
QWizard.WizardOption.NoCancelButtonOnLastPage           # 在最后页中不显示Cancel按钮

向导对话框和向导页都可以用 setPixmap(which:QWizard.WizardPixmap,pixmap:QPixmap) 方法设置向导对话框中显示的图片,用向导对话框设置的图片作用于所有页,用向导页设置的图片只作用于向导页所在的页面,其中参数 which 的取值是 QWizard.WizardPixmap 的枚举值,用于设置图片放置的位置,可以取值如下:

QWizard.WizardPixmap.WatermarkPixmap
QWizard.WizardPixmap.LogoPixmap
QWizard.WizardPixmap.BannerPixmap
QWizard.WizardPixmap.BackgroundPixmap

setButton(which:QWizard.WizardButton,button:QAbstractButton) 方法往对话框中添加某种用途的按钮,其中参数 which 的取值是 QWizard.WizardButton 的枚举值,用于指定按钮的用途。QWizard.WizardButton的取值如下所示。

QWizard.WizardButton.BackButton             # Back按钮
QWizard.WizardButton.NextButton             # Next按钮
QWizard.WizardButton.CommitButton           # Commit按钮
QWizard.WizardButton.FinishButton           # Finish按钮
QWizard.WizardButton.CancelButton           # Cancel按钮
QWizard.WizardButton.HelpButton             # Help按钮
QWizard.WizardButton.CustomButton1          # 用户自定义第一个按钮
QWizard.WizardButton.CustomButton2          # 用户自定义第二个按钮
QWizard.WizardButton.CustomButton3          # 用户自定义第三个按钮
QWizard.WizardButton.Stretch                # 布局中的水平伸缩器

对话框中最多可以添加 3 个自定义的按钮,要使自定义按钮可见,还需要用 setOption() 方法把自定义按钮显示出来。通常情况下 Next 按钮和 Finish 按钮是互斥的。

QWizard 类常用信号:

currentIdChanged(id:int)            # 当前页面id改变时发射信号,参数是新页的id
customButtonClicked(which:int)      # 单击自定义按钮时发射信号,参数是自定义按钮的索引
helpRequested()                     # 单击帮助按钮时发射信号
pageAdded(id:int)                   # 添加向导页是发射信号,参数是新页的id
pageRemoved(id:int)                 # 移除向导页是发射信号,参数是被移除页的id

QWizardPage 类常用方法:

setButtonText(which:QWizard.WizardButton, text:str) -> None                                     # 设置某种用途按钮的文字
buttonText(which:QWizard.WizardButton) -> str                                                   # 获取指定用途的按钮的文本

setCommitPage(commitPage:bool) -> None                                                          # 设置成提交页
isCommitPage() -> bool                                                                          # 获取是否是提交页
setFinalPage(finalPage:bool) -> None                                                            # 设置成最终页
isFinalPage() -> bool                                                                           # 获取是否是最终页

setPixmap(which:QWizard.WizardPixmap, pixmap:QPixmap) -> None                                   # 在指定区域设置图片
pixmap(which:QWizard.WizardPixmap) -> QPixmap                                                   # 获取指定区域的图片
setTitle(title:str) -> None                                                                     # 设置标题
title() -> str                                                                                  # 获取标题
setSubTitle(subTitle:str) -> None                                                               # 设置子标题
subTitle() -> str                                                                               # 获取子标题

registerField(name:str, widget:QWidget, property:str=None, changed_signal:str=None) -> None     # 创建字段
setField(name:str, value:Any) -> None                                                           # 设置字段的值
field(name:str) -> Any                                                                          # 获取字段的值

validatePage() -> bool                                                                          # 验证向导页中输入的内容
wizard() -> QWizard                                                                             # 获取向导页所在的向导对话框
cleanupPage() -> None                                                                           # 清除内容,恢复默认值
initializePage() -> None                                                                        # 初始化向导页中的内容
isComplete () -> bool                                                                           # 获取是否完成输入,以便激活Next按钮或Finish按钮
validatePage() -> bool                                                                          # 验证向导页中输入的内容,若为True,则显示下一页
nextId() -> int                                                                                 # 返回下一页的ID

用向导页的 setCommitPage(bool) 方法可以把向导页设置成提交页,提交页上用 Commit 按钮替换 Next 按钮,且不能用 Back 或 Cancel 按钮来撤销。单击 Commit 按钮后,下一页的 Back 按钮失效。用 isCommit() 方法可以获取该页是否是提交页。

用向导页的 setFinalPage(bool) 方法可以把向导页设置成最后页,最后页上用 Finish 按钮替换 Next 按钮,此时用 nextId() 方法获取下一页的 ID 时返回 -1。

向导对话框中的多个向导页之间的数据不能自动进行通信,要实现向导页之间的数据传递,可以将向导页上的控件属性定义成字段,并可以将控件属性与某信号关联,这样当属性值发生变化时发送信号,也可以通过字段设置或获取控件的属性值,字段对于向导对话框来说是全局性的。

字段的定义通过 registerField(name:str,widget:QWidget,property:str=None,changedSignal:str=None) 函数来实现,其中 name字段名称widget向导页上的控件property字段的属性changedSignal与字段属性相关的信号

定义好字段后,可以利用 setField(name:str,value:Any) 方法和 field(name:str) 方法设置和获取字段的值。用 setDefaultProperty(className:str,property:str,changedSignal:str) 方法可以设置某类控件的某个属性与某个信号相关联。

PySide6 对大多数控件能自动将某个属性与某个信号相关联。

控件 属性 关联的信号
QAbstractButton checked toggled(bool)
QAbstractSlider value valueChange(int)
QComboBox currentIndex currentIndexChanged(ing)
QDateTimeEdit dateTime dateTimeChanged(QDatetime)
QLineEdit text textChanged(str)
QListWidget currentRow currentRowChanged(bool)
QSpinBox value valueChanged(int)

isComplete() 函数的返回值为 True 时,会激活 Next 按钮或 Finish 按钮。可以重写该函数,用户在页面上输入信息后,当满足一定条件时改变 isComplete() 的返回值,以便激活 Next 按钮或 Finish 按钮。如果重写 isComplete() 函数,一定要确保 completeChange() 信号也能发送。

用户单击 Next 按钮或 Finish 按钮后,需要验证页面上输入的内容是否合法,这时会调用向导对话框的 validateCurrentPage() 函数和向导页的 validatePage() 函数,通常需要重写这两个函数以便完成对输入内容的验证,如果返回 True 则显示下一页。

单击 Next 按钮后,在显示下一页之前,会调用向导页的 initializePage() 函数。可以重写该函数,以便根据前面的向导页的内容初始化本向导页的内容。

单击 Back 按钮后,在显示前一页之前,会调用向导页的 cleanupPage() 函数。可以重写该函数,以保证向导页能恢复默认值。

根据 nextId() 函数的返回值,决定要显示的下一页,如果没有后续页,则返回 -1。单击 next 按钮和 back 按钮都会调用 nextId() 函数,如果重写该函数,会根据已经输入和选择的内容让 nextId() 返回相应页的 ID 号,从而控制页面显示的顺序。

QWizardPage 类常用信号:

completeChanged()        # 当isCompleted()的返回值发生变化时发射信号

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QWizard, QWizardPage
from PySide6.QtWidgets import QFormLayout
from PySide6.QtWidgets import QLineEdit, QPlainTextEdit, QSpinBox
from PySide6.QtWidgets import QPushButton, QComboBox
from PySide6.QtWidgets import QMessageBox

# 向导页1
class WizardPage_1(QWizardPage):
    def __init__(self, parent=None):
        # 调用父类的__init__()方法
        super().__init__(parent)

        # 设置主标题
        self.setTitle("学生成绩输入系统")
        # 设置子标题
        self.setSubTitle("基本信息")

        # 创建表单布局
        form = QFormLayout(self)

        # 创建单行文本框控件
        self.line_name = QLineEdit()
        self.line_name.setPlaceholderText("请输入姓名")
        self.line_number = QLineEdit()
        self.line_number.setPlaceholderText("请输入学号")

        # 向表单布局中添加行
        form.addRow("姓名: ", self.line_name)
        form.addRow("学号: ", self.line_number)

        # 定义信号与槽的连接
        self.line_name.textChanged.connect(self.isComplete)
        self.line_number.textChanged.connect(self.isComplete)
        self.line_name.textChanged.connect(self.completeChanged_emit)
        self.line_number.textChanged.connect(self.completeChanged_emit)

        # 创建字段
        self.registerField("name", self.line_name)
        self.registerField("number", self.line_number)

    # 重写isComplete()函数
    def isComplete(self):
        if self.line_name.text() != "" and self.line_number.text() != "":
            return True
        else:
            return False

    # 重写isComplete()函数后,需要重新发送信号
    def completeChanged_emit(self):
        self.completeChanged.emit()

    # 重写数据校验的函数
    def validatePage(self):
        # 确保学号输入的数字
        if self.line_number.text().isdigit():
            return True
        else:
            QMessageBox.warning(self, "警告", "输入有误,请检查输入的信息")
            return False

# 向导页2
class WizardPage_2(QWizardPage):
    def __init__(self, parent=None):
        # 调用父类的__init__()方法
        super().__init__(parent)

        # 设置主标题
        self.setTitle("学生成绩输入系统")
        # 设置子标题
        self.setSubTitle("详情信息")

        # 创建表单布局
        form = QFormLayout(self)

        # 创建组合框控件
        comboBox_gender = QComboBox()
        comboBox_gender.addItems(["女", "男"])
        form.addRow("性别: ", comboBox_gender)

        # 创建整数选择控件
        spinBox_age = QSpinBox()
        spinBox_age.setRange(0, 300)
        form.addRow("年龄: ", spinBox_age)

        # 创建字段
        self.registerField("gender", comboBox_gender)
        self.registerField("age", spinBox_age)

# 向导页3
class WizardPage_3(QWizardPage):
    def __init__(self, parent=None):
        # 调用父类的__init__()方法
        super().__init__(parent)

        # 设置主标题
        self.setTitle("学生成绩输入系统")
        # 设置子标题
        self.setSubTitle("考试成绩")

        # 创建表单布局
        form = QFormLayout(self)

        # 创建小数选择控件
        spinBox_chinese = QSpinBox()
        spinBox_chinese.setRange(0, 150)

        spinBox_math = QSpinBox()
        spinBox_math.setRange(0, 150)

        spinBox_english = QSpinBox()
        spinBox_english.setRange(0, 150)

        form.addRow("语文: ", spinBox_chinese)
        form.addRow("数学: ", spinBox_math)
        form.addRow("英语: ", spinBox_english)

        # 创建字段
        self.registerField("chinese", spinBox_chinese)
        self.registerField("math", spinBox_math)
        self.registerField("english", spinBox_english)

# 向导对话框
class Wizard(QWizard):
    def __init__(self, parnent=None):
        # 调用父类的__init__()方法
        super().__init__(parnent)

        # 设置向导对话框的风格
        self.setWizardStyle(QWizard.WizardStyle.ModernStyle)

        # 添加向导页
        self.addPage(WizardPage_1(self))
        self.addPage(WizardPage_2(self))
        self.addPage(WizardPage_3(self))

        # 创建按钮控件
        self.button_back = QPushButton("上一步")
        self.button_next = QPushButton("下一步")
        self.button_cancel = QPushButton("取消")
        self.button_finish = QPushButton("完成")

        # 向导对话框中添加某种用途的按钮
        self.setButton(QWizard.WizardButton.BackButton, self.button_back)
        self.setButton(QWizard.WizardButton.NextButton, self.button_next)
        self.setButton(QWizard.WizardButton.CancelButton, self.button_cancel)
        self.setButton(QWizard.WizardButton.FinishButton, self.button_finish)

        # 设置向导对话框中按钮的布局
        self.setButtonLayout(
            [
                self.WizardButton.Stretch,
                self.WizardButton.CancelButton,
                self.WizardButton.BackButton, self.WizardButton.NextButton,
                self.WizardButton.FinishButton
            ]
        )

class MyWidget(QWidget):
    def __init__(self):
        # 1.调用父类Qwidget类的__init__()方法
        super().__init__()
        # 2.调用setupUi()方法初始化页面
        self.setup_ui()

    def setup_ui(self):
        # 1.设置窗口对象大小
        self.resize(700, 500)

        # 2.创建向导对话框
        self.wizard = Wizard()

        # 3.创建按钮控件,点击弹出向导对话框
        button_enter = QPushButton("点击进入学生成绩管理系统", self)
        button_enter.clicked.connect(self.enter_wizard)

        # 创建多行文本框控件,用来显示信息
        self.plainText = QPlainTextEdit(self)
        self.plainText.setGeometry(0, 50, 500, 300)
        self.plainText.setReadOnly(True)

        # 定义信号与槽的连接
        self.wizard.button_finish.clicked.connect(self.complete)

    def enter_wizard(self):
        # 设置初始页
        self.wizard.setStartId(0)
        # 重新启动
        self.wizard.restart()
        # 打开对话框
        self.wizard.open()

    def complete(self):
        template = "姓名: {}, 学号: {}, 性别: {}, 年龄: {}, 语文: {}, 数学: {}, 英语: {}\r\n"

        gender = ""
        if str(self.wizard.field("gender")) == "1":
            gender = "男"
        elif str(self.wizard.field("gender")) == "0":
            gender = "女"

        string = template.format(
            self.wizard.field("name"), self.wizard.field("number"), gender,
            self.wizard.field("age"),
            self.wizard.field("chinese"), self.wizard.field("math"), self.wizard.field("english")
        )

        print(string)
        self.plainText.appendPlainText(string)

if __name__ == "__main__":
    # 1.创建一个QApplication类的实例
    app = QApplication(sys.argv)
    # 2.创建一个窗口
    window = MyWidget()
    # 3.展示窗口
    window.show()
    # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
    sys.exit(app.exec())

image-20240615185316675

posted @ 2025-04-16 08:54  Yasuo_Hasaki  阅读(59)  评论(0)    收藏  举报
//雪花飘落效果