pyside6学习笔记

主要模组简介绍

在Qt官网的介绍中,PyQt包括三个主要的基础模组。

  • QtCore:提供核心非 GUI 功能,如信号和 槽、属性、项目模型的基类、 序列化等。
  • QtGui:使用GUI功能扩展QtCore:事件,窗口 和屏幕,OpenGL和基于光栅的2D绘画,如 以及图像。
  • QtWidgets:为您的应用程序提供现成的小部件, 包括 UI 的图形元素。

调用方式

如果需要调用某个模块,可以先在官网搜索该模块所在的基础模块,在程序中按以上的方式对应调用即可。

QT 官网

QT for python

1
2
3
from PySide6.QtWidgets import ...
from PySide6.QtGui import ...
from PySide6.QtCore import ...

安装与环境配置

安装

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pyside6

安装PySide6时就已经安装Qt Designer、uic和rcc工具。我们只需要在PyCharm里配置一下即可。

配置

使用PyCharm集成开发工具,在安装 QtTools库以后,还要对 QtDesignerPyUIC进行环境配置,将其集成到 PyCharm

image-20230109003938283

QtDesigner

Qt Designer是PyQt和PySide通用的工具,通过拖拽窗口部件和属性编辑完成GUI的设计工作,保存为*.ui文件

拷到项目中使用。

安装完 pyside6直接在命令行运行 pyside6-designer即可打开 designer

从顶部菜单栏选择:File -> Settings,弹出 Seetings窗口;选择:Tools -> ExternalTools,在右侧点击 “+” 弹出 CreateTool窗口

image-20230116005934006

  • Name:填写 QtDesigner,标识作用

  • Program:填写 designer.exe 的路径,例如 F:\ProgramData\miniconda3\envs\notes\Scripts\pyside6-designer.exe

  • Arguments:不用填写

  • Working directory:填写生成 UI 文件的保存路径

    • 要将 .ui文件保存在当前``Project 路径下,则填写 ProjectFileDir `
    • 要将 .ui文件保存在当前 Project路径下,\program 子目录中,则填 FileDir

在项目名称(新建ui时)或你要编辑的ui文件上打开右键菜单,找到External Tools(或你设置的Group名称),打开PySide6 QtDesinger。

可以通过uic工具转成py文件使用,也可以通过以下代码调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import sys

from PySide6.QtCore import QFile, QIODevice
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication

if __name__ == "__main__":

    app=QApplication(sys.argv)

    ui_file_name="01-窗口创建/demo.ui"
    ui_file=QFile(ui_file_name)
    if not ui_file.open(QIODevice.ReadOnly):
        print(f"Cannot open {ui_file_name}: {ui_file.errorString()}")
        sys.exit(-1)
    loader=QUiLoader()
    window=loader.load(ui_file)
    ui_file.close()
    if not window:
        print(loader.errorString())
        sys.exit(-1)
    window.show()

    sys.exit(app.exec())

PyUIC

pyuic安装在 Scripts目录下,对应 pyside6-uic.exe

PyUIC将QtDesigner生成的ui文件转换为py文件

从顶部菜单栏选择:File -> Settings,弹出 Seetings窗口;选择:Tools -> ExternalTools,在右侧点击 “+” 弹出 CreateTool窗口

CreateTool 窗口依次填写:

  • Name:填写 PyUIC,标识作用
  • Program:填写 pyside6-uic 的路径,需要区分虚拟环境和系统环境 F:\ProgramData\miniconda3\envs\notes\Scripts\pyside6-uic.exe
  • Arguments:填写 FileName -o ui_ FileNameWithoutExtension .py
  • Working directory:填写将 .ui 文件转换为 .py 文件的保存路径,填写 FileDir

在要转换的ui文件上点击右键,在右键菜单里使用上述配置好的uic工具即可转换为同名的py文件。

PyRCC

Program中配置的是pyside6-rcc.exe的文件路径

F:\ProgramData\miniconda3\envs\notes\Scripts\pyside6-rcc.exe

image-20230116012639083

  • Name:填写 PyRCC
  • Program:填写 pyside6-rcc 的路径,F:\ProgramData\miniconda3\envs\notes\Scripts\pyside6-rcc.exe
  • Arguments中填写 FileName -o rcc_ FileNameWithoutExtension .py
  • Working directory中填写 FileDir

新建一个resource.qrc文件,把用到的图片资源写到配置文件里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE RCC>

<RCC version="1.0">

<qresource> 

<file alias="contacts.png">ico/contacts.png</file>

<file alias="exit.png">ico/exit.png</file>

<file alias="about.png">ico/about.png</file>

<file alias="config.png">ico/config.png</file>

<file alias="help.png">ico/help.png</file>

</qresource>

</RCC>

也可以用Qt Designer右下角的资源编辑器进行编辑

image-20230116013508159

编辑保存后,到PyCharm中在要转换的qrc文件上点击右键,在右键菜单里使用上述配置好的rcc工具即可转换为同名的py文件。

引用py文件中的资源使用的时候用冒号加图片路径,如:

1
QtGui.Qpixmap(':images/file.png')

要把程序打包成可执行文件的时候,先把资源文件转成py后调用就方便多了。

基础了解

元对象系统

翻译信息:

本文翻译自 PySide6 官方文档 The Meta-Object System

协议:本翻译遵守原文档使用的GNU Free Documentation License version 1.3 授权

译者:muzing

翻译时间:2022.06

译者注:本文原文由Qt 6(C++) 文档直接转换而来,似乎代码部分并未完全替换为有效的 Python 代码,建议与 C++ 原版文档对比阅读

Qt 的元对象系统(meta-object system)和自省(introspection)功能的概述。

Qt 的元对象系统为对象间通信、运行时类型信息和动态属性系统提供了信号与槽机制。

元对象系统基于三件事:

1.QObject 类为可以利用元对象系统的对象提供基类。
2.类声明私有部分中的 Q_OBJECT 宏用于启用元对象特性,例如动态属性、信号和槽。
3.元对象编译器(moc) 为每个 QObject 子类提供实现元对象功能所需的代码。

moc 工具读取 C++ 源文件。如果它找到一个或多个包含 Q_OBJECT 宏的类声明,它会生成另一个 C++ 源文件,其中包含每个类的元对象代码。这个生成的源文件要么是 #include 被包含在类的源文件中,要么(更常见地)是被编译并与类的实现链接。

除了提供对象间通信的信号与槽机制(这是引入系统的主要原因),元对象代码还提供以下附加功能:

  • metaObject() 返回类的关联 meta-object
  • className() 在运行时将类名作为字符串返回,无需通过 C++ 编译器支持本机运行时类型信息(RTTI)
  • inherits() 函数返回对象是否继承 QObject 继承树中指定类的类的实例
  • tr() 翻译字符以进行国际化
  • setProperty()property() 按名称动态设置和获取属性
  • newInstance() 构造一个新的类实例

也可以在 QObject 类上使用qobject_cast() 执行动态转换。qobject_cast() 函数的行为类似于 标准 C++ 的 dynamic_cast(),其优点是不需要 RTTI 支持,并且可以跨动态库边界工作。它尝试将其参数转换为尖括号中指定的指针类型,如果对象的类型正确(在运行时确定),则返回非零指针;如果对象的类型不兼容,则返回 None

例如,假设 MyWidget 继承自 QWidget 并使用Q_OBJECT 宏声明:

1
obj = MyWidget()

QObject * 类型的 obj 变量实际上是指 MyWidget 对象,所以我们可以适当地转换它:

1
widget = QWidget(obj)

成功从 QObject 转换到 QWidget,因为对象其实是一个 MyWidget,它是 QWidget 的子类。由于我们知道 obj 是一个 MyWidget,所以也可以将其转换为 MyWidget *:

1
myWidget = MyWidget(obj)

转换至 MyWidget 成功,因为 qobject_cast() 没有区分内置 Qt 类型和自定义类型。

1
2
label = QLabel(obj)
# label is 0

另一方面,转换为 QLabel 失败。指针然后被设置为 0。这使得可以在运行时根据类型以不同的方式处理不同类型的对象:

1
2
3
if(QLabel label = QLabel(obj)) {            label.setText(tr("Ping"))
} else if(QPushButton button = QPushButton(obj)) {
button.setText(tr("Pong!"))

虽然可以在没有 Q_OBJECT 宏和元对象代码的情况下使用QObject 作为基类,但如果不使用Q_OBJECT 宏,则信号和槽、以及此处描述的其他功能都将不可用。从元对象系统的角度来看,没有元代码的 QObject 子类等价于最接近的具有元对象代码的祖先 。这意味着,例如,className() 不会返回类的实际名称,而是这个祖先的类名。

因此,我们强烈建议 QObject 的所有子类都使用Q_OBJECT 宏,无论它们是否真的使用信号、槽和属性。

对象模型

翻译信息:

本文翻译自 Qt6 官方文档 Object Model

协议:本翻译遵守原文档使用的GFDLv1.3 授权

译者:muzing

翻译时间:2022.06

标准 C++ 对象模型为对象范例提供了非常有效的运行时支持。但它的静态性质在某些具体问题领域不够灵活。GUI 编程是一个需要运行时效率和高灵活性的领域。Qt 通过将 C++ 的速度与 Qt 对象模型的灵活性相结合,来实现这一点。

Qt 为 C++ 添加了如下特性:

这些 Qt 特性中的许多是基于从QObject 的继承,用标准 C++ 技术实现。其他的,比如对象通信机制和动态属性系统,需要由 Qt 自带的元对象编译器(moc)提供的元对象系统

元对象系统是一种 C++ 扩展,使得该语言更适合真正的组件 GUI 编程。

重要的类

这些类构成了 Qt 对象模型的基础。

QMetaClassInfo 关于类的附加信息
QMetaEnum 关于枚举器的元数据
QMetaMethod 关于成员函数的元数据
QMetaObject 包含有关 Qt 对象的元信息
QMetaProperty 关于属性的元数据
QMetaSequence 允许对顺序容器进行类型擦除访问
QMetaType 管理元对象系统中的具名类型
QObject 所有 Qt 对象的基类
QObjectCleanupHandler 监视多个 QObject 的生命周期
QPointer 模板类,提供受保护的指向 QObject 的指针
QSignalBlocker 包裹 QObject::blockSignals() 的异常安全包装器
QSignalMapper 绑定来自可识别发送者的信号
QVariant 行为类似于最常见的 Qt 数据类型的集合

Qt 对象:身份?值?

上面列出的 Qt 对象模型的一些附加功能要求我们将 Qt 对象视为身份(identities),而不是值(values)。值被复制或分配,身份被克隆。克隆意味着创建一个新的身份,而不是旧身份的精确复制品。例如,双胞胎有不同的身份。他们可能看起来相同,但名称不同、位置不同,并且可能有完全不同的社交圈子。

克隆身份是比复制或分配更复杂的操作。我们可以在 Qt 对象模型中看到这意味着什么。

一个 Qt 对象……

  • 可能有一个唯一的QObject::objectName()。如果我们复制一个 Qt 对象,该给这个副本起什么名字呢?
  • 对象层次结构中占据一个位置。如果我们复制一个 Qt 对象,副本应该放在哪里?
  • 可以连接到其他 Qt 对象以向它们发出信号或接收它们发出的信号。如果我们复制一个 Qt 对象,该如何将这些连接转移到副本中呢?
  • 可以在运行时添加未在 C++ 类中声明的新属性。如果我们复制一个 Qt 对象,副本是否应该包括添加到原始对象的属性?

出于这些原因,Qt 对象应该被视为身份而不是值。身份是克隆的,而不是复制或分配的,克隆身份是比复制或分配值更复杂的操作。因此,QObject 及其所有直接或间接继承的子类,都被禁用了复制构造函数和赋值运算符

对象树与所有状态

概述

QObjects 在对象树(object trees)中组织自身。当创建一个以另一个对象为父对象的QObject 时,它会被添加到父对象的children() 列表中,并在父对象被销毁时销毁。事实证明,这种方式非常适合 GUI 对象的需求。例如,一个QShortcut(键盘快捷键)是相关窗口的子对象,因此当用户关闭该窗口时,快捷键也会被销毁。

QQuickItem 是 Qt Quick 模块的基本视觉元素,继承自QObject,但有一个与 QObject 父对象不同的视觉父项的概念。一个项目的视觉父项可能并不是其父对象。参阅Concepts - Visual Parent in Qt Quick 获取更多详细信息。

QWidget,即 Qt Widgets 模块的基础类,扩展了父子关系。一个普通子对象也成为一个子控件,也就是说,它会被显示在父级的坐标系中,并被其父级的边界按图形方式裁剪。例如,当应用程序在关闭消息框后销毁它时,正如我们所希望的那样,消息框的按钮和标签也被销毁,这是因为按钮和标签是消息框的子控件。

您也可以自行删除子对象,它们会自动从其父控件中移除自己。例如,当用户移除一项工具栏时,可能会导致应用程序删除其QToolBar 对象之一,在这种情况下,工具栏的父对象QMainWindow 将检测到变化,并相应地重新配置其屏幕空间。

当应用程序视觉上或行为上表现异常时,调试函数QObject::dumpObjectTree() 和QObject::dumpObjectInfo() 通常很有用。

QObjects 的构造/销毁顺序

QObjects 在堆上创建(即,使用new 创建)时,可以以任意顺序从它们构建对象树,稍后,可以以任意顺序销毁树中的对象。当任何QObjects 被删除时,如果该对象有父对象,则析构函数会自动从其父对象中删除该对象。如果该对象有子对象,则析构函数会自动删除每个子对象。不管销毁的顺序,没有QObjects 会被删除两次。

QObjects 在栈上创建时,适用相同的行为。通常,破坏顺序仍不会造成问题。考虑一下代码段:

1
2
3
4
5
6
int main()
{
QWidget window;
QPushButton quit("Quit", &window);
...
}

父对象 window 和子对象 quit 都是QObjects,因为QPushButton 继承自QWidget,QWidget 又继承自QObjects。这段代码是正确的:quit 的析构函数没有被调用两次,因为 C++ 语言标准 (ISO/IEC 14882:2003) 指定本地对象的析构函数按其构造函数的相反顺序调用。因此,先调用子对象 quit 的析构函数,然后将自己从其父对象 window 中移除,再调用window 的析构函数。

但是考虑一下如果交换构造顺序会发生什么,如第二个片段所示:

1
2
3
4
5
6
7
8
int main()
{
QPushButton quit("Quit");
QWidget window;

quit.setParent(&window);
...
}

在这种情况下,破坏顺序会引发问题。首先调用父对象的析构函数,因为它是最后被创建的。然后调用其子对象 quit 的析构函数,但这是不正确的,因为 quit 是一个局部变量。当 quit 随后超出作用域时,其析构函数再次被调用,这一次是正确的,但已经发生了破坏。

继承关系图

QtWidgets

所有可视控件都继承自QWidget类

QtWidgets

可利用__subclasses__魔法方法获取各个组件的继承关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def get_direct_inherited(widget):
"""获取组件被直接继承的子类,不包含多层继承的"""
return widget.__subclasses__()


def get_inherit_subclass(widget):
""""获取组件被继承以及多层继承的所有子类"""
all_inherit_list=list()

def get_subclass(cls):
return cls.__subclasses__()

def get_widget_all_inherit(_subclass):
nonlocal all_inherit_list

if get_subclass(_subclass) !=0:
for subclass in get_subclass(_subclass):
all_inherit_list.append("-----------------")
all_inherit_list.append(subclass)
get_widget_all_inherit(subclass)

cls_inherit_list=get_subclass(widget)
for subclass_inherit in cls_inherit_list:
all_inherit_list.append(subclass_inherit)
get_widget_all_inherit(subclass_inherit)

return all_inherit_list


if __name__=='__main__':
from PySide6.QtWidgets import QWidget

get_direct_inherited(QWidget)
# get_inherit_subclass(QWidget)

Qt 命名空间

QtCore.Qt 命名空间下包含了整个 Qt 库中所使用的各种标识符。

这些标识符大多为枚举(enum)或标志(flags)类型。本文收录部分标识符文档的中文翻译,按字母顺序排列。

###Alignment

Qt.AlignmentFlag 中又分为水平对齐方式与垂直对齐方式,具体有如下数种:

水平对齐:

常量 描述
Qt.AlignLeft 0x0001 与左边缘对齐
Qt.AlignRight 0x0002 与右边缘对齐
Qt.AlignHCenter 0x0004 在可用空间中水平居中
Qt.AlignJustify 0x0008 两端对齐(尽可能使文字占满横向空间)

垂直对齐:

常量 描述
Qt.AlignTop 0x0020 与顶部对齐
Qt.AlignBottom 0x0040 与底部对齐
Qt.AlignVCenter 0x0080 在可用空间中垂直居中
Qt.AlignBaseline 0x0100 与基线对齐

若需同时设置水平、垂直两个维度的对齐方式,只需将两个Flags用或运算符连接,例如:
Qt.AlignCenter 等价于 Qt.AlignVCenter | Qt.AlignHCenter

###CursorMoveStyle

此枚举值描述文本光标移动的风格。逻辑风格中,键盘左箭头意味着光标向文本的前方移动(对于从右至左的文本,前方意味着右方);而视觉风格中,键盘左箭头意味着光标向视觉上的左侧移动,而不考虑文本书写方向。

常量 描述
Qt.LogicalMoveStyle 0 在从左至右的文本块内,按下键盘左方向键时减少光标位置,右方向键增加光标位置;在从右向左的文本块内相反。
Qt.VisualMoveStyle 1 无论书写方向如何,按下键盘左方向键光标总会向左移动,按下右方向键光标向右移动。

###FocusPolicy

常量 描述
Qt.TabFocus 0x1 通过键盘Tab键获取焦点
Qt.ClickFocus 0x2 通过鼠标点击获取焦点
Qt.StrongFocus TabFocus | ClickFocus | 0x8 通过键盘Tab或鼠标点击获取焦点
Qt.WheelFocus StrongFocus | 0x4 在StrongFocus基础上,还支持鼠标滚轮滚动获取焦点
Qt.NoFocus 0 该控件不接受焦点,QLabel等不需要用户键盘操作的控件的默认值

###LayoutDirection

控制 Qt 的布局与文字方向。

常量 描述
Qt.LeftToRight 0 从左至右布局
Qt.RightToLeft 1 从右至左布局
Qt.LayoutDirectionAuto 2 自动布局

对于阿拉伯语、希伯来语等特定语言,需要从右至左布局。

###ScrollBarPolicy

此枚举类型描述了QAbstractScrollArea 滚动条的各种模式。水平滚动条与垂直滚动条的模式相互独立。

常量 描述
Qt.ScrollBarAsNeeded 0 只有当内容太大而无法容纳时,QAbstractScrollArea 才显示滚动条。此为默认值。
Qt.ScrollBarAlwaysOff 1 QAbstractScrollArea 永不显示滚动条。
Qt.ScrollBarAlwaysOn 2 QAbstractScrollArea 总显示一个滚动条。此属性在具有瞬态滚动条的操作系统上被忽略。

###TextElideMode

此枚举值指定显示需省略的文本时省略号应出现的位置:

常量 描述
Qt.ElideLeft 0 省略号应出现在文本的开头。
Qt.ElideRight 1 省略号应出现在文本的末尾。
Qt.ElideMiddle 2 省略号应出现在文本的中间。
Qt.ElideNone 3 省略号不应出现在文本中。

Qt.ElideMiddle 通常是最适合 URL 的选择(例如,”http://bugreports.qt.../QTWEBSITE-13/"),而 Qt.ElideRight 适合其他字符串。

###TextFormat

常量 描述
Qt.PlaintText 0 将文本字符串解析为纯文本
Qt.RichText 1 将文本字符串解析为富文本
Qt.AutoText 2 自动识别为纯文本或富文本
Qt.MarkdownText 3 将文本字符串解析为Markdown格式的文本

###TextInteractionFlag

常量 描述
Qt.NoTextInteraction 0 不能与文本进行交互
Qt.TextSelectableByMouse 1 可以使用鼠标选择文本,并用上下文菜单或标准键盘快捷键复制到剪贴板
Qt.TextSelectableByKeyboard 2 可以用键盘上的光标键选择文本,会显示一个文本光标
Qt.LinksAccessibleByMouse 4 链接高亮显示,并可用鼠标激活
Qt.LinksAccessibleByKeyboard 8 链接可以使用Tab键获得焦点,并通过Enter键激活
Qt.TextEditable 16 文本完全可编辑
Qt.TextEditorInteraction TextSelectableByMouse | TextSelectableByKeyboard | TextEditable 文本编辑器的默认值
Qt.TextBrowserInteraction TextSelectableByMouse | LinksAccessibleByMouse | LinksAccessibleByKeyboard QTextBrowser的默认值

###WindowModality

此枚举值用于控制窗口的模态行为。对话框窗口大多为模态窗口。

常量 描述
Qt.NonModal 0 窗口为非模态,不阻塞其他窗口的输入
Qt.WindowModal 1 窗口对单个窗口结构层次为模态,阻塞对其父窗口(及其的兄弟窗口)、祖父窗口(及其兄弟窗口)的输入
Qt.ApplicationModal 2 窗口对应用程序为模态,阻塞对所有窗口的输入

###WindowType

此枚举值用于为控件指定各种窗口系统(window-system)属性。它们一般比较少见,但在少数情况下是必要的。其中一些标志取决于底层窗口管理器是否支持。

主要类型包括:

常量 描述
Qt.Widget 0x00000000 QWidget 的默认类型。这种类型的控件如果有父控件则作为子控件,若没有父控件则为独立窗口。参见 Qt.Window 和 Qt.SubWindow。
Qt.Window 0x00000001 表示该控件是一个窗口,不管该控件是否有父控件,一般带有一个窗口系统框架和一个标题栏。注意如果控件没有父对象,则无法取消设置此标志。
Qt.Dialog 0x00000002 | Window 表示该控件是一个应装饰为对话框的窗口(即,一般在标题栏中没有最大化最小化按钮)。这是QDialog 的默认类型。如果想用它作为模态对话框,它应该从另一个窗口启动,或者有父窗口并与QWidget.windowModality 属性一起使用。如果将其设置为模态,对话框将阻止应用程序中的其他顶级窗口获得任何输入。我们将具有父控件的顶级窗口称为次要窗口(secondary window)。
Qt.Sheet 0x00000004 | Window 表示窗口是 macOS 上的 sheet。由于使用sheet 意味着窗口模式,因此推荐的方法是使用QWidget.setWindowModality() 或QDialog::open() 替代。
Qt.Popup 0x00000008 | Window 表示该控件是一个弹出式顶级窗口,即它是模态的,但具有适合弹出式菜单的窗口系统框架。
Qt.Tool Popup | Dialog 表示该控件是一个工具窗口。工具窗口通常是一个小窗口,具有比一般窗口更小的标题栏和装饰,一般用于工具按钮的集合。如果有父控件,则工具窗口将始终保留在其顶部。如果没有父级,也可以考虑使用Qt.:WindowStaysOnTopHint。如果窗口系统支持,工具窗口可以用更轻量的框架来装饰。它也可以与 Qt.:FramelessWindowHint 结合使用。在 macOS 上,工具窗口对应于窗口的NSPanel 类。这意味着窗口位于普通窗口之上,因此无法在其上层放置普通窗口。默认情况下,当应用程序处于非活动状态时,工具窗口将消失。这可以通过Qt.WA_MacAlwaysShowToolWindow 属性来控制。
Qt.ToolTip Popup | Sheet 表明该控件是工具提示。这在内部用于实现工具提示。
Qt.SplashScreen ToolTip | Dialog 表明该窗口是闪屏(splash screen)。这是QSplashScreen 的默认类型。
Qt.SubWindow 0x00000012 表明此控件是子窗口,例如QMdiSubWindow 控件。
Qt.ForeignWindow 0x00000020 | Window 表明此窗口对象是一个句柄,表示由另一个进程或手动使用本地代码创建的本地平台窗口。
Qt.CoverWindow 0x00000040 | Window 表示该窗口代表一个覆盖窗口,在某些平台上最小化应用程序时显示。

还有许多标志可用于自定义顶级窗口的外观。这对其他窗口没有影响:

常量 描述
Qt.MSWindowsFixedSizeDialogHint 0x00000100 在微软 Windows 上为窗口提供一个细对话框边框。这种风格传统上用于固定大小的对话框。注意:不建议在多显示器环境中使用此标志,因为系统将强制窗口在跨屏幕移动时保持其原始大小,这在使用具有不同分辨率的显示器时尤其不受欢迎。
Qt.MSWindowsOwnDC 0x00000200 在微软 Windows 上为窗口提供自己的显示上下文。
Qt.BypassWindowManagerHint 0x00000400 此标志可用于向平台插件指示应禁用”所有”窗口管理器协议。根据应用程序运行的操作系统和窗口管理器运行的情况,该标志的行为会有所不同。该标志可用于获取未设置配置的本机窗口。
Qt.X11BypassWindowManagerHint BypassWindowManagerHint 完全绕过窗口管理器。这会导致一个完全不受管理的无边框窗口(即,除非手动调用QWidget.activateWindow(),否则没有键盘输入)。
Qt.FramelessWindowHint 0x00000800 生成无边框窗口。用户不能通过窗口系统移动或调整无边框窗口的大小。在 X11 上,标志的结果取决于窗口管理器及其理解 Motif 和/或 NETWM 的能力。大多数现有的现代窗口管理器都可以处理这个问题。
Qt.NoDropShadowWindowHint 0x40000000 禁用在支持的平台上的窗口投影。
Qt.CustomizeWindowHint 0x02000000 关闭默认窗口标题 hints。
Qt.WindowTitleHint 0x00001000 为窗口添加标题栏。
Qt.WindowSystemMenuHint 0x00002000 为窗口添加系统菜单,很可能是一个关闭按钮。如果想要隐藏/显示关闭按钮,更好的做法是使用WindowCloseButtonHint。
Qt.WindowMinimizeButtonHint 0x00004000 为窗口添加最小化按钮。在某些平台上,这意味着 WindowSystemMenuHint 也已生效。
Qt.WindowMaximizeButtonHint 0x00008000 为窗口添加最大化按钮。在某些平台上,这意味着 WindowSystemMenuHint 也已生效。
Qt.WindowMinMaxButtonsHint WindowMinimizeButtonHint | WindowMaximizeButtonHint 为窗口添加最大化、最小化按钮。在某些平台上,这意味着 WindowSystemMenuHint 也已生效。
Qt.WindowCloseButtonHint 0x08000000 为窗口添加关闭按钮。在某些平台上,这意味着 WindowSystemMenuHint 也已生效。
Qt.WindowContextHelpButtonHint 0x00010000 为对话框添加上下文帮助按钮。在某些平台上,这意味着 WindowSystemMenuHint 也已生效。
Qt.MacWindowToolBarButtonHint 0x10000000 在 macOS 上添加一个工具栏按钮(即,在有工具栏的窗口的右上方的椭圆形按钮)
Qt.WindowFullscreenButtonHint 0x80000000 在 macOS 上添加一个全屏按钮
Qt.BypassGraphicsProxyWidget 0x20000000 如果父控件已经嵌入,则阻止窗口及其子窗口自动将自己嵌入到 QGraphicsProxyWidget 中。如果希望控件始终是桌面上的顶级控件,则可以设置此标志,无论父控件是否已嵌入场景中。
Qt.WindowShadeButtonHint 0x00020000 如果底层窗口管理器支持,则添加一个阴影按钮替代最小化按钮。
Qt.WindowStaysOnTopHint 0x00040000 通知窗口系统该窗口应位于所有其他窗口之上。注意,在某些基于 X11 的窗口管理器上,还必须传递 Qt.X11BypassWindowManagerHint 才能使此标志正常工作。
Qt.WindowStaysOnBottomHint 0x04000000 通知窗口系统该窗口应位于所有其他窗口之下。
Qt.WindowTransparentForInput 0x00080000 通知窗口系统该窗口仅用于输出(显示某些内容)而不接受输入。因此输入事件应该像不存在一样略过。
Qt.WindowOverridesSystemGestures 0x00100000 通知窗口系统该窗口实现了自己的一组手势,系统级的手势(例如三指切换屏幕)应当被禁用。
Qt.WindowDoesNotAcceptFocus 0x00200000 通知窗口系统该窗口不接受输入焦点。
Qt.MaximizeUsingFullscreenGeometryHint 0x00400000 通知窗口系统在最大化窗口时应尽可能多地使用可用的屏幕几何空间,包括可能被UI覆盖的区域(例如状态栏或应用程序启动器)。这可能会导致窗口被置于这些系统UI之下,具体情况取决于平台是否支持。启用该标志后,用户负责将QScreen.availableGeometry() 也考虑在内,以便应用程序中需要用户交互的任何UI元素都不会被系统UI覆盖。
Qt.WindowType_Mask 0x000000ff 用于从窗口标志中提取窗口类型的掩码。

模块简介

PySide是Qt在Python的绑定,是将C++开发环境下的Qt移植到Python环境下。由于Python 语句简单,用Python语言开发Qt应用程序就变得相对容易。

下面内容是PySide几个主要模块的简介,其中 QtWidgets、QtCore和QtGui 是基本模块,开发GUI时都会用这三个模块,其他模块是扩展模块。模块有 QtWidgets、QtCore、QtGui,QtWebEngineWidgets、QtChart、QtMultimedia、QtSql 和 QtPrintSupport。

  • QtWidgets是窗口模块,提供窗口类和窗口上的各种控件(按钮、菜单、输人框、列表框等)类。
  • QtCore 是核心模块,是其他模块的应用基础,包括五大模块:元对象系统、属性系统、对象模型、对象树、信号与槽。QtCore 模块涵盖了 PySide 核心的非 GUI 功能,此模块被用于处理程序中涉及的时间、文件、目录、数据类型、文本流、链接、MIME.线程或进程等对象。
  • QtGui 模块涵盖多种基本图形功能的类,包括事件处理、2D图形、基本的图像和字体文本等。
  • QtSql模块提供了常用关系型数据库的接口和数据库模型,方便读写数据库中的数据。
  • QtMultimedia 模块包含处理多媒体事件的类库,通过调用API接口访问摄像头、语音设备,播放音频和视频,录制音频和视频及拍照等。
  • QtChart 和QtDataVisualization 模块用于数据可视化,可以绘制二维和三维数据图表。
  • QtPrintSupport 模块提供打印支持,能识别系统中安装的打印机并进行打印,可以对打印参数进行设置,提供打印对话框和打印预览对话框。
  • QtBluetooth 模块包含了处理蓝牙的类库,它的功能包括扫描设备、连接、交互等。QtNetwork 模块包含用于网络编程的类库,这组类库通过提供便捷的TCP/IP及UDP的c/s程式码集合,使得网络编程更容易。
  • QtWebEngine 和 QtWebEngineWidgets 模块借助开源的Chromium浏览器,在应用程序中嵌入 Web 浏览功能。
  • QtXml模块包含了用于处理XML的类库,提供实现SAX和DOMAPI的方法。· QtOpenGL、QtOpenGLFunctions 和 QtOpenGLWidgets 模块使用OpenGL 库来渲染3D和2D图形,该模块使得Qt GUI库和OpenGL库无缝集成。
  • QtDesigner模块可以为Qt Designer 创建白定义控件。
  • QtSvg 模块为显示矢量图形文件的内容提供了函数。
  • QtTest模块包含了可以通过单元测试调试PySide应用程序的功能。
  • QtStateMachine 模块可以创建和执行状态图。
  • QtHelp 模块可以为应用程序集成在线帮助。
  • QtConcurrent 模块支持多线程程序。
  • Qt3DCore、Qt3DInput、Qt3DRender、Qt3DAnimation、Qt3DLogic、Qt3DExtras等模块提供三维渲染、三维实时动画。

QWidget窗口的创建

PySide6的窗口类主要有三种,分别为QWidget、QMainWindow 和QDialog,其中QMainWindow 和 QDialog 从QWidget类继承而来。要创建和显示窗口,需要用这3个类中的任意一个类实例化对象,并让窗口对象显示并运行起来。窗口类在PySide6的QtWidgets 模块中,使用窗口类之前,需要用”from PySide6.QtWidgets import QWidget,QMainWindow,QDialog”语句把它们导人进来。

下面的代码创建一个空白的QWidget 窗口,读者需要理解这段代码,这是整个PySide6

可视化编程最基础的知识。

1
2
3
4
5
6
7
8
9
import sys
from PySide6.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv) # 创建应用程序实例对象
myWindow = QWidget() # 创建窗口实例对象
myWindow.show() # 显示窗口
n = app.exec() # 执行 exec()方法,进入事件循环,若遇到窗口退出命令,返回整数工
sys.exit(n) # 通知Python系统,结束程序运行

1.第1行导入系统模块sys,这个系统模块是指Python系统,而不是操作系统。
2.第2行导入QApplication 类和 QWidget 类,PySide6 的类都是以大写字母”Q”开始。
3.第4行创建OAnnlicatinn 类的实例对象ann.为窗口的创建进行初始化、其中svs.
4.argv是字符串列表,记录启动程序时的程序文件名和运行参数,可以通过print(sys.argv)函数输出sys.argv的值,sys.argv的第1个元素的值是程序文件名及路径,也可以不输入参数sys.argv 创建 QApplication 实例对象app。QApplication可以接受的两个参数是-nograb 和-dograb,-nograb告诉Python禁止获取鼠标和键盘事件,dograb则忽略-nograb选项功能,而不管-nograb参数是否存在于命令行参数中。一个程序中只能创建一个QApplication 实例,并且要在创建窗口前创建。
5.第5行用不带参数的QWidget 类创建QWidget 窗口实例对象myWindow,该窗口是独立窗口,有标题栏。
6.第6行用show()方法显示窗口,这时窗口是可见的。
7.第7行执行QApplication实例对象的exec()方法,开始窗口的事件循环,从而保证窗口一直处于显示状态。如果窗口上有其他控件,并为控件的消息编写了处理程序,则可以完成相应的动作。如果用户单击窗口右上角的关闭窗口按钮×正常退出界面,或者因程序崩溃而非正常终止窗口的运行,都将引发关闭窗口(closeA1lWindows())事件,这时app的方法exec()会返回一个整数,如果这个整数是0表示正常退出,如果非0表示非正常退出。请注意,当执行到app的exec()方法时,会停止后续语句的执行,直到所有可视化窗体都关闭(退出)后才执行后续的语句。需要注意的是,还有一个与exec()方法功能相同的方法exec_(),但exec_()方法已过时。
8.第8行调用系统模块的exit()方法,通知Python解释器程序已经结束,如果是sys.exit(0)状态,则Python 认为是正常退出;如果不是sys.exit(0)状态,则Python 认为是非正常退出。无论什么情况,sys.exit()都会抛出一个异常SystemExit,这时可以使用try…except语句捕获这个异常,并执行except中的语句,例如清除程序运行过程中的临时文件;如果没有try…except语句,则 Python解释器终止 sys.exit()后续语句的执行。第7行和第8行可以合并成一行sys.exit(app.exec())来执行。运行上面的程序,会得到一个窗口,这还只是一个空白窗口,在窗口上没有放置任何控件。
9.第78行可以这么简写sys.exit(app.exec())

在PyQt中使用qrc/rcc资源系统

本文摘自在PyQt中使用qrc/rcc资源系统 - muzing的杂货铺

Qt 资源系统简介

Qt 资源系统(The Qt Resource System)是一种独立于平台的资源管理器,用于在应用程序的可执行文件中存储二进制文件。对 PyQt 而言,这意味着在 Python 代码中直接以二进制形式存储图标、QSS、长文本翻译等资源文件。使用Qt 资源管理系统可以有效防止资源文件丢失,对于需要打包发布 的 PyQt 程序尤其实用。

在项目中使用Qt 资源系统,大致分为三个步骤:编写 .qrc 文件、使用rcc 编译资源、导入与使用。下文将一一详细讲解。

qrc 文件

简介与示例

Qt 资源集合文件(Qt Resource Collection File)一般以 .qrc 作为扩展名保存,故简称 .qrc 文件。其文件格式基于XML,用于将文件系统(硬盘)中的资源文件与 Qt 应用程序关联起来。.qrc 还可以实现为资源分组、设置别名等功能。

下面是一个简单的例子:

Resources 目录下包含图标、关于文档等资源文件。

1
2
3
4
5
6
7
8
$ tree Resources
Resources
├── Icons
│   ├── Py2exe-GUI_icon_72px.png
│   └── Python_128px.png
├── Texts
│  └── About_zh.md
└── resources.qrc

在此处新建一个 resources.qrc 文件,内容如下:

1
2
3
4
5
6
7
8
<!DOCTYPE RCC>
<RCC>
<qresource>
<file>Icons/Py2exe-GUI_icon_72px.png</file>
<file>Icons/Python_icon.ico</file>
<file>Texts/About_zh.md</file>
</qresource>
</RCC>

注意文件的相对路径是以 .qrc 所在的目录 Resources\ 为根目录开始计算的。

这样便建立了硬盘上文件系统中原文件与 Qt 资源系统中资源路径之间的联系。

使用前缀进行分组

在文件系统中,可以通过目录对不同类型的资源进行分组。在上面的例子中,图标文件都在 Icons/ 目录下,而长文本在 Texts/ 下。在 .qrc 中,也可以通过指定 <qresource> 标签的 prefix 属性来对资源进行分组:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE RCC>
<RCC>
<qresource prefix="icons">
<file>Icons/Py2exe-GUI_icon_72px.png</file>
<file>Icons/Python_icon.ico</file>
</qresource>
<qresource prefix="texts">
<file>Texts/About_zh.md</file>
</qresource>
</RCC>

为资源创建别名

有些资源的文件名很长,每次使用时都输入完整文件名较为繁琐。可以通过在 <file> 标签中添加 alias 属性为其创建别名,方便未来在资源路径中使用:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE RCC>
<RCC>
<qresource prefix="icons">
<file alias="Py2exe-GUI_icon">Icons/Py2exe-GUI_icon_72px.png</file>
<file alias="Python_icon">Icons/Python_icon.ico</file>
</qresource>
<qresource prefix="texts">
<file alias="About_Text">Texts/About_zh.md</file>
</qresource>
</RCC>

使用rcc 编译资源

rcc 简介

Qt 提供了Resource Compiler 命令行工具(简称 rcc),用于在构建过程中将资源嵌入 Qt 应用程序。对于 PyQt.也有对应版本的 rcc 工具,用于将 .qrc 中指定的资源文件数据编译至 Python 对象。

rcc 的安装与基本使用

当通过 pip 安装 PySide6 或其他 PyQt 时,会同时自动安装对应版本的 rcc 工具。这些工具的调用命令有所不同(详见下表),但使用方式与功能是一致的。激活已安装 PyQt 的 Python 虚拟环境,在命令行(注意不是 Python 交互式解释器)中输入对应的 rcc 命令即可。

平台 rcc 命令名称
PySide6 pyside6-rcc
PyQt5 pyrcc5
PySide2 pyside2-rcc
PyQt6 不提供

使用PySide6 提供的 pyside6-rcc 工具编译出的 .py 文件,也可以放入 PyQt6 项目中使用,只需将文件开头的 from PySide6 import QtCore 替换为 from PyQt6 import QtCore 即可。

例如,对于 PySide6,在命令行调用命令

1
pyside6-rcc -o compiled_resources.py resources.qrc

即可将 resources.qrc 中列出的资源文件编译到输出文件 compiled_resources.py 中。

rcc 命令行选项

此处以 pyside6-rcc 6.4.1 为例,列出了完整的选项列表(翻译版):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$ pyside6-rcc --help
Usage: /path/to/your/python3/site-packages/PySide6/Qt/libexec/rcc[options]inputs
Qt Resource Compiler version 6.4.1

Options:
-h, --help 显示关于命令行选项的帮助

--help-all 显示包括Qt独有选项在内的所有帮助

-v, --version 显示版本信息

-o, --output <file> 将输出写入到 <file> 中,而不是 stdout 中

-t, --temp <file> 为大资源文件使用临时文件 <file>

--name <name> 用<name> 创建一个外部初始化函数

--root <path> 用根目录 <path> 作为资源访问路径的前缀

--compress-algo <algo> 使用<algo> 算法压缩输入文件([zlib], none)

--compress <level> 按 <level> 级别压缩输入文件

--no-compress 禁用所有压缩,等同于 --compress-algo=none

--no-zstd 禁止使用zstd 压缩

--threshold <level> 衡量是否值得进行压缩的阈值

--binary 输出一个作为动态资源使用的二进制文件

-g, --generator <cpp|python|python2> 选择生成器

--pass <number> Pass number for big resources

--namespace 关闭命名空间宏

--verbose 启用verbose 模式

--list 只列出 .qrc 文件条目,不生成代码

--list-mapping 只输出 .qrc 中定义的资源路径与文件系统路径的
映射,不生成代码

-d, --depfile <file> 向 <file> 中写入一个包含 .qrc 依赖项的 depfile

--project 输出一个包含当前目录下所有文件的资源文件

--format-version <number> 写入 RCC 格式的版本

Arguments:
inputs 输入文件(*.qrc)

编译出的 Python 文件

运行成功后,在 .qrc 中声明的所有资源文件都已经被编译到 compiled_resources.py 这个 Python 文件中,不妨打开查看其内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 以下为 compiled_resources.py 文件中内容

# Resource object code(Python 3)
# Created by: object code
# Created by: The Resource Compiler for Qt version 6.4.1
# WARNING! All changes made in this file will be lost!

from PySide6 import QtCore

qt_resource_data = b"......"

qt_resource_name = b"......"

qt_resource_struct = b"......"

def qInitResources():
QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)

def qCleanupResources():
QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)

qInitResources()

最上方的注释标明了该文件由与 Qt6.4.1 版本匹配的资源编译器生成。并警告用户不要直接编辑该文件,因为所有修改都会被下一次编译操作覆盖掉。

接下来是三段长长的二进制编码字符串,其中正是资源文件:

  • qt_resource_data - 资源文件内容数据
  • qt_resource_name - 资源文件名称
  • qt_resource_struct - 资源结构

还有两个函数 qInitResources()qCleanupResources(),分别对应向 Qt 中注册资源与清理资源。

代码的最后一行调用了注册资源函数。

在主程序中使用

对于 PyQt 程序,从「直接加载使用资源文件」切换到「使用Qt 资源系统读取资源」,还需要如下步骤:

1.在主程序中导入编译后的资源
2.用「资源路径」替换「文件路径」
3.由使用Python 内置 open() 函数改为使用Qt 中QFile 类或QDir 类提供的 open() 方法

导入编译后的资源

在主程序中添加 import 导入语句,将刚才获得的 compiled_resources.py 导入:

1
import compiled_resources  # type: ignore

因为 import 的过程会执行该模块中的所有代码,也就自动调用了 qInitResources() 函数,完成了资源的注册与加载。

PyCharm 等 IDE 可能将此行代码判断为 “未使用的 import 语句” 而提示一个弱警告。可以通过在该行末尾添加特殊的 # type: ignore 注释来显式告知静态检查器忽略此行,消除这种不必要的警告。

资源路径

对于直接使用资源原文件,会使用其在文件系统中的路径,例如

1
icon = QPixmap("Icons/Python_icon.ico")

而在 Qt 资源系统中使用,则需要将文件路径替换为「资源路径」。资源路径由 .qrc 文件决定。

对于最一般的情况,直接在文件名前添加 :/ 即可得到其资源路径:

1
2
3
<qresource>
<file>Icons/Python_icon.ico</file>
</qresource>
1
icon = QPixmap(":/Python_icon.ico")

对于有前缀进行分组的,则需要在文件名前添加 :/ prefix /作为资源路径:

1
2
3
<qresource prefix="icons">
<file>Icons/Python_icon.ico</file>
</qresource>
1
icon = QPixmap(":/icons/Python_icon.ico")

对于指定了别名的,可以直接使用别名:

1
2
3
<qresource prefix="icons">
<file alias="Py_ico">Icons/Python_icon.ico</file>
</qresource>
1
icon = QPixmap(":/icons/Py_ico")

读取资源文件

需要使用Qt 提供的QFileQDir 读取编译后的资源文件,而不再能使用Python 提供的 open() 函数等。

例如,一段从 Markdown 文件中读取应用程序”关于”文本的代码,使用直接读取原资源文件的写法如下:

1
2
3
4
5
def get_about_text():
about_file = open(../../Resources/About.md", "r", encoding="utf-8") # 调用Python内置的open()
about_text = about_file.read()
about_file.close()
return about_text

而使用Qt 资源系统后,需要修改为如下形式:

1
2
3
4
5
6
7
8
9
from PySide6.QtCore import QFile, QIODevice

def get_about_text():
# 使用Qt风格读取文本文件
about_file = QFile(":/texts/About_Text") # 使用Qt中的QFile类
about_file.open(QIODevice.ReadOnly | QIODevice.Text) # 打开文件
about_text = str(about_file.readAll(), encoding="utf-8") # 读取文件,并将 QBtyeArray 转为 str
about_file.close()
return about_text

对于图片,可以在创建QIconQImageQPixmap 对象时将直接资源路径作为参数传入:

1
icon = QPixmap(":/icons/Python_icon.ico")

在 IDE 中配置

在 PyCharm 中配置使用rcc

可以将 rcc 工具添加至 PyCharm 中,避免每次使用都需要输入繁琐的命令行。(目前版本的 PyCharm 中已经原生内置了对 pyrcc4pyside-rcc 的支持,但其他版本的 rcc 工具快捷使用仍需自行在「外部工具」中创建。)

打开 文件 -> 设置 -> 工具 -> 外部工具(File -> Settings -> Tools -> External Tools)

打开设置-工具-外部工具

然后创建工具。配置可以参考下图,仍然以 pyside6-rcc 为例:

在 PyCharm 中配置 rcc 工具

其中比较重要的是「工具设置」里面的三行配置:

1
2
3
程序:        
PyInterpreterDirectory


/pyside6-rcc
实参: -o compiled_ FileNameWithoutExtension .py FileName
工作目录: FileDir

其中凡是以一对 $ 包裹的字符,均为 PyCharm 提供的宏,分别代表「Python 解释器目录」、「不带扩展名的文件名」、「文件名」和「文件所在目录」。

完成配置后,在待编译的 .qrc 文件上打开右键菜单,找到「外部工具 - pyside6-rcc」,点击即可运行,非常方便。

在右键菜单中使用pyside6-rcc外部工具

使用VS Code 编辑 qrc

安装Qt for Python 插件后,VS Code 编辑器会对 .qrc 文件提供一定的语法高亮、亦可一键编译。

1
2
# VS Code 插件安装命令:
ext install seanwu.vscode-qt-for-python

Qt for Python 插件提供了丰富的功能

使用QtCreator 编辑 qrc

此小节参考自 https://blog.csdn.net/anbuqi/article/details/120455219

直接在文本编辑器中以 XML 形式编写复杂的 .qrc 文件时,较为繁琐、易出错,可以考虑安装 Qt 官方的QtCreater IDE 来生成 .qrc 文件。

1
2
3
4
5
6
7
$ tree resource
resource
├── icon
│   ├── ic_last_step.svg
│   ├── ic_next_step.svg
│   └── ic_start.svg
└── res.qrc

首先启动 QtCreater,在 resource/ 目录中新建 res.qrc 文件:

创建qrc文件与添加图标路径

然后以 icon 前缀创建一个分组:

添加前缀

接着用Add Files 按钮把图标文件添加进来,并保存:

将图标文件添加到路径中

此时得到了 res.qrc:

1
2
3
4
5
6
7
<RCC>
<qresource prefix="/icon">
<file>icon/ic_last_step.svg</file>
<file>icon/ic_next_step.svg</file>
<file>icon/ic_start.svg</file>
</qresource>
</RCC>

为了缩短引用路径,还可以为每个图标文件设置别名(alias):

设置别名

现在得到这样的 res.qrc:

1
2
3
4
5
6
7
<RCC>
<qresource prefix="/icon">
<file alias="ic_last_step">icon/ic_last_step.svg</file>
<file alias="ic_next_step">icon/ic_next_step.svg</file>
<file alias="ic_start">icon/ic_start.svg</file>
</qresource>
</RCC>

进阶话题

国际化多语言

有时应用程序需要在不同的语言环境下使用不同的文件,可以通过设置 lang 属性来轻松实现。下面是一个例子:

1
2
3
4
5
6
<qresource>
<file>cut.jpg</file>
</qresource>
<qresource lang="fr">
<file alias="cut.jpg">cut_fr.jpg</file>
</qresource>

当系统语言为其他语言时,Qt 程序将会使用文件 cut.jpg;而当系统语言为法语时,会自动替换为 cut_fr.jpg

压缩

rcc 会尝试压缩内容以优化硬盘空间使用。默认情况下,它将进行启发式检查以确认是否值得压缩。如果不能充分压缩,则将直接存储非压缩的内容。可以使用-threshold选项控制此判断的阈值。例如,默认情况下阈值为 70,表示只有在压缩后的文件比原文件小 70%(不超过原文件大小的 30%)时才有必要压缩。

1
rcc -threshold 25 myresources.qrc

在某些情况下也可以关闭压缩功能。一种常见情况是,某些资源已经是压缩后的格式(例如 .png 文件),再次压缩几乎不会进一步减小文件体积,但会占用CPU 成本。另一种情况是,硬盘空间非常充裕,期望应用程序在运行时可以将内容存储在干净的内存页中。在命令行中添加 -no-compress 命令以关闭压缩。

1
rcc -no-compress myresources.qrc

还可以控制 rcc 使用的压缩算法与压缩级别,例如:

1
rcc -compress 2 -compress-algo zlib myresources.qrc

表示使用zlib 压缩算法,压缩等级为 2。

除了在命令行调用rcc 时指定选项,还可以在 .qrc 文件中控制阈值、压缩算法与压缩等级:

1
2
3
<qresource>
<file compress="1" compress-algo="zstd">data.txt</file>
</qresource>

rcc 具体支持的压缩算法类型与压缩等级,参见官方文档

参考资料

1.Qt6 官方文档:The Qt Resource System
2.Qt6 官方文档:Resource Compiler(rcc)
3.Qt for Python 官方教程:Using .qrc Files(pyside6-rcc)
4.pyside6(1):Qt 资源系统和qrc文件使用
5.Stack Overflow: How can resources be provided in PyQt6(which has no pyrcc)?

信号与槽

信号与槽概念

对于可视化编程,需要将界面上的控件有机结合起来,实现控件功能的联动和交互操作。

通过信号(signal)与槽(slot)机制实现的交互功能。

信号与槽是PySide6编程的基础,也是Qt的一大创新,有了信号与槽的编程机制,在PySide6中处理界面上各个控件的交互操作时变得更加直观和简单。

信号是指从QObject类继承的控件(窗口、按钮、文本框、列表框等)在某个动作下或状态发生改变时发出的一个指令或一个信息

例如一个按钮被单击(clicked)、右击一个窗口(customContextMenuRequested)、一个输入框中文字的改变(textChanged)等

当这些控件的状态发生变化或者外界对控件进行输人时,让这些控件发出一个信息,来通知系统其某种状态发生了变化或者得到了外界的输入,以便让系统对外界的输人进行响应。

槽是系统对控件发出的信号进行的响应,或者产生的动作,通常用函数来定义系统的响应或动作。

例如对于单击”计算”按钮,按钮发出被单击的信号,然后编写对应的函数,当控件发出信号时,就会自动执行与信号关联的函数。

信号与槽的关系可以是一对一,也可以是多对多,即一个信号可以关联多个槽函数,一个槽函数也可以接收多个信号。PySide6已经为控件编写了一些信号和槽函数,使用前需要将信号和槽函数进行连接,另外用户还可以自定义信号和自定义槽函数。

重载型信号的处理

重载型信号连接

查询控件的信号时,会发现有些控件有多个名字相同但是参数不同的信号。

例如对于按钮有clicked()和 clicked(bool)两种信号,一种不需要传递参数的信号,另一种传递布尔型参数的信号。

这种信号名称相同、参数不同的信号称为重载(overload)型信号。

对于重载型信号定义自动关联槽函数时,需要在槽函数前加修饰符@Slot(type)声明是对哪个信号定义槽函数,其中type是信号传递的参数类型。

例如如果对按钮的clicked(bool)信号定义自动关联槽函数,需要在槽函数前加入@Slot(bool)进行修饰;如果对按钮的clicked()信号定义自动关联槽函数,需要在槽函数前加人@Slot()进行修饰。

需要注意的是,在使用@Slot(type)修饰符前,应提前用from PySide6.QtCore import Slot语句导人槽函数。

定义一个信号后就有连接connect()、发送emit()、断开disconnect()属性

重载型信号断开

已连接的信号非重载类型的直接使用signaName.disconnect()断开连接即可

重载类型的使用signaName[type].disconnect()断开连接

手动关联内置信号的自定义槽函数

除了使用控件内置信号定义自动连接的槽函数外,还可以将控件内置信号手动连接到其他函数上,这时需要用到信号的 connect()方法。

btnCalculate.clicked.connect(self.method)语句将按钮的单击信号clickedmethod()函数进行连接

也可以在主程序中,在消息循环语句前用myWindow.ui.btnCalculate.clicked.connect(myWindow.method)语句进行消息与槽函数的连接

基类QObject

QObject是所有的Qt对象的基类,所有的对象都是直接或者间接的继承自QObject

对象名称,属性

API

方法 说明
setObjectName(“唯一名称”) 给一个Qt对象设置一个名称``一般这个名称是唯一的,当做对象的ID来使用
objectName() 获取一个Qt对象的名称
setProperty(“属性名称”,值) 给一个Qt对象动态的添加一个属性与值
property(“属性名称”) 获取一个对象的属性值
dynamicPropertyNames() 获取一个对象中所有通过setProperty()设置的属性名称

应用场景

  • 用于qss的ID选择器,属性选择器,方便统一设置样式

    QObject.qss

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    QLabel#notice {
    font-size: 20px;
    color: gray;
    border: 1px solid gray;
    border-radius: 8px;
    }
    QLabel#notice[notice_level="normal"]{
    color: green;
    border-color: green;
    }
    QLabel#notice[notice_level="warning"]{
    color: yellow;
    border-color: yellow;
    }
    QLabel#notice[notice_level="error"]{
    color: red;
    border-color: red;
    }
  • 用于装饰器的信号与槽

父子对象操作

API

方法 说明
setParent(parent) 设置父对象,父对象只能设置一个
parent() 获取父对象
children() 获取所有直接子对象,不包括间接的子对象如孙子辈的
findChild(参数1, 参数2, 参数3) 获取某一个指定名称和类型的子对象
1
参数1:QObject对象或者多个QObject对象元组

1
参数2:setProperty设置的属性名称,可以省略

1
参数3:查找选项,有两个可选

Qt.FindChildrenRecursively(递归查找,默认选项)/Qt.FindDirectChildrenOnly(只查找直接子对象) |

应用场景

内存管理机制

当创建一个QObject时,如果使用了其他对象作为其父对象 那么,它就会被添加到父对象的children()列表中.当父对象被销毁时,这个QObject也会被销毁

  • 涉及到Qt对象内存管理机制
  • 如果一个控件,没有任何父控件,那么就会被当成顶层控件(窗口)
  • 如果想要一个控件被包含在另外一个控件内部,就需要设置父子关系

顶层控件

如果一个控件,没有任何父控件,那么就会被当成顶层控件(窗口)

多个顶层窗口相互独立

如果想要一个控件被包含在另外一个控件内部,就需要设置父子关系

  • 显示位置受父控件约束
  • 生命周期也被父对象接管

案例

1.创建两个独立的窗口

要求

设置不同的标题
社会我顺哥
人狠话不多
涉及知识点
创建窗口
设置窗口标题
掌握级别
了解如果创建控件没有设置任何父对象, 会有什么效果

2.创建一个窗口, 包含另外两个子控件QWidget

要求

两个子控件必须在同一个窗口内部
涉及知识点
控件的父子关系
掌握级别
掌握给一个控件设置父控件的两种方式

3.创建一个窗口, 包含多个子控件QWidget和QLabel

要求

要求让所有的QLabel类型子控件都设置背景颜色为cyan
即使后续再增加新的QLabel子控件
涉及知识点
控件的父子关系设置
获取一个控件的子控件
样式设置
掌握级别
了解

信号处理

API

方法 说明
widget.信号方法.connect(槽函数) 连接信号与槽
obj.disconnect() 取消连接信号与槽
obj:可为空间或信号 控件:取消控件的所有信号连接 信号:取消指定信号的连接
widget.blockSignals(bool) 临时(取消)阻止指定控件所有的信号与槽的连接
widget.signalsBlocked() 信号是否被阻止
widget.receivers(信号) 返回连接到信号的接收器数量

应用场景

  • 监听信号, 响应用户行为
  • 信号与槽机制

案例

1.当用户点击按钮的时候, 打印”点我嘎哈?”

要求

用户点了按钮, 你就负责打印
涉及知识点
按钮创建, 设置
监听按钮点击的信号
掌握级别
了解信号监听部分

2.在所有修改的窗口标题前, 添加前缀”撩课-“

要求

比如, 后续我们修改标题为”Hello Sz”; 最终会自动变为”撩课-Hello Sz!”
支持多次修改
涉及知识点
设置窗口标题
监听窗口标题改变信号
临时取消/恢复信号与槽的连接
掌握级别
了解信号监听部分

类型判定

API

  • isWidgetType() 是否是控件类型 继承自QWidget类
  • inherits(父类) 一个对象是否继承(直接或者间接)自某个类

应用场景

过滤筛选控件

案例

1.创建一个窗口, 包含多个QLabel或其他控件

要求

将包含在窗口内所有的QLabel控件, 设置背景色cyan
涉及知识点
子控件获取
控件类型判定
样式设置
掌握级别
掌握控件判定部分

对象删除

obj.deleteLater()

删除一个对象时, 也会解除它与父对象之间的关系 deleteLater()并没有将对象立即销毁,而是向主消息循环发送了一个event,下一次主消息循环收到这个event之后才会销毁对象 这样做的好处是可以在这些延迟删除的时间内完成一些操作,坏处就是内存释放会不及时

想要移除某一个对象的时候使用,bu同于python的del方法,会删除对象对应的子组件

事件处理

API

方法 说明
childEvent()
customEvent()
eventFilter()
installEventFilter()
removeEventFilter
event()

应用场景

  • 事件机制
  • 拦截事件, 监听特定行为

定时器

API

方法 说明
startTimer(ms, Qt.TimerType) -> timer_id 开启一个定时器 Qt.TimerType Qt.PreciseTimer 精确定时器:尽可能保持毫秒准确 Qt.CoarseTimer 粗定时器:5%的误差间隔 Qt.VeryCoarseTimer 很粗的定时器:只能到秒级`` timer_id 定时器的唯一标识
killTimer(timer_id) 根据定时器ID,杀死定时器
timerEvent() 定时器执行事件

应用场景

  • 轮询
  • 倒计时

案例

1.创建一个窗口, 并设置一个子控件QLabel

要求

展示10s倒计时
倒计时结束, 就停止计时
涉及知识点
标签额创建和设置
自定义标签类的封装
定时器的使用
掌握级别
了解定时器基本操作

2.创建一个窗口, 通过定时器不断增加该窗口的尺寸大小

要求

每100ms 宽高均增加1px
涉及知识点
窗口控件的封装
定时器的使用
掌握级别
了解定时器

语言翻译

tr()

应用场景:多语言国际化支持

信号

新号 说明
objectNameChanged(objectName) 对象名称发生改变时发射此信号
destroyed(obj) 对象被销毁时, 发射此信号

QApplication

1
2
QApplication(self) -> None
QApplication(self, arg__1: Sequence[str]) -> None

在进行可视化编程时,无论出现几个窗口,都要创建一个而且只能创建一个QApplication类的实例对象,为窗口的正确显示提供基本的条件。

QApplication的实例对象代表整个运行程序,通过对QApplication实例对象的设置可以对整个应用程序进行设置。

QApplication类提供的方法如表所示,其中一些方法及参数在后续的内容中进行介绍。

需要注意的是,参数类型是以”Qt”开始的枚举类型时,需要用”from PySide6.QtCore import Qt”语句从 QtCore 模块中导入 Qt.例如 setEffectEnabled(Qt.UIEffect,enable=True)方法中,枚举类型Qt.UIEffect 是指 PySide6.QtCore.Qt中的枚举类型;Union[paral, para2…]是类型选择,表示可以从所列的类型中选择其中的一个数据类型作为参数。

QApplication方法一览

QApplication的方法及参数类型 返回值类型 说 明
[static]exec() int 进入消息循环,直到遇到 exit()命令
[static]quit() None 退出程序
[static]exit(retcode:int=0) None 退出程序,exec()的返回值是 retcode
[static]setQuitOnLastWindowClosed(bool) None 设置当最后一个窗口关闭时,程序是否退出, 默认是 True
setAutoSipEnabled(bool) None 对于接受键盘输入的控件,设置是否自动弹出 软件输人面板(software input panel),仅对需 要输入面板的系统起作用
autoSipEnabled() bool 获取是否自动弹出软件输入面板
setStyleSheet(sheet:str) None 设置样式表
styleSheet() str 获取样式表
[static]activeModalWidget() QWidget 获取带模式的活跃对话框
[static]activePopupWidget() QWidget 获取活跃的菜单
[static]activeWindow() QWidget 返回能接收键盘输入的顶层窗口
[static]alert(QWidget, duration: int=0) None 使非活跃的窗口发出预警,并持续指定的时间(毫秒)。如果持续时间为0,则一直发出预警, 直到窗口变成活跃的窗口
[static]allWidgets() List[QWidget] 获取所有的窗口和控件列表
[static]beep() None 发出铃响
[static]closeAllWindows() None 关闭所有窗口
[static]cursorFlashTime() int 获取光标闪烁时间
[static]setDoubleClickInterval(int) None 设置鼠标双击时间(毫秒)以区分双击和两次 单击
[static]doubleClickInterval() int 获取鼠标双击的时间间隔
[static]focusWidget() QWidget 获取接收键盘输人的有焦点的控件
[static]setFont(QFont) None 设置程序默认字体
[statie]font() QFont 获取程序的默认字体
[static]font(QWidget) QFont 获取指定控件的字体
[static]setEffectEnabled(Qt.UIEffect,enable=True) None 设置界面特效,Qt.UIEffect 可以取 Qt.UI_ AnimateMenu、Qt.UI_ FadeMenu、Qt.UI_ FadeTooltip、Qt.UI_ AnimateCombo、Qt.UI_ AnimateTooltip,Qt.UI_AnimateToolBox
[static]isEffectEnabled(Qt.UIEffect) bool 获取是否有某种特效
[static]keyboardInputInterval() int 获取区分两次键盘输人的时间间隔
[static]palette() QPalette 获取程序默认的调色板
[static]palette(QWidget) QPalette 获取指定控件的调色板
[static]setActiveWindow(QWidget) None 将窗口设置成活跃窗口以响应事件
[static]setCursorFlashTime(int) None 设置光标闪烁时间(毫秒)
[static]setEffectEnabled(Qt.UIEffect,enable: bool=True) None 设置界面特效
[static]setKeyboardInputInterval(int) None 设置区分键盘两次输人的时间间隔
[static]setPalelve(Union[QPalette, Qt.GlobalColor,QColor]) None 设置程序默认的调色板
[static]setStartDragDistance(int) None 设置拖拽动作开始时,光标的移动距离(像 素),默认值是10
[static]startDragDistance() int 获取拖拽起始时光标需移动的距离
[static]setStartDragTime(ms:int) None 设置拖拽动作开始时,鼠标按下的时间(毫 秒),默认是500
[static]startDragTime() int 获取从按下鼠标按键起到拖拽动作开始的 时间
[static]setStyle(QStyle) None 设置程序的风格
[static]style() QStyle 获取风格
[static]setWheelScrollL,ines(int) None 设置转动滚轮时,界面控件移动的行数,默认
[static]topLevelAt(QPoint) QWidget 是3 获取指定位置的顶层窗口
[static]topLevelAt(x:int,y: int) QWidget 获取指定位置的顶层窗口
[static]topLevelWidgets() List[QWidget] 获取顶层窗口列表,顶层窗口可能被隐藏
[static]widgetAt(QPoint) QWidget 获取指定位置的窗口
[static]widgetAt(x: int,y:int) QWidget 获取指定位置的窗口
[static]setApplicationDisplayName(str) None 设置程序中所有窗口标题栏上显示的名称
[static]setLayoutDirection(Qt.LayoutDirection) None 设置程序中的布局方向,Qt.LayoutDirection 可以取 Qt.LeftToRight、Qt.RightToLeft 或 Qt.LayoutDirectionAuto
[static]setOverrideCursor(Union[QCursor,Qt.CursorShape,QPixmap]) None 设置应用程序当前的光标
[static]overrideCursor() QCursor 获取当前的光标
[static]restoreOverrideCursor() None 恢复 set()verrideCursor()之前的光标设置,可 以多次恢复
[static]setWindowIcon(Union[QIcon,QPixmap]) None 为整个应用程序设置默认的图标
[static]windowIcon() QIcon 获取图标
Lstatic]setApplicationName(str) None 设置应用程序名称
[static]setApplicationVersion(str) None 设置应用程序的版本
[static]translate(context: bytes, key: bytes,disambiguation: bytes=None, n:int=-1) str 字符串解码,本地化字符串
Lstatic]postEvent(receiver:QObject, QEvent,Priority=Qt.EventPriority) None 将事件放入消息队列的尾端,然后立即返回, 不保证事件立即得到处理
Lstatic]sendEvent(receiver: QObject.QEvent) bool 用notify()函数将事件直接派发给接收者进行 处理,返回事件处理情况
[static]sendPostedEvents(receiver: QObject=None,event_type:int=0) None 将事件队列中用postEvent()函数放人的事件 立即分发
notify(QObject,QEvent) bool 把事件信号发送给接收者,返回接收者的 event()函数处理的结果
event(QEvent) bool 重写该方法,处理事件
[static]sync() None 处理事件使程序与窗口系统同步

例子

下同下面的程序创建两个窗口,通过QApplication的实例对象app为整个程序设置标题栏上的名称和图标,在第2个窗口上单击”响铃与预警”按钮,将会发出响铃,并使第一个窗口在任务栏上闪烁。

image-20230225015948793

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton
from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap


class myWidget(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.setupui()

self.button.clicked.connect(self.bell_alert)

def setupui(self):
self.setWindowTitle('Hello')
self.resize(300, 150)

self.label = QLabel(self) # 在窗口上创建标签
self.label.setText('欢迎学习pyside6编程!')
self.label.setGeometry(80, 50, 150, 20)

self.button = QPushButton(self)
self.button.setText("响铃与预瞥")
self.button.setGeometry(90, 100, 100, 20)

def bell_alert(self):
QApplication.beep() # 程序发出响铃声
QApplication.alert(win, duration=0) # 第2个窗口发出预警


if __name__ == "__main__":
app = QApplication(sys.argv)
app.setApplicationDisplayName("欢迎程序") # 设置所有窗口标题栏上显示的名称
app.setEffectEnabled(Qt.UIEffect.UI_AnimateCombo)
app.setWindowIcon(QPixmap(r'../../Resources/animal/m1.png')) # 为所有窗口设置图标

win = QWidget() # 创建第1个窗口
win.show()

myWindow = myWidget() # 用myWidget()创建第2个窗口
myWindow.show()

sys.exit(app.exec())

参数/单位类

坐标点类QPoint和QPointF

电脑屏幕的坐标系的原点在左上角,从左到右是x轴方向,从上往下是y轴方向。

要定位屏幕上的一个点的位置,需要用到QPoint类或QPointF类,这两个类的区别是QPoint用整数定义x和y值,QPointF用浮点数定义x和y值。

QPoint类和 QPointF类在QtCore 模块中,使用前需用from PySide6.QtCore import QPoint,QPointF语句导人到当前程序中。

用QPoint 和 QPointF 类定义坐标点实例的方法如下所示,其中xpos和ypos分别表示x和y坐标。

1
2
3
4
5
6
7
8
9
10
QPoint()
QPoint() -> None
QPoint(QPoint: PySide6.QtCore.QPoint) -> None
QPoint(xpos: int, ypos: int) -> None

QPointF()
QPointF() -> None
QPointF(QPointF: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint]) -> None
QPointF(p: PySide6.QtCore.QPoint) -> None
QPointF(xpos: float, ypos: float) -> None

QPoint 类和 QPointF 类的方法

方法及参数类型 说明
setX(int)
setX(float)
设置x坐标值
setY(int)
setY(float)
设置Y坐标值
x() 获取x坐标值
y() 获取Y坐标值
toTuple() 输出元组(x, y)
[static]dotProduct(p1: Union[QPointF, QPoint], p2: Union[QPointF, QPoint]) -->Union[int, float] 两个点的x和y坐标乘积之和,即x1* x2 + y1 * y2
isNull(self) -> bool 如果x=y=0则返回Ture
manhattanLength(self) -> float 返回x和y绝对值的和
transposed(self) -> QPointF/ QPoint 将x和y对调
toPoint(self) -> QPoint 用四舍五入把 QPointF转换成 QPoint

QPoint或 QPointF 可以当作二维向量,用于加减运算,也可以与一个整数或浮点数相乘或相除,还可以逻辑判断,例如下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from PySide6.QtCore import QPoint, QPointF

p1=QPoint(-3, 4)
p2=QPointF(5, 8)

print(QPoint.dotProduct(p1, p1), QPointF.dotProduct(p1, p2))

p3=p2 - p1

p4=p1 * 3

print(p3.x(), p3.y(), p4.x(), p4.y())
print(p1==p2, p1 !=p2)

"""
运算结果如下:
25 17.0
8.0 4.0 -9 12
False True
"""

尺寸类Qsize和QsizeF

一个控件或窗口有长度和高度属性,长度和高度可以用QSize类或QSizeF 类来定义

QSize 类和 QSizeF 类在 QtCore 模块中,使用前需用from PySide6.QtCore import QSize,QSizeF语句导人到当前程序中。

用QSize 和 QSizeF 定义尺寸实例的方法如下,其中w和h分别表示宽度或高度,QSize 用整数定义,QSizeF 用浮点数定义。

1
2
3
4
5
6
7
8
9
10
11
QSize():
QSize(self) -> None
QSize(QSize: PySide6.QtCore.QSize) -> None
QSize(w: int, h: int) -> None


QSizeF():
QSizeF(self) -> None
QSizeF(QSizeF: Union[PySide6.QtCore.QSizeF, PySide6.QtCore.QSize]) -> None
QSizeF(sz: PySide6.QtCore.QSize) -> None
QSizeF(w: float, h: float) -> None

QSize 和QSizeF 的方法基本相同

QSizeF的常用方法如表所示。

  • 主要方法是用setWidth(float)、setHeight(float)设置宽度和高度;用width()、height()方法获取宽度和高度。
  • scale(width:float, height: float,Qt.AspectRatioMode)方法中,Qt.AspectRatioMode 可以取以下:
    • Qt.IgnoreAspectRatio(不保持比例关系,缩放后的QSizeF尺寸(width,height))
    • Qt.KeepAspectRatio(保持原比例关系,缩放后的QSizeF 在(width,height)内部尽可能大)
    • Qt.KeepAspectRatioByExpanding(保持原比例关系,缩放后的QSizeF 在(width,height)外部尽可能小),参数值不同,返回的值也不同;
  • shrunkBy(Union[QMargins,QMarinsF])方法中,根据页边距 QMarginsQMarginsF指定的收缩距离,返回新的 QSizeF,QMargins QMarginsF
方法 返回值和类型 说明
setWidth(float)setHeight(float)
setWidth(int)setHeight(int)
None 设置宽和高
width()height() int / float 获取宽和高
shrunkBy(Union[QMargins,QMarginsF]) QSizeF 在原QSizeF 基础上根据页边距收缩得到新QSizeF
grownBy(Union[QMargins,QMarginsF])) QSizeF 在原QSizeF基础上根据页边距扩充得到新QSizeF
boundedTo(Union[QSize,QSizeF]) QSizeF 新QSizeF的高度是自己和参数的高度中值小的高度,宽度亦然
expandedTo(Union[QSize,QSizeF]) QSizeF 新QSizeF 的高度是自已和参数的高度中值大的高度,宽度亦然
toTuple() Tuple 返回元组(width,height)
isEmpty() bool 当宽度和高度有一个小于等于0时.返回值是True
isNull() bool 宽度和高度都是0时,返回值是 True
isValid() bool 当宽度和高度都大于等于0时,返回值是True
transpose() None 高度和宽度对换
transposed() QSizeF 新QSizeF的高度是原QSizeF的宽度,宽度是原QSizeF的高度
scale(width:loat, height:float, Qt.AspectRatioMode) None 根据高度和宽度的比值参数Qt.AspectRatioMode.重新设置原 QSizeF 的宽度和高度
scale(QSizeF,Qt.AspectRatioMode) None 根据高度和宽度的比值参数Qt.AspectRatioMode.重新设置原 QSizeF 的宽度和高度
scaled(width: float, height: float, Qt.AspectRatioMode) QSizeF 返回调整后的新 QSizeF
scaled(QSizeF,QAspectRatioMode) QSizeF 返回调整后的新 QSizeF
toSize() QSize 将QSizeF 转换成 QSize

QSize 和 QSizeF类也可以进行加减乘除运算和逻辑运算,例如下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from PySide6.QtCore import QSize, QSizeF, QMargins, Qt

s1=QSize(5, 6)
s2=QSizeF(8, 10)

s3=s2 - s1
print("s3:", s3.width(), s3.height())

s4=s1
print("s4:", s4.width(), s4.height())

margin=QMargins(1, 2, 3, 4)
s5=s2.shrunkBy(margin)
print("s5:", s5.width(), s5.height())

s1=QSize(5, 6)
ss=s1.scaled(10, 20, Qt.AspectRatioMode.IgnoreAspectRatio)
print("IgnoreAspectRatio:", ss.width(), ss.height())

ss=s1.scaled(10, 20, Qt.AspectRatioMode.KeepAspectRatioByExpanding)
print("KeepAspectRatioByExpanding", ss.width(), ss.height())

"""
s3: 3.0 4.0
s4: 5 6
s5: 4.0 4.0
IgnoreAspectRatio: 10 20
KeepAspectRatioByExpanding 16 20
"""

矩形框类QRect和QRectF

矩形框类QRect和QRectF

矩形框可以定义一个矩形区域,含有 QPoint 和QSize 信息的类形的左上角是QPoint 的信息,矩形框的宽度和高度是 QSize 信息。对于一个控件,在窗口中有位置宽度和高度信息,控件的位置可以通过其左上角的位置确定,控件的位置、宽度和高度都可以通过矩形框类来定义。

矩形框类分为 QRect 和 QRectF 两种它们在 QtCore 块中使用前需要用from PySide6.QtCore import QRect, QRectF语句导人到当前程序中。

用QRect 或 QRectF 类来定义矩形框实例对象,可以采用以下几种方法,其中 QRect用整数定义,QRectF 用浮点数定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
QRect:
QRect(self) -> None
QRect(QRect: PySide6.QtCore.QRect) -> None
QRect(left: int, top: int, width: int, height: int) -> None
QRect(topleft: PySide6.QtCore.QPoint, bottomright: PySide6.QtCore.QPoint) -> None
QRect(topleft: PySide6.QtCore.QPoint, size: PySide6.QtCore.QSize) -> None


QRectF:
QRectF(self) -> None
QRectF(QRectF: Union[PySide6.QtCore.QRectF, PySide6.QtCore.QRect]) -> None
QRectF(left: float, top: float, width: float, height: float) -> None
QRectF(rect: PySide6.QtCore.QRect) -> None
QRectF(topleft: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint], bottomRight: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint]) -> None
QRectF(topleft: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint], size: Union[PySide6.QtCore.QSizeF, PySide6.QtCore.QSize]) -> None

矩形框QRect类的常用方法如表所示:

用QRect或QRectF 定的矩形有4个角点 topLeft,topRight,bottomLeft、bottomRight,4 个边 left,right,top,bottom 和1 个中心 center 几何特征,通过一些方法可以获取或者移动角点位置、边位置或中心位置

方法 说明
setLeft(x),setRight(x) 设置左边 x值和y 值位置,上边和下边位置不变
setTop(y) 设置上边位置y值,左右和底边不变
setBottom(y) 设置底部值,真实底部值需要再加 1
setBottommLeft(QPoint) 设置左下角位置,右上角的位置不变
setBottomRight(QPoint) 设置右下角位置,左上角的位置不变
setCoords(xl,yl,x2,y2) 设置左上角坐标 x1y1和右下角坐标 x2y2真实右下角坐标需要横纵坐标都加1
getCoords() 返回左上角和右下角坐标元组(int,int,int,int),有下角的x和值都要减去 1
serWidth(w),setHeight(h) 设置宽度和高度,左上角的位置不变
setSize(QSize) 设置宽度和高度
size() 获取高度和宽度的 QSize
width(),height() 返回宽度值和高度值
setRect(x,y,w,h) 设置矩形框的左上角位置及宽度、高度
setTopLeft(QPoint) 设置左上角位置,右下角的位置不变
setTopRight(QPoint) 设置右上角位置,左下角的位置不变
setX(x) ,setY(y) 设置左上角的x值和y值,右下角的位置不变
x()、y() 返回左上角 x值和y值
bottomLeft(),bottomRight() 返回左下角 QPoint 和右下角 QPoint,y值是(底部 y一1)
center() 返回中心点QPoint
getRect() 返回左上角坐标和宽高元组(x,y,w,h)
isEmpty() 当宽度和高度有一个小于等于0时,返回值是 True
isNull() 当宽度和高度都是 0时,返回值是 True
isValid() 当宽度和高度都大于0时,返回值是True
adjust(xl,yl ,x2,y2) 调整位置,调整后的位置是在原左上角的x和分别加x1和y右下角的x和y分别加x2和y2
adjusted(xl,y1,x2 ,y2) 调整位置,并返回新的 QRect 对象
moveBottomLeft(QPoint) 移动左下角到QPoint,宽度和高度不变
moveBottomRight(QPoint) 移动右下角到QPoint,宽度和高度不变
moveCenter(QPoint) 移动中心到 QPoint,宽度和高度不变
moveLeft(x), moveRight(x) 移动左边到x值,右边到x+1值,宽度和高度不变
moveTo(QPoint, moveTo(x,y) 左上角移动到 QPoint 点或(x;)点,宽度和高度不变
moveTop(y), moveBottom(y) 移动上边到 y底部到 y+1值宽度和高度不
moveTopLeft(QPoint) 移动左上角到QPoint宽度和高度不变
moveTopRight(QPoint) 移动右上角到 QPoint,宽度和高度不变
left(), right() 返回左边 x 值和右边 x-1值
top(), bottom() 获取左上角的 y值和底部 y-1值
topLeft(), topRight() 获取左上角的QPoint 和右上角的 QPoint
intersected(QRect) 返回两个矩形的公共交叉矩形 QRect
intersects(QRect) 判断两个矩形是否有公共交叉矩形
united(QRect) 返回由两个矩形的边形成的新矩形
translate(dx,dy) 矩形框整体平移 dx, dy
translate(QPoint) 矩形框整体平移QPoint,x() QPoint.y()
translated(dx,dy) 返回平移 dx和 dy 后的新 QRect
translated(QPoint) 返回平移 QPoint.x()和 QPoint,y()后的新 QRect
transposed() 返回宽度和高度对换后的新 QRect

用表中的方法获取右边线、底边线、右下角左下角和右上角的坐标值时,如下图所示,右下角的 x 值和值返回值比真实值都小1右边线和底边线比真实值都小1。

在算右下角的坐标时,可以用rect.x()十rect.width()"和"rect.y()十rect.height()语句到x和y坐标

image-20230213235023364

intersected()方法可以计算两个矩形的交矩形而united()方法可以计算两个矩形的矩形,它们的运算关系如图

image-20230213235216333

矩形框类常用于定义控件的左上角的位置和宽度、高度,例如下面的语句定义一个标签Label 的左上角坐标为(80,150),宽度是 100,高度是 20

1
2
3
label=QLabel(self)
rect=QRect(80, 150, 100, 20)
label.setGeometry(rect)

页边距类QMargins和QMarginsF

页边距类 QMargins 和 QMarginsF 通常应用于布局窗口和打印中,设置布局控件窗口内的工作区距边框的左边、顶部、右边和底部的距离,如图所示

在打印中设置打印区域距纸张四个边的距离。用布局或窗口的 setContentsMargins(QMargins)方法可设置页边距。

image-20230213235710525

使用前需要使用from PySide6.QtCore import QMargins, QMarginsF导入。

QMargins 定义的页边距是整数,QMarginsF 定义的页边距是浮点数(float)。用QMargins和QMarginsF 创建页边距对象的方法如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
QMargins:
QMargins(self) -> None
QMargins(QMargins: PySide6.QtCore.QMargins) -> None
QMargins(left: int, top: int, right: int, bottom: int) -> None


QMarginsF:
QMarginsF(self) -> None
QMarginsF(QMarginsF: Union[PySide6.QtCore.QMarginsF, PySide6.QtCore.QMargins]) -> None
QMarginsF(left: float, top: float, right: float, bottom: float) -> None
QMarginsF(margins: PySide6.QtCore.QMargins) -> None

QMargins和QMarginsF 的方法基本相同QMarginsF 的常用方法下表所示,其中isNull()方法获取页边距是否为空,如果所有边距都接近0,则返回值是True。

QMarginsF的方法 返回值类型 说明
setLeft(iloat) None 设置左边距
left() float 获取左边距
setTop(float) None 设置顶边距
top() float 获取顶边距
isNull() bool 获取页边距是否为空
setRight(float) None 设置右边距
right() float 获取右边距
setBottom(float) None 设置底边距
botlom() float 获取底边距
toMargins() QMargins 转换成 QMargins

字体类QFont类

字体类 QFont 可以设置界面控件上显示的字体,字体属性包括字体名称、字体尺寸粗体字、倾斜字、上/下划线、删除线等。

如果指定的字体在使用时没有对应的字体文件,Qt 将自动选择最接近的字体,如果要显示的字符在字体中不存在,则字符会被显示为一个空心方框。

字体类在QtGui模块中使用前需要用from PySide6.QtGui import QFont语句把字体类导人进来。用字体类定义字体实例对象的方法如下。

1
2
3
4
5
QFont(self) -> None
QFont(families: Sequence[str], pointSize: int=-1, weight: int=-1, italic: bool=False) -> None
QFont(family: str, pointSize: int=-1, weight: int=-1, italic: bool=False) -> None
QFont(font: Union[PySide6.QtGui.QFont, str, Sequence[str]]) -> None
QFont(font: Union[PySide6.QtGui.QFont, str, Sequence[str]], pd: PySide6.QtGui.QPaintDevice) -> None

参数:

  • families 或 family 是字体名称;
  • pointSize 是字体尺寸,取值为负值或0时,字体尺寸与系统有关,通常是12 点;
  • weight 是字体粗细程度;
  • italic 是斜体

字体类 QFont 的常用方法分为两种,一种是设置字体属性的方法,另一种是获取字体属性的方法。设置字体属性的方法名称以”set”开始不含 set 的方法是取字体的属性值字体类 QFont 的常用方法如表所示,主要方法介绍如下。

QFont 的方法及参数类型 返回值的类型 说明
setBold(bool) None 设置粗体
bold() bool 如果 weight()的值大于 QFont.Medium的值,返回 True
serCapitalization(QFont.Capitalization) None 设置大小写字体
capitalization() QFont.Capitalization 获取大小写状态
setFamilies(Sequence[str]) None 设置字体名称
families() List[sur] 获取字体名称
setFamily(str) None 设置字体名称
family() str 获取字体名称
setFixedPitch(bool) None 设置固定宽度
fixedPitch() bool 获取是否设置了固定宽度
setItalic(bool) None 设置斜体
italic() bool 获取是否斜体
setKerning(bool) None 设置字距,”a”的宽度+”b”的宽度不一定等于”ab”的宽度
kerning() bool 获取是否设置了字距属性
setLetterSpacing(QFont, SpacingType.float) None 设置字符间隙
letterSpacing() float 获取字符间距
setOverline(bool) None 设置上划线
overline() bool 获取是否设置了上划线
setPixelSize(int) None 设置像素尺寸
pixelSize() int 获取像素尺寸
setPointSize(int) None 设置点尺寸
pointSize() int 获取点尺寸
setPointSizeF(float) None 设置点尺寸,参数是浮点数
pointSizeF() float 获取点尺寸
setStretch(int) None 设置拉伸百分比
stretch() int 获取拉伸百分比
setStrikeOut(bool) None 设置删除线
strikeOut() bool 获取是否设置了删除线
setStyle(QFont.Style) None 设置字体风格
style() QFont.Style 获取字体风格
setUnderline(bool) None 设置下划线
underline() bool 获取是否设置了下划线
setWeight(QFont.Weight) None 设置字体粗细程度
weight() QFont.Weight 获取字体的粗细程度
setWordSpacing(float) None 设置字间距离
wordSpacing() float 获取字间距
toString() str 将字体属性以字符串形式输出
fromString(str) bool 从字符串中读取属性,成功则返回 True
  • 窗口上的各种控件及窗口都会有字体属性,通过控件或窗口的 font()方法可以获取字体,然后对获取的字体按照表所示的方法进行字体属性设置,设置完成后通过控件或窗口的 setFont(QFont)方法将设置好的字体重新赋给控件或窗口。当然也可以定义一个全新的字体对象,再通过控件或窗口的 setFont(QFont)方法将这个全新的字体赋给控件或窗口,可以用QApplication 的 setFont(QFont)方法为整个应用程序设置默认字体。
  • 用setFamily(str)方法设置字体名称,名称中可以用逗号将多个字体名称隔开PySide6 自动根据逗号将名称分解成多个字体名称,也可以直接用setFamilies(Sequence[str])方法设置多个字体名称,第1个是主字体。需要注意的是字体名称的大小写敏感,当设置的字体名称不支持时,会自动搜索匹配的字体,当字体不支持文字符号时,文字符号用方框来表示
  • setPixelSize(int)方法使用像素作为单位来设置字体大小。setPointSize(int)方法设置实际中我们肉眼看到的字体的大小,与像素无关。使用setPixelSize(int)方法设置字体尺寸时,在像素大小不同的设备上显示的大小也不同。使用setPointSize(int)方法设置的字体尺寸,在不同设备上显示的大小是相同的。如果指定了pointSize,则像素 pixelSize 尺寸的属性值是-1;反之,如果指定了 pixelSize,则pointSize属性值是-1。字体尺寸也可以用setPointSizeF(float)方法设置,其中参数是浮点数。
  • 用setCapitalization(QFont, Capitalization)方法设置大小写方法,枚举类型 QFont.Capitalization 可以取 QFont.MixedCase、QFont, AllUppercase、QFontAllLowercase、QFont,SmallCaps 或 QFont,Capitalize(每个字的首字母大写)。
  • 用setWeight(QFont,Weight)方法设置字体的粗细程度,举类型 QFontWeight可以取 QFont, Thin,QFont, ExtraLight,QFont, Light,QFont, Normal、QFont.Medium,QFont, DemiBold、QFont, Bold,QFont, ExtraBold 或 QFont, Black,对应值分别是 100、200、·· 900,字体由细到粗。
  • 用setStyle(QFont,Style)方法设置字体的风格,举类型QFont.Style 可以取QFont, StyleNormal,QFont, Styleltalic 或 QFont, StyleOblique
  • 用setStretchint()方法设置拉伸百分比,参数大于 100 表示拉长,小于100表示缩的短,参数也可以用枚举值(见下)设置。AnyStretch拉伸系数仅应用于轮廓字体。位图字体将忽略拉伸因子。
    • QFont.AnyStretch(值为0表示可匹配其他字体属性)标识可匹配其他字体的属性,它将接受任何拉伸因子,不会对字体应用任何变换。
    • QFont.UltraCondensed(值为 50)
    • QFont,ExtraCondensed(值为 62)
    • QFont.Condensed(值为 75)
    • QFont,SemiCondensed(值为87)
    • QFont,Unstretched(值为100)
    • QFont.SemiExpanded(值为 112)
    • QFont Expanded(值为 125)
    • QFont.ExtraExpanded(值为150)
    • QFont,UltraExpanded(值为 200)来
  • 用setLetterSpacing(QFont,SpacingType,float)方法设置字符间隙,其中 QFont.SpacingType 可以取 QFont,PercentageSpacing(用百分比来表示,大于 100 增大间隙,小于 100 减小间隙)或 QFont.AbsoluteSpacing(用绝对值来表示正值增大间隙,负值减小间隙)。
  • 用toString()方法将宇体的属性以宇符串形式输出,这样可以把字体属性保存到文件中。用fromString(str)方法从字符申获取字体属性。

下面的程序在窗口上创建10个标签控件(QLabel),分别给 10个标签设置不同的字体属性,同时给应用程序设置默认字体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import QApplication, QWidget, QLabel


class win_demo(QWidget):
def __init__(self):
super().__init__()
self.set_wininit()

self.fonts=list()
self.labels=list()

self.createFont() # 调用函数
self.createLabels() # 调用函数
self.getLabelFont() # 调用函数

def set_wininit(self):
self.resize(800, 600) # 设置窗口大小
self.setWindowTitle("hello world") # 设置窗口标题

def createFont(self): # 生成10个字体
# 字体列表
fontName=('宋体', '仿宋', '黑体', '楷体', '隶书', '幼圆', '华文中宋', '方正舒体', '华文黑体', 'Times New Roman')

for i in range(10):
f=QFont()
f.setPointSizeF(25.5)
f.setFamily(fontName[i])
self.fonts.append(f)

self.fonts[0].setBold(True)
self.fonts[1].setItalic(True)
self.fonts[2].setStrikeOut(True)
self.fonts[3].setOverline(True)
self.fonts[4].setUnderline(True)
self.fonts[5].setCapitalization(QFont.AllUppercase)
self.fonts[6].setWeight(QFont.Thin)
self.fonts[7].setWordSpacing(50)
self.fonts[8].setStretch(70)
self.fonts[9].setPixelSize(50)

def createLabels(self):
string="Nice to Meet You!很高兴认识你!"

for i in range(10):
label=QLabel(self) # 在窗口上创建标签控件
label.setGeometry(0, 50 * i, 800, 70) # 标签位置和尺寸
label.setText(str(i) + ':' + string) # 设置标签文字
label.setFont(self.fonts[i]) # 设置标签文字的字体
self.labels.append(label)

def getLabelFont(self): # 获取每个字体的信息
# 标签列表
print("字体信息:")
template="Label{}: family:{}, Bold:{}, Italic:{}, StrikeOut:{}, OverLine:{}, UnderLine:{}, Capitalization:{}, Weight:{}, WordSpacing:{}, Stretch:{}, PixelSize:{}, pointSize:{}"
j=0
for i in self.labels:
f=i.font() # 获取标签的字体
print(template.format(j, f.family(), f.bold(), f.italic(), f.strikeOut(), f.overline(), f.underline(), f.pointSize(), f.capitalization(), f.weight(), f.wordSpacing(), f.stretch(), f.pixelSize()))
j +=1


if __name__=='__main__':
app=QApplication(sys.argv)
win=win_demo()

win.show()
sys.exit(app.exec())

image-20230214013905368

颜色类QColor

PySide6 的颜色类是 QColor,需要导入 from PySide6.QtGui import QColor,颜色可以用以下方法表示:

  • RGB(红,red;绿,green;蓝,blue)值来定义,还可以用
  • HSV(色相,hue;饱和度,saturation;值,value)值、
  • CMYK(青色,cyan;品红,magenta:色,yellow;黑色,black)
  • HSL(色相,hue;饱和度,saturation;亮度,lightness)值来定义

RGB 和 HSV 可以用于电脑屏幕的颜色显示,红绿蓝三种颜色的值都为 0255,值越大表示这种颜色的分量越大,HSV 中 H 的取值为0359,S 和 V的取值都为0~255,除了定义红绿蓝3种颜色成分外,通常还需要定义alpha通道值,表示颜色的透明度。alpha通道的取值也是0~255,值越大表示越不透明。

用QColor类定义颜色的方法如下所示,其中 QColor(name:str)中 name 是颜色名称例如’Blue’、Beige’、LightPink’。

  • 颜色值还可以用RGB 字符串或ARGB字符串来定义RGB字符串格是”#RRGGBB”,

  • ARGB字符串格式是”#AARRGGBB”其中 RRGG和BB 分别是用十六进制表示的红、绿、蓝颜色的值,AA 是 alpha 通道的值例如”#00ff0000”表示红色。

  • QtCore.Qt.GlobalColor 是指 QtCore.Qt 中定义的一些颜色校举常量,

  • Qt.GlobalColor 是枚举常量,可以取

    • Qt.white
    • Qt.black
    • Qt.red
    • Qt.darkRed
    • Qt.green
    • Qt.darkGreen
    • Qt.blue
    • Qt.darkBlue
    • Qt.cyan
    • Qt.darkCyan
    • Qt.magenta
    • Qt.darkMagenta
    • Qt.yellow
    • Qt.darkYellow
    • Qt.gray
    • Qt.darkGray
    • Qt.lightGray

    Qt.transparent(透明黑色)

    Qt.color0(0 像素值,只针对 QBitmap 图像)或 Qt.color1(1像素值,只针对 QBitmap图像)。

    QColor.Spec 是枚举类型,可以取 QColor.RgbQColor.Hsv,QColor.Cmyk.QColor.Hsl、QColor,ExtendedRgb 或 QColor,Invalid,QColor, ExtendedRgb 表示的颜色值取浮点数时可以x小于 0 或大于 1。

1
2
3
4
5
6
7
8
QColor(self) -> None
QColor(arg__1: Any) -> None
QColor(color: PySide6.QtCore.Qt.GlobalColor) -> None
QColor(name: str) -> None
QColor(r: int, g: int, b: int, a: int=255) -> None
QColor(rgb: int) -> None
QColor(rgba64: PySide6.QtGui.QRgba64) -> None
QColor(spec: PySide6.QtGui.QColor.Spec, a1: int, a2: int, a3: int, a4: int, a5: int=0) -> None

颜色类 QColor 的常用方法如表所示:

颜色类的方法中一种是名称以 set 开始的方法,为设置颜色相关值;另外一种名称没有 set 的是取颜色相关值,如 setRed(int)设置颜色的红色值,而 red()是获取颜色的红色值。

设置或获取颜色的相关值时,一种是用整数表示的值,另一种是用浮点数表示的值,用浮点数表示的值,取值范围是 0~1用setNamedColor(str)方法使用颜色名称或字符串来定义颜色,例如 setNamedColor(‘blue)setNamedColor(‘# 0012FF34’)。用name(format; QColor.NameFormat=QColor.HexRgb)方法获取字符串颜色,其中 QColor,NameFormat 是举值可以取 QColor.HexRgb 或 QColor HexArgb,返回的颜色字符申分别是#RRGGBB和#AARRGGBBQ。Color 类一般不直接定义控件的颜色,而是与调色板或画刷一起使用。

Qcolor的方法

Qcolor的方法及参数类型 返回值的类型 说 明
seRed(red: int) None 设置RGB的R值
setRedF(red:float) None 设置RGB的R值
red() int 获取RGB值中的R值
redF() float 获取RGB值中的R值
setGreen(green:int) None 设置RGB的G值
setGreenF(green:float) None 设置RGB的G值
green() int 获取RGB值中的G值
greenF() float 获取RGB值中的G值
setBlue(blue: int) None 设置RGB的B值
setBlueF(blue: float None 设置RGB的B值
blue() int 获取RGB值中的B值
blueF() float 获取RGB值中的B值
set Alpha(alpha: int) None 设置alpha 通道的值
setAlphaF(alpha:float) None 设置alpha 通道的值
alpha() int 获取 alpha 通道的值
alphaF() float 获取 alpha 通道的值
setRgb(r: int,g:int,b: int,a: int=255) None 设置R、G、B、A值
setRgbF(r: float,g: float, b: float,a: float=1.0) None 设置R、G、B、A值
getRgb() Tuple[int,int,int, int] 获取R、G、B、A值
getRgbF() Tuple[float,float, float, float] 获取R、G、B、A值
setHsl(h:int,s:int,1: int,a: int=255) None 设置HSL值
setHslF(h: float,s: float,1: float,a: float=1.0) None 设置HSL值
getHs1() Tuple[int, int, int.int] 获取H、S、L和A值
getHslF() Tuple[float, float, float,float] 获取H、S、L和A值
setHsv(h:int,s: int,v:int,a: int=255) None 设置HSV值
setHsvF(h: float,s: float,v: float,a: float=1.0) None 设置HSV值
getHsv() TupleCint,int, int, · int] 获取H、S、V和A值
getHsvF() Tuple[float.float, float, float] 获取H、S、V和A值
setCmyk(c:int,m: int,y: int, k:int, a: int=255) None 设置CMYK值
setCmykF(c:float,m: float,y: float,k: float,a: float=1.0) None 设置CMYK值
getCmyk() TupleCint, int,int, int,int] 获取C、M、Y、K和A值
getCmykF() Tuple[float,float, float,float,float] 获取C、M、Y、K和A值
setRgb(rgb:int) None 设置RGB值
setRgba(rgba:int) None 设置RGBA值
rgb() int 获取 RGB值
rgba() int 获取RGBA值
setNameclColor(str) None 设置颜色名称或”#AARRGGBB”
name(format:QColor.NameFormat=QColor.HexRgb) str 获取颜色的”#RRGGBB”或”#AARRGGBB”
convertTo(colorSpec: QColor.Spec) QColor 获取指定格式的颜色副本
spec() QColor.Spec 获取颜色输出的格式
isValid() bool 获取颜色是否有效
toCmyk() QColor 转换成CMYK表示的颜色
toHsl() QColor 转换成 HSL表示的颜色
toHsv() QColor 转换成 HSV表示的颜色
toRgb() QColor 转换成 RGB表示的颜色
[static]fromCmyk(c:int,m: int,y:int,k:int,a:int=255) QColor 从C、M、Y、K、A值中创建颜色
[static]fromCmykF(c:float,m: float,y: float,k:float,a: float=1.0) QColor 从C、M、Y、K、A值中创建颜色
[static]fromHsl(h: int,s:int,1: int,a:int=255) QColor 从H、S、L、A值中创建颜色
[static]fromHslF(h: float, s: float,1: fIoat,a: float=1.0) QColor 从H、S、L、A值中创建颜色
[static]fromHsv(h: int,s: int, v:int,a:int=255) QColor 从H、S、V、A值中创建颜色
[static]fromHsvF(h: float, s: float,v:float,a: float=1.0) QColor 从H、S、V、A值中创建颜色
[static]fromRgb(r:int,g: int, b: int,a:int=255) QColor 从R、G、B、A值中创建颜色
[static]fromRgbF(r:float,g: float,b: float,a: float=1.0) QColor 从R、G、B、A值中创建颜色
[static]fromRgb(rgb:int) QColor 从RGB值中创建颜色
[static]fromRgba(rgba:int) QColor 从RGBA值中创建颜色
[static]isValidColor(str) bool 获取用文本表示的颜色值是否有效

RGB值与颜色名称的对应关系

RGB 颜色名称
QColor(255,0,0)
QColor(0,255,0) 绿
QColor(0,0,255)
QColor(79,129,189) 淡蓝
QColor(192,80,77) 朱红
QColor(155,187,89) 浅绿
QColor(128,100,162)
QColor(75,172,198) 浅蓝
QColor(151,151,151)
QColor(36,169,225) 天蓝
QColor(91,74,66) 深棕
QColor(130,57,53) 红棕
QColor(137,190,178) 蓝绿
QColor(201,186,131) 泥黄
QColor(222,221,140) 暗黄
QColor(222,156,83)
QColor(199,237,233) 亮蓝
QColor(175,215,237) 蓝灰
QColor(92,167,186) 蓝绿
QColor(147,224,255) 浅蓝

调色板类QPalette

使用调色板需要先导入:from PySide6.QtGui import QPalette

调色板实例对象的创建方式如下所示

1
2
3
4
5
6
7
8
from PySide6.QtGui import QPalette
QPalette(self) -> None
QPalette(button: PySide6.QtCore.Qt.GlobalColor) -> None
QPalette(button: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int]) -> None
QPalette(button: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], window: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int]) -> None
QPalette(palette: Union[PySide6.QtGui.QPalette, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor]) -> None
QPalette(windowText: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], button: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], light: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], dark: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], mid: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], text: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], bright_text: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], base: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], window: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap]) -> None
QPalette(windowText: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], window: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], light: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], dark: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], mid: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], text: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], base: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int]) -> None

颜色组ColorGroup,颜色角色ColorRole

PySide6中各种控件和窗口的颜色都由调色板类QPalette来定义,可以为窗体和窗体上的控件设置前景色、背景色,可以用palette()方法和 setPalette(QPalette)方法获取和设置窗体及控件的调色板,另外可以通过QApplication类的setPalette(QPalette)方法为整个应用程序设置默认的调色板。

QPalette类有两个基本的概念,一个是颜色组ColorGroup,另一个是颜色角色ColorRole。

颜色组ColorGroup 分为3种情况:

  • 激活状态(Active,获得焦点)、
  • 非激活状态(Inactive,失去焦点)
  • 失效状态(Disabled,不可用),例如进行多窗口操作时.单击其中的一个窗口,可以在窗口中输人数据,则这个窗口是激活状态,其他窗口是非活跃状态。

当将一个控件的enable属性设置为False时(可通过 setEnabled(bool)方法设置),这个控件就处于失效状态,失效状态的控件不能接受任意输入,例如按钮不能单击、输人框中不能输人文字。对于一个控件,例如一个Label 标签或 PushButton按钮,可以设置其文字的颜色,也可以设置其背景颜色。

颜色角色ColorRole的作用是对控件或窗体的不同部分分别设置颜色。将ColorGroup 和ColorRole结合起来,可以为控件不同部分不同状态设置不同的颜色。

一个窗口由多个控件构成,可以用颜色角色为窗口和窗口中的控件定义不同的颜色角色。

PySide6 中颜色组由枚举常量 QPalettc.ColorGroup 确定,QPalette,ColorGroup 可取:

  • QPalette.ColorGroup.Active激活,获得焦点
  • QPalette.ColorGroup.Normal常规状态
  • QPalette.ColorGroup.Inactive非激活,失去焦点
  • QPalette.ColorGroup.Disabled失效状态 Disabled,禁用

颜色角色由枚举常量 QPalette.ColorRole确定, QPalette.ColorRole的枚举值如表所示。

枚举常量 说明
QPalette.ColorRole.WindowText 0 窗口的前景色
QPalette.ColorRole.Window 10 窗口控件的背景色
QPalette.ColorRole.Text 6 文本输入控件的前景色
QPalette.ColorRole.Button 1 按钮的背景色
QPalette.ColorRole.Button Text 8 按钮的前景色
QPalette.ColorRole.PlaceholderText 20 输入框中占位文本的 颜色
QPalette.ColorRole.ToolTipBase 18 提示信息的背景色
QPalette.ColorRole.ToolTipText 19 提示信息的前景色
QPalette.ColorRole.BrightText 7 文本的对比色
QPalette.ColorRole.AlternateBase 16 多行输入输出控件(如 QListWiget)行 交替背景色
QPalette.ColorRole.Highlight 12 所选物体的背 景色
QPalette.ColorRole.HighlightedText 13 所选物体的前 景色
QPalette.ColorRole.Link 14 超链接的颜色
QPalette.ColorRole.LinkVisited 15 超链接访问后 颜色
QPalette.ColorRole.Light 2 与控件的3D效 果和阴影效果有 关的颜色
QPalette.ColorRole.Midlight 3 与控件的3D效 果和阴影效果有 关的颜色
QPalette.ColorRole.Dark 4 与控件的3D效 果和阴影效果有 关的颜色
QPalette.ColorRole.Mid 5 与控件的3D效 果和阴影效果有 关的颜色
QPalette.ColorRole.Shadow 11 与控件的3D效 果和阴影效果有 关的颜色
QPalette.ColorRole.Base 9 文本输入控件(如 QTextEdit) 背景色

可以用QColor,Qt.GlobalColor QBrush QGradient 来定义有初始颜色的调色板,其中 QColor Qt.GlobalColor 定义的颜色是纯颜色而 QBrush QGradient 定义的颜色是可以渐变的。有关 QBrush 和 QGradient 的使用方法参 QPainter内容。

调色板类QPalctte 的常用方法

  • 窗口上的各种控件及窗口都会有调色板属性,通过控件或窗口的 palette()方法可以获取调色板,然后对获取的调色板进行颜色设置,设置完成后通过控件或窗口的setPalette(QPalette)方法将设置好的调色板重新赋给控件或窗口,当然也可以定义一个全新的调色板对象,通过控件或窗口的 setPalette(QPalette)方法将这个全新的调色板赋予控件或窗口。
  • 对控件或窗口的不同部分不同状态设置颜色需要用调色板的 setColor()方法或setBrush()方法。用brush()方法可以获得不同状态不同角色的画刷,过画刷的color()方法可以获得颜色 QColor 对象。
  • 如果需要设置控件的背景色,应将背景色设置成自动填充模式,通过控件的方法setAutoFillBackground(True)来设置。对于按钮通常还需要关闭3D效果,通过按钮的 setFlat(True)来设定
QPalette的方法及参数类型 返回值类型
serColor(QPalette.ColorGroup, QPalette.ColorRole, color: Union[QColcr,Qt.GlobalColor,str]) None
setColor(QPalette.ColorRole, color: Union[QColor, Qt.GlobalColor,str]) None
color(QPalette.ColorGroup, QPalette.ColorRole) QColor
color(QPalette.ColorRole) QColor
setBrush(QPalette.ColorGroup, QPalette.ColorRole,brush: Union[QBrush, Qt.BrushStyle, Qt.GlobalColor.QColor, QGradient, QImage,QPixmap]) None
setBrush(QPalette.ColorRole, brush: Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage.QPixmap]) None
brush(QPalette.ColorGroup.QPalette.ColorRole) QBrush
brush(QPalette.ColorRole) QBrush
setCurrentColorGroup(QPalette.ColorGroup) None
currentColorGroup() QPalette.ColorGroup
alternateBase() QBrush
base() QBrush
brightText() QBrush
button() QBrush
buttonText() QBrush
dark() QBrush
highlight() QBrush
highlightedText() QBrush
isBrushSet(QPalette.ColorGroup, QPalette.ColorRole) 6001
isEqual(crl: QPalette.ColorGroup,cr2: QPalette.ColorGroup) 6001
light() QBrush
link() QBrush
linkVisited() QBrush
mid() QBrush
midlight() QBrush
placeholderText() QBrush
shadow() QBrush
text() QBrush
toolTipBase() QBrush
toolTipText() QBrush
window() QBrush
windowText() QBrush

实例:

image-20230214233504539

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import sys  # Demo2_4.Py
from PySide6.QtWidgets import QApplication, QWidget, QLabel
from PySide6.QtGui import QFont, QColor, QPalette
from random import randint, seed


class SetPalette(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setGeometry(200, 200, 1200, 500) # 设置窗口尺寸
self.setWindowTitle("设置调色板实例")

self.createLabels() # 调用函数
self.setLabelColor() # 调用函数
self.getLabelColorRGB() # 调用函数

def createLabels(self):
self.labels=list()
font=QFont("黑体", pointSize=20)
string="Nice to meet you!很高兴认识你!"

for i in range(10):
label=QLabel(self) # 在窗口上创建标签控件
label.setGeometry(5, 50 * i, 1200, 40) # 标签位置和尺寸
label.setText(str(i) + ': ! + string)# 设置标签文字')
label.setFont(font)
# 设置标签文字的字体
self.labels.append(label) # 标签列表

def setLabelColor(self):
seed(12)
for label in self.labels:
colorBase=QColor(randint(0, 255), randint(0, 255), randint(0, 255)) # 定义颜色
colorText=QColor(randint(0, 255), randint(0, 255), randint(0, 255)) # 定义颜色

palette=label.palette()

palette.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.Window, colorBase) # 定义背景色
palette.setColor(QPalette.ColorGroup.Active, QPalette.ColorRole.WindowText, colorText) # 定景色
label.setAutoFillBackground(True) # 设置背景自动填充
label.setPalette(palette) # 设置调色板

def getLabelColorRGB(self): # 获取标签前景颜色和背景颜色 RGB 值
for label in self.labels:
r, g, b, a=label.palette().window().color().getRgb() # 获取背景颜色的 RGB 值
rT, gT, bT, a=label.palette().windowText().color().getRgb() # 获取文字颜色的 RGB 值
text=(label.text() + "背景颜色:{} {} {}; 文字颜色:{} {} {}").format(r, g, b, rT, gT, bT)
label.setText(text)


if __name__=='__main__':
app=QApplication(sys.argv)

windows=SetPalette()
windows.show()
sys.exit(app.exec())

图像类

image-20230212181021306

PySide6的图像类有QImage、QPixmap、QPicture、QBitmap 四大类,这几个类都是从QPaintDevice类继承而来的,它们的继承关系如图所示。

  • QPixmap 适合将图像显示在电脑屏幕上,可以使用QPixmap 在程序之中打开png、jpeg 等图像文件。QBitmap 是 QPixmap 的一个子类,它的色深限定为1,颜色只有黑白两种,用于制作光标QCursor 或画刷 QBrush 等。

  • QImage 专门读取像素文件,其存储独立于硬件,是一种QPaintDevice设备,可以直接在QImage上用QPainter绘制图像,可以在另一个线程中对其进行绘制,而不需要在GUI线程中处理,使用这一方式可以很大幅度提高GUI响应速度。

    当图片较小时,可直接用QPixmap进行加载,当图片较大时用QPixmap加载会占很大的内存,这时用QImage进行加载会快一些,QImage 可以转成QPixmap。QPicture 是一个可以记录和重现QPainter命令的绘图设备,它还可以保存QPainter绘制的图形,QPicture 将QPainter的命令序列化到一个I0设备上,保存为一个平台独立的文件格式。

  • QPicture与平台无关,可以用到多种设备之上,比如svg、pdf、ps、打印机或者屏幕。

QtGui.QPixmap

用QPixmap 类创建实例的方法如下,其中 wh 和QSize 指定图像的像索数(尺寸大小),str 是一个图像文件。

1
2
3
4
5
6
7
8
from PySide6.QtGui import QPixmap
QPixmap(self) -> None
QPixmap(arg__1: PySide6.QtCore.QSize) -> None
QPixmap(arg__1: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]) -> None
QPixmap(fileName: Union[str, bytes, os.PathLike], format: Union[bytes, NoneType]=None, flags: PySide6.QtCore.Qt.ImageConversionFlag=Instance(Qt.AutoColor)) -> None
QPixmap(image: Union[PySide6.QtGui.QImage, str]) -> None
QPixmap(w: int, h: int) -> None
QPixmap(xpm: Iterable) -> None

QImage,QPixmap,QBitmap,QPicture 这4个类都有 load()和 save()方法,用于从文件中加载图片和保存图片;QImage 和 QPixmap 类有 fill()方法可以填充某种颜色的图形;QPixmap类的 tolmage()方法可以将 QPixmage 图像转换成 QImage图像

QPixmap类的常用方法如表所示其中用save(str,format=None,quality=-1)方法可以保存图像成功则返回True。其中str是保存的文件路径和文件名;format是文件类型,用字节串表示,支持的格式如表2-11所示如果是None,则根据文件的扩展名确定类型;quality的取值为0~100的整数取-1表示采用默认值,对于有损压缩的文件格式来说,它表示图像保存的质量,质量越低压缩率越大。用load(str,format=None,flags=Qt.AutoColor)方法可以从文件中加载图像,其中flags是QtImageConversionFlag的枚举类型表示颜色的转换模式可以取QtAutoColor(由系统自动决定)QtColorOnly(彩色模式)或Qt.MonoOnly(单色模式)用setMask(QBitmap)方法设置遮掩图,黑色区域显示,白色区域不显示

QPixmap类的常用方法

QPixmap的方法及参数类型 返回值的类型 说 明
copy(rect: QRect=Default(QRect)) QPixmap 深度复制图像的局部区域
copy(x: int,y: int,width: int,height: int) QPixmap 深度复制图像的局部区域
load(fileName: str, format: Union[bytes, NoneType]=None, Qt.ImageConversionFlags=Qt.AutoColor) bool 从文件中加载图像,成功则返回True
save(QIODevice, format: Union[bytes, NoneType]=None,quality: int=-1) bool 保存图像到设备中,成功则返回 True
save(fileName: str,format: Union[bytes, NoneType]=None,quality:int=-1) bo01 保存图像到文件中,成功则返回True
scaled(QSize, Qt.AspectRatioMode=Qt.IgnoreAspectRatio) QPixmap 缩放图像
scaled(w: int, h: int, Qt.AspectRatioMode=Qt.IgnoreAspectRatio) QPixmap 缩放图像
scaledToHeight(h: int) QPixmap 缩放到指定的高度
scaledToWidth(w: int) QPixmap 缩放到指定的宽度
setMask(Union[QBitmap,str]) None 设置遮掩图,黑色区域显示,白色区域 不显示
mask() QBitmap 获取遮掩图
swap(Union[QPixmap,QImage]) None 与别的图像进行交换
tolmage() QImage 转换成QImage图像
convertFromImage(QImage) bool 从QImage 图像转换成 Qpixmap,成功 则返回True
[static]fromImage(QImage) QPixmap 将 QImage 图像转换成 QPixmap
transformed(QTransform) QPixmap 将图像进行旋转、缩放、平移和错切等 变换,详见6.1节的内容
rect() QRect 获取图像的矩形尺寸
size() QSize 获取图像的区域尺寸
width()height() int 获取图像的宽度和高度
fill(fillColor: Union[QColor,Qt.GlobalColor]=Qt.white) None 用某种颜色填充图像
hasAlpha() bool 是否有 alpha通道值
depth() int 获取图像的深度,例如32bit 图深度 是32
isQBitmap() bool 获取是否是QBitmap图

QPixmap 可以读写的文件格式

图像格式 是否可以读写
BMP Read/write
GIF Read
JPG Read/ write
JPEG Read/write
PNG Read/write
PBM Read
PGM Read
PPM Read/ write
XBM Read/ write
XPM Read/ write

例子

下面的程序在窗口上创建一个 QLabel 标签和一个 QPushButton 按钮,单击QPushButton 按钮选择图像文件,用图像文件创建QPixmap 对象,然后在QLabel标签中显示QPixmap 图像

image-20230215002227914

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QPushButton, QFileDialog
from PySide6.QtGui import QPixmap
from PySide6.QtCore import Qt


class MyPixmap(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setGeometry(200, 200, 800, 500) # 设置窗口尺寸
self.setupUi() # 调用函数建立界面

def setupUi(self): # 创建界面
self.label=QLabel("单击按钮打开图像文件!") # 创建标签
self.label.setAlignment(Qt.AlignCenter) # 中心对齐
font=self.label.font() # 获取字体
font.setPointSize(10) # 设置字体大小
self.label.setFont(font) # 给标签设置字体
self.open_button=QPushButton("打开图像文件(&O)") # 创建按钮
self.open_button.setFont(font) # 给按钮设置字体

self.vertical_layout=QVBoxLayout(self) # 在窗口上创建竖直布局
self.vertical_layout.addWidget(self.label) # 在布局中添加标签
self.vertical_layout.addWidget(self.open_button) # 在布局中添加按钮

self.open_button.clicked.connect(self.open_button_clicked) # 按钮信号与槽的连接

def open_button_clicked(self):
fileName, filter=QFileDialog.getOpenFileName(filter="图像文件(*.png *.bmp *.jpg *.jpeg);; 所有文件(* .*)") # 打开对话框获取文件名
pixmap=QPixmap(fileName) # 创建 QPixmap 图像
self.label.setPixmap(pixmap) # 在标签中显示图像


if __name__=='__main__':
app=QApplication(sys.argv)
window=MyPixmap()
window.show()
sys.exit(app.exec())

QtGui.QImage

QImage 是绘图设备可以直接用QPainter 在 QImage 上绘制图像,QImage 可以直接操作图像上的像素。用QImage类创建实例的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
from PySide6.QtGui import QImage

QImage(self) -> None
QImage(arg__1: str, arg__2: int, arg__3: int, arg__4: PySide6.QtGui.QImage.Format) -> None
QImage(arg__1: str, arg__2: int, arg__3: int, arg__4: int, arg__5: PySide6.QtGui.QImage.Format) -> None
QImage(arg__1: Union[PySide6.QtGui.QImage, str]) -> None
QImage(data: bytes, width: int, height: int, bytesPerLine: int, format: PySide6.QtGui.QImage.Format, cleanupFunction: Union[Callable, NoneType]=None, cleanupInfo: Union[int, NoneType]=None) -> None
QImage(data: bytes, width: int, height: int, format: PySide6.QtGui.QImage.Format, cleanupFunction: Union[Callable, NoneType]=None, cleanupInfo: Union[int, NoneType]=None) -> None
QImage(fileName: Union[str, bytes, os.PathLike], format: Union[bytes, NoneType]=None) -> None
QImage(size: PySide6.QtCore.QSize, format: PySide6.QtGui.QImage.Format) -> None
QImage(width: int, height: int, format: PySide6.QtGui.QImage.Format) -> None
QImage(xpm: Iterable) -> None

其中,format是QImage Format 的枚举值,指定QImage 的图形文件的格式其常用取值如下表所示:

  • QImage.Format_ARGB32 表示采用32位ARGB 格式存储(0xAARRGGBB)
  • QImage.Format_ARGB8565_Premultiplied 表示采用24 位预乘ARGB格式存储(8-5-6-5)
  • QImage.Format_Mono 表示每个像素用1位存储
  • QImage.Format.RGB32 表示用32位 RGB 格式存储(0xfIRRGGBB)
  • QImage.Format_RGB888 表示用24位RGB格式存储(8-8-8)。

因为涉及存储格式,因此这里需要对图像的类型作一些说明:

  • 单色图像就是黑白图像,用1位存储一个像素的颜色。

  • 8 位图像是指使用一个8 位的索引把图像存储到颜色表中,因此 8 位图像的每个像占据 8位1B)的存储空间每个像素的颜色与颜色表中某个索引的颜色相对应。颜色表使用QVector 存储 QRgb 类型颜色该类型包含一个0xAARRGGBB 格式的四元组数据。

  • 32 位图像没有颜色表每个像素包含一个 QRgb 类型的值,共有 3 种类型的 32 位图像,分别是 RGB(即 0xfRRGGBB)ARGB和预乘 ARGB。

  • 带 alpha 通道的图像有两种处理方法:

    一种是直接 alpha,另一种是预乘alpha。直接 alpha 图像的 RGB 数值是原始的数值,而预乘 alpha 图像的 RGB 数值是乘以alpha通道后得到的数值,比如ARGB=(a,rg;),预乘 alpha 的值为(a,a * r,a * g,a * b),PySide6 预乘 alpha 通道图像的算法是把红绿、蓝通道的数值乘以alpha 通道的数值再除以 255

QImage.Format.Format的取值 QImage.Format.Format 的取值 QImage.Format.Format的取值
QImage.Format.Format_Invalid QImage.Format.Format_ARGB6666_Premultiplied QImage.Format.Format_RGBX8888
QImage.Format.Format_Mono QImage.Format.Format_ARGB32_Premultiplied QImage.Format.Format_RGBA8888
QImage.Format.Format_MonoL.SB QImage.Format.Format_ARGB8555_Premultiplied QImage.Format.Format_RGB30
QImage.Format.Format_ Indexed8 QImage.Format.Format_ARGB8565_Premultiplied QImage.Format.Format_Alpha8
QImage.Format.Format_RGB32 QImage.Format.Format_A2BGR30_Premultiplied QImage.Format.Format_Grayscale8
QImage.Format.Format_ARGB32 QImage.Format.Format_ARGB4444_Premultiplied QImage.Format.Format_Grayscalel6
QImage.Format.Format_RGB555 QImage.Format.Format_A2RGB30_Premultiplied QImage.Format.Format_RGBX64
QImage.Format.Format_RGB16 QImage.Format.Format_RGBA64_Premultiplied QImage.Format.Format_RGBA64
QImage.Format.Format_RGB888 QImage.Format.Format_RGBA8888_Premultiplied QImage.Format.Format_RGB444
QImage.Format.Format_RGB666 QImage.Format.Format_BGR30 QImage.Format.Format_BGR888

QImage类的常用方法如表所示:

QImage 可以对图像的像素颜色进行深入操作

  • 可以对图像的颜色 RGB 值进行翻转
  • 可以获取每个像素点的 RGB 值
  • 可以设置每个像素点的 RGB值,因此在获取一个像素点的 RGB 值后应对其进行处理。例如将 RGB三个值取原 RGB值的平均值,可以使图像灰度化;
  • RGB值都增加或减少一个相同的值,可以使图像亮度增加或降低,但是注意不要超过 255 和低于 0;
  • 用卷积计算可以进行锐化模糊化、调节色调等处理,
  • 对图像像索颜色的操作与图像的格式有关,例如对单色和 8bit 图像,存储的是索引和颜色表;对32bit 图像,存储的是ARGB值。
Qlmage的方法及参数类型 返回值的类型 说明
format() QImage.Format 获取图像格式
convertTo(QImage.Format) None 转换成指定的格式
copy(QRect)、copy(int.int,int,int) Qlmage 从指定的位置复制图像
fill(color: Union[QColor.Qt.GlobalColor.str]) None 填充颜色
load(str, format=None,flags=Qt.AutoColor) bool 从文件中加载图像,成功则返 回True
save(str,format=None,quality=-1) bool 保存图像,成功则返回True
save(QIODevice, format=None,quality=-1) bool 保存图像,成功则返回True
scaled(QSize, Qt.AspectRatioMode=Qt.IgnoreAspectRatio) QImage 将图像的长度和宽度缩放到新的宽 度和高度,返回新的 QImage对象
scaled(w: int,h: int,Qt.AspectRatioMode=Qt.IgnoreAspectRatio) QImage 将图像的长度和宽度缩放到新的宽 度和高度,返回新的 QImage对象
scaledtoHeight(int,Qt.TransformationMole) Qlmage 将高度缩放到新的高度,返回新 的 QImage 对象
scaledtoWidth(int.Qt.TransforinationMode) Qlmage 将宽度缩放到新的宽度,得到新 的QImage对象
size() QSize 返回图像的尺寸
width()、height() int 返回图像的宽度和高度
setPixelColor(int,int,QColor) None 设置指定位置处的颜色
setPixelColor(QPoint,QColor) None 设置指定位置处的颜色
pixelColor(int,int)、pixelColor(QPoint) QColor 获取指定位置处的颜色值
pixIndex(int,int)、pixIndex(QPoint) int 获取指定位置处的像素索
setText(key:str,value: str) None 嵌人字符串
text(key:str=’’) str 根据关键字获取字符串
textKeys() List[str] 获取文字关键字
rgbSwap() None 颜色翻转,颜色由 RGB转孩 为 BGR
rgbSwapped() QImage 返回颜色反转后的图形,颜色曲 RGB转换为BGR
invertPixels(QImage.InvertMode=QImage.InvertRgb) None 返回颜色反转后的图形,有 QImage.InvertRgb(反转 RGB值, A值不变)和 QImage.InvernRgta(反转 RGBA值)两种模式,颜色由 ARGB 转 换 成(255-A)(255-R)(255-G)(255-B)
transformed(QTransform) QImage 对图像进行变换
mirror(horizontally: bool=False,vertically:bool=True) None 对图像进行镜像操作
mirrored(horizontally: bool=False, vertically: bool=True) QImage 返回镜像后的图像
setColorTable(colors:Sequence[int]) None 设置颜色表,仅用于单色或8 bit 图像
colorTable() ListCint] 获取颜色表中的颜色
color(i:int) int 根据索引值获取索引表中的颜色
setPixel(QPoint, index_or_rgb:int) None 设置指定位置处的颜色值或素引
setPixel(x: int,y: int,index_or_rgb; int) None 设置指定位置处的颜色值或素引
Pixel(pt:QPoint) int 获取指定位置处的颜色值
Pixel(x:int,y:int) int 获取指定位置处的颜色值
pixelIndex(pt; QPoint) int 获取指定位置处的颜色索引值
pixelIndex(x: int,y; int) int 获取指定位置处的颜色索引值

QtGui.QBitmap

QBitmap 是只能存储黑白图像的位图,可以用于图标(QCursor)或画刷(QBrush)QBitmap可以从图像文件或 QPixmap 中转换过来,也可以用QPainter 来绘制用QBitmap类创建位图实例对象的方法如下,fileName是图像文件路径

1
2
3
4
5
6
7
8
from PySide6.QtGui import QBitmap

QBitmap(self) -> None
QBitmap(QBitmap: Union[PySide6.QtGui.QBitmap, str]) -> None
QBitmap(arg__1: PySide6.QtCore.QSize) -> None
QBitmap(arg__1: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]) -> None
QBitmap(fileName: str, format: Union[bytes, NoneType]=None) -> None
QBitmap(w: int, h: int) -> None

QBitmap类继承自 QPixmap,因此具有 QPixmap 的方法

  • QBitmap的 clear()方法可以清空图像内容
  • transformed(QTransform)方法可以对位图进行转换,返回转换后的位图、参数 QTransform 的介绍参考 Qpainter绘图的内容:fromImage(QImage,flags=Qt.AutoColor)方法可以从 QImage 中创建位图并返回位图,其中参数 ags 是Qt.lmageConversionFlag 的枚举值,表示转换模式,可以取 Qt.AutoColor(由系统自动决定)或 QL,Mono0nly(单色模式)。

QtGui.QPicture

QPicture 是一个读写设备,用QPainter 可以直接在 QPicture 上绘图,并可以记录和重放QPainter 的绘图过程。QPicture 采用专用的二进制存储格式,独立于硬件,可以在任何设备上显示用QPicture 类创建图像实例的方法如下所示,其中 formatVersion 用于设置匹配更早版本的 Qt.-1表示当前版本。

1
2
3
4
from PySide6.QtGui import QPicture

QPicture(arg__1: Union[PySide6.QtGui.QPicture, int]) -> None
QPicture(formatVersion: int=-1) -> None

QPicture类的常用方法如表

QPicture的方法和参数类型 返回值的类型 说明
devType() int 返回设备号
play(QPainter) boo1 重新执行QPainter的绘图命令,成功则返回 Tue
load(fileName: str) bool 从文件中加载图像
load(dev:QIODevice) bool 从设备中加载图像
save(dev: QlODevice) bool 保存图像到设备
save(fileName: str) bool 保存图像到文件
setBoundingRect(r:QRect) None 设置绘图区域
boundingRect() QRect 返回绘图区域
setData(data:bytes,size: int) None 设置图像上的数据和数量
data() object 返回指向数据的指针
size() int 返回数据的数量

图类的应用实例

下面的程序将窗口划分为 4 个区域,在每个区域中分别显示同一张图片,左上角显示QPixmap 图,右上角显示 QBitmap 图,左下角显示经过灰度处理的 Qlmage 图,右下角显示经过亮化处理的 QImage 图。这里用到了 QPainter 类,我们将在第6章详细介绍 QPainter类的使用方法。程序的运行结果如图所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:13
# File_name: 01-图类的应用实例.py
import sys
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPixmap, QBitmap, QImage, QColor
from PySide6.QtCore import QRect


class ShowPictures(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("绘图")
self.pix = QPixmap()
self.bit = QBitmap()
self.image = QImage()

self.pix.load("../../Resources/animal/m1.png")
self.bit.load("../../Resources/animal/m2.png")
self.image.load("../../Resources/animal/m3.png")

# 下面创建两个 image 图像,分别存储灰度图和明亮图
self.image_1 = QImage(self.image.width(), self.image.height(), QImage.Format.Format_ARGB32)
self.image_2 = QImage(self.image.width(), self.image.height(), QImage.Format.Format_ARGB32)

self.gray() # 用灰度处理函数
self.bright() # 调用明亮处理函数

def paintEvent(self, param):
w = int(self.width() / 2) # 窗口的一半宽度
h = int(self.height() / 2) # 窗口的一半高度

# 创建4个矩形区域
rect1 = QRect(0, 0, w - 2, h - 2)
rect2 = QRect(w, 0, w - 2, h - 2)
rect3 = QRect(0, h, w, h)
rect4 = QRect(w, h, w, h)

# 在4个矩形区域绘画
painter = QPainter(self)
painter.drawPixmap(rect1, self.pix)
painter.drawPixmap(rect2, self.bit)
painter.drawPixmap(rect3, self.image_1)
painter.drawPixmap(rect4, self.image_2)

def gray(self):
color = QColor()
for i in range(1, self.image_1.width() + 1):
for j in range(1, self.image_1.height() + 1):
alpha = self.image.pixelColor(i, j).alpha()
r = self.image.pixelColor(i, j).red()
g = self.image.pixelColor(i, j).green()
b = self.image.pixelColor(i, j).blue()
average = int((r + g + b) / 3)
color.setRgb(average, average, average, alpha)
self.image_1.setPixelColor(i, j, color)
self.image_1.save("gray.jpg")

def bright(self):
color = QColor()
delta = 50 # RGB 增加值
for i in range(1, self.image_1.width() + 1):
for j in range(1, self.image_1.height() + 1):
alpha = self.image.pixelColor(i, j).alpha()
r = self.image.pixelColor(i, j).red() + delta
g = self.image.pixelColor(i, j).green() + delta
b = self.image.pixelColor(i, j).blue() + delta

r = 255 if r > 255 else r
g = 255 if g > 255 else g
b = 255 if b > 255 else b
color.setRgb(r, g, b, alpha)
self.image_2.setPixelColor(1, j, color)

self.image_2.save("bright.jpg")


if __name__ == '__main__':
app = QApplication(sys.argv)
window = ShowPictures()
window.show()
sys.exit(app.exec())

图标类QIcon

为了增加界面的美观性,可以为窗口和按钮类添加图标。窗口和控件通常有 Normal.ActiveDisabled和Selected状态,有些控件,例如ORadio Button,还可以有on和off状态根据控件所处的不同状态,控件的图标也会有不同的显示效果

  • Normal
  • Active
  • Disabled
  • Selected

图标类是QIcon用QIcon类创建图标实例的方法如下。可以从QPixmap中创建也可以从一个图片文件中直接创建,另外还可以利用资源文件中的图片创建图标。当从QPixmap 创建图标时,系统会自动产生窗口不同状态下对应的图像,比如窗口在禁用状态下其图标为灰色;从文件构造图标时,文件并不是立刻加载,而是当图标要显示时才加载。

1
2
3
4
5
6
from PySide6.QtGui import QIcon
QIcon(self) -> None
QIcon(engine: PySide6.QtGui.QIconEngine) -> None
QIcon(fileName: str) -> None
QIcon(other: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap]) -> None
QIcon(pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]) -> None

QIcon类的主要方法是 addFile()和 addPixmap(),它们的格式为 addFile(fileName[size- QSize()[,mode=Normal[,state=ff]]])和 addPixmap(QPixmap[, modeNormal[,state=0ff]]),其中,mode 可以取 QIcon.Normal(未活)、QIcon.Active(激活)、QIcon.Disabled(禁用)和 QIcon, Seleted(选中),state 可以取 QIcon.On 和 QIcon.off.另外,QIcon的 pixmap()方法可以获取图标的图像,isNull()方法可以判断图标的图像是否是无像素图像。

通过窗口的 setWindowIcon(QIcon)方法或控件的 setIcon(QIcon)方法可以为窗口和控件设置图标,通过应用程序QApplication 的 setWindowIcon(QIcon)方法可以为整个应用程序设置图标,例如下面的程序。

image-20230215205606256

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:15
# File_name: 01- 重写contextMenuEvent法.py
import sys
from PySide6.QtWidgets import QApplication, QWidget, QPushButton
from PySide6.QtGui import QPixmap, QIcon


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
pix = QPixmap()
pix.load("../../Resources/animal/m1.png")

icon = QIcon(pix) # 设置窗口图标
self.setWindowIcon(icon)
btn = QPushButton(self)
btn.setIcon(icon) # 设置按钮图标


if __name__ == '__main__':
app = QApplication(sys.argv)
# pix=QPixmap(":/icons/pic/student.png")
# #icon=QIcon(pix)

windows = MyWidget()
windows.show()
sys.exit(app.exec())

光标类QCursor

将光标移动到不同的控件上,并且控件在不同的状态下,可以为控件设置不同的光标形状。定义光标需要用到QtGui模块中的QCursor类。定义光标形状有两种方法,一种是用标准的形状 QtCursorShape,另一种是用自己定义的图片来定义。如果用自定义的图片来定义光标形状,需要设置光标的热点 hotx 和 hotY,hotX 和 hotY 的值是整数如果取负值则以图片中心点为热点,即 hotX=bitmap().width()/2,hotY=bitmap()height()/2。

用QCursor创建光标实例的方式如下,其中 Qt.CursorShape 设置标准的光标形状,mask参数是遮掩图像,可以用QPiyman的setMask(QPixman)方法提前给光标设置遮掩图。

如光标图像和掩图的颜色值都是 1,则结果是黑色;

如光标图像和图的颜值都是0,则结果是透明色;

如果光标图像的颜色值是 ,而掩图的颜色值 1,则结果是色。反之在 Windows 上是 XOR 运算的结果,其他系统上未定义

1
2
3
4
5
6
from PySide6.QtGui import QCursor
QCursor(self) -> None
QCursor(bitmap: Union[PySide6.QtGui.QBitmap, str], mask: Union[PySide6.QtGui.QBitmap, str], hotX: int=-1, hotY: int=-1) -> None
QCursor(cursor: Union[PySide6.QtGui.QCursor, PySide6.QtCore.Qt.CursorShape, PySide6.QtGui.QPixmap]) -> None
QCursor(pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str], hotX: int=-1, hotY: int=-1) -> None
QCursor(shape: PySide6.QtCore.Qt.CursorShape) -> None

标准的光标形状是Qt.CursorShape 的举值,Qt.CursorShape 的枚举值及光标形状如表所示。

通过窗口和控件的 setCursor()方法可以设置光标形状如 setCursorOCursor(Qt.PointingHandCursor))

参数 形状 参数 形状 参数 形状
Qt.ArrowCursor image-20230205001240998 Qt.UpArrowCursor image-20230205001255960 Qt.CrossCursor image-20230205001307176
Qt.IBeamCursor image-20230205001350176 Qt.WaitCursor image-20230205001401876 Qt.BusyCursor image-20230205001411942
Qt.ForbiddenCursor image-20230205001422983 Qt.PointingHandCursor image-20230205001437064 Qt.WhatsThisCursor image-20230205001452317
Qt.SizeVerCursor image-20230205001505884 Qt.SizeHorCursor image-20230205001515383 Qt.SizeBDiagCursor image-20230205001526173
Qt.SizeAllCursor image-20230205001536781 Qt.SplitVCursor image-20230205001544693 Qt.SplitHCursor image-20230205001552120
Qt.OpenHandCursor image-20230205001601361 Qt.ClosedHandCursor image-20230205001610114 Qt.BlankCursor 不显示空白

光标类QCursor的常用方法

光标类QCursor 的常用方法如表 2-16 所示,主要方法是用setShape(Qt.CursorShape)设置光标形状。

QCursor的方法及参数类型 返回值的类型 说明
setShape(Qt.CursorShape None 设置光标形状
shape() Qt.CursorShape 获取形状
bitmap() QBitmap 获取 QBitmap 图
pixmap() QPixmap 获取 QPixmap 图
hotSpott) QPoint 获取热点位置
mask() QBitmmsp 获取遮掩图
[static]setPos(x:int.y:int) None 设置光标热点到屏幕坐标系下的指定位置
[static]sexPos{p: QPoint) None 设置光标热点到屏幕坐标系下的指定位置
[static]pos() QPoint 获取光标热点在屏幕坐标系下的位置

光标类QCursor 的应用实例

下面的程序在窗口上绘制图片,然后设置两个 32X32 像素的 QBitmap 图片,图片的填充颜色分别为白色和黑色,用这两个 QBitap 作为光标和遮掩图。

image-20230215205521785

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:17
# File_name: 光标类QCursor 的应用实例.py
import sys

import PySide6
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPixmap, QBitmap, QCursor
from PySide6.QtCore import QRect, Qt


class SetCursor(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
bit = QBitmap(32, 32) # 创建32x32的位图
bit_mask = QBitmap(32, 32) # 创建32x32的位图
bit.fill(Qt.black) # 设置填充颜色
bit_mask.fill(Qt.white) # 设置填充颜色
self.setCursor(QCursor(bit, bit_mask)) # 设置光标

def paintEvent(self, event: PySide6.QtGui.QPaintEvent) -> None:
pix = QPixmap()
rect = QRect(0, 0, self.width(), self.height())
pix.load("../../Resources/animal/m1.png")

painter = QPainter(self)
painter.drawPixmap(rect, pix)


if __name__ == '__main__':
app = QApplication(sys.argv)
window = SetCursor()
window.show()
sys.exit(app.exec())

地址类QUrl

要获取网站上的资源或访问一个网站,需要知道资源或网站的 URL 地址。URL(uniform resource locator)是统一资源定位系统,是互联网上用于指定资源位置的表示方法,它有固定的格式。

URL格式介绍

一个URL 地址的格式如图 所示,由 scheme、user、password、host、port和fragment等部分构成,以下是对各部分的说明

image-20230215205752085

scheme 指定使用的传输协议,它由 URL 起始部分的一个或多个 ASCII字符表示scheme 只能包含 ASCII 字符,对输人不作转换或解码,必须以 ASCII 字母开始scheme可以使用的传输协议如表

所示。

协议 说 明
file 本地计算机上的文件,格式:file:///
http 通过HTTP访问资源,格式:HTTP://
bttps 通过安全的 HTTPS访问资源,格式:HTTPS://
ftp 通过FTP访问资源,格式:FTP://
mailto 资源为电子邮件地址,通过SMTP访问,格式:mailto:
MMS 支持 MMS(媒体流)协议(软件如 Windows Media Player),格式:MMS:/
ed2k 支持 ed2k(专用下载链接)协议的P2P软件(如电驴)访问资源,格式:ed2k:
Flashget 支持 Flashget(专用下载链接)协议的 P2P 软件(如快车)访问资源,格式:Flashget:/
thunder 通过支持thunder(专用下载链接)协议的 P2P 软件(如迅雷)访问资源,格式: thunder://
gopher 通过Gopher协议访问资源
  • authority由用户信息、主机名和端口组成。所有这些元素都是可选的即使authority为空,也是有效的。authority的格式为”username:password @hostname:port”用户信息(用户名和密码)和主机用”@”分割,主机和端口用”分割。如果用户信息为空,则”@”必须省略;端口为空时,可以使用”:”。
  • userinfo指用户信息是URL中authority可选的一部分。用户信息包括用户名和一个可选的密码,由”:”分割,如果密码为空,则”:”必须省略。
  • host 指存放资源的服务器主机名或IP地址
  • port是可选的,省略时使用方案的默认端口。各种传输协议都有默认的端口号,如HTTP的默认端口为80。如果输入时省略,则使用默认端口号。有时候出于安全或其他考虑,可以在服务器上对端口进行重定义,即采用非标准端口号,此时 URI中就不能省略端口号。
  • Path 是由”/“隔开的字符串,一般用来表示主机上的一个路径或文件地址,path 在authority 之后query 之前。
  • fragment指定网络资源中的片断,是 URL 的最后一部分,由”#”后面跟的字符串表示。它通常指的是用于 HTTP 页面上的某个链接或错点。一个网页中有多个名词解释,可使用fragment 直接定位到某一名词解释。例如”https://doc.qt.io/qt-5/qurl.html# setUserInfo”中”# setUserInfo”表示定位到网页中的”setUserInlo”内容
  • query 指查询字符串,是可选的,用于给动态网页(如使用CGIISAPIPHP/JSP/ASP、NET 等技术制作的网页)传递参数。可有多个参数,用”&”隔开,每个参数的名和值用=连接。

QUrl类的常用方法

PySide中用QUrl 类定义 URL 地址,QUr1可以用解码模式百分比编码加密模式定义URL。

解码模式适合直接阅读,加密模式适合互联网传播。

用QUrl 类定义 URL 地址的方法如下,其中 url是 URL 的格式地址文本,mode 可以 QUrl.TolerantMode(修正地址中的错误)、QUrlStrictMode(只使用有效的地址)。

1
2
3
4
5
from PySide6.QtCore import QUrl

QUrl(self) -> None
QUrl(copy: Union[PySide6.QtCore.QUrl, str]) -> None
QUrl(url: str, mode: PySide6.QtCore.QUrl.ParsingMode=Instance(QUrl.ParsingMode.TolerantMode)) -> None

QUrl类的常用方法如表所示。可以给 URL 的每部分单独赋值,也可进行整体赋值,或者用其他方式构造 URL 地址。QUrl类的主要方法介绍如下

  • 可以用setScheme(str)、setUserName(str,mode)、setPassword(str,mode)、setHost(str,mode), setPath(str , mode), setPort(int) , setFragment(str, mode).setQuery(str,mode)和setQuery(QUrlQuery)方法分别设置URL 地址的各部分的值,也可以用setUserInfo(str;mode) setAuthority(str,mode)方法设置多个部分的值用setUrl(str,mode)方法设置整个 URL值,其中参数 mode是QUrlParsingModemode枚举值,可以取QUrlTolerantMode(修正地址中的错误)QUrlStrictMode(只使用有效的地址)或 QUrlDecodedMode(百分比解码模式只使用于分项设置)
  • QUrl除了用上面的方法,还可以从字符串或本地文件中创建。用fromLocalFile(str)方法可以用本机地址字符串创建一个QUrl;用fromStringList(Sequence[str],mode=QUrlTolerantMode)方法可以将满足URL规则的字符串列表转成QUr1列表,并返回List[QUrl];用fromUserInput(str)方法可以将不是很清足URL地址规则的字符串转换成有效的QUrl例如fromUserInput(“ftp.nsdwproject.org”)将变换成 QUrl(“ftp:// tp.nsdw-project.org”);用fromEncoded(bytes;mode=QUrlTolerantMode)方法将编码形式的二进制数据转换成QUrl
  • 可以将QUrl表示的地址转换成字符串,用toDisplayString(options=QurlPrettyDecoded)方法转换成易于辨识的字符串用toLocalFile()方法转换成本机地址,用toString(options-QUrl, PrettyDecoded)方法将 URL地址转换成字符串,用toStringList(Sequence[QUrl],options=QUrl, PrettyDecoded)方法将多个 QUr转换成字符串列表,其中参数 options 是 QUr.FormattingOptions 的枚举类型,可以取的值有 QUrl.RemoveScheme(移除传输协议)QUrlRemovePassword.QUrl, RemoveUserInfo, QUrl, RemovePort、QUrl.RemoveAuthority、 QUr.RemovePath, QUrl, RemoveQuery, QUrl, RemoveFragment, QUrl, RemoveFilename.QUrl,None(没有变化)QUrl,PreferLocalFile(如果是本机地址,返回本机地址)QUrl, StripTrailingSlash(移除尾部的斜线)或 QUrl.NormalizePathSegments(移除多余的路径分隔符,解析”,”和”.”)
  • URL 地址可以分为百分比编码形式或未编码形式未编码形式适用于显示给用户,编码形式通常会发送到 Web 服务。用toEncoded(options=QUrlFullyEncoded)方法将 URL 地址转换成编码形式,并返回 QBytesArray; 用fromEncoded(Union[QByteArray, bytes, bytearray], mode=QUrlTolerantMode)方法将编码的 URL 地址转换成非编码形式,并返回 QUrl
QUrI的方法及参数类型 返回值 说 明
setScheme(scheme: str) None 设置传输协议
setUserName(userName: str,mode=QUrl.DecodedMode) None 设置用户名
setPassword(password: str,mode=QUrI.DecodedMode) None 设置密码
setHost(host: str, mode=QUrI.DecodedMode) None 设置主机名
setPath(path: str, mode=QUrI.DecodedMode) None 设置路径
setPort(port:int) . None 设置端口
setFragment(fragment: str,mode=QUrl.TolerantMode) None 设置片段
setQuery(query: str, mode=QUrl.TolerantMode) None 设置查询
setUserInfo(userInfo: str, mode=QUrl.TolerantMode) None 设置用户名和密码
setAuthority(authority: str,mode=QUrl.TolerantMode) None 设置用户信息、主机和端口
setUrl(url: str,mode=QUrl.TolerantMode) None 设置整个URI.值
[static]fromLocalFile(str) QUrI 将本机文件地址转换成QUrl
[static]fromStringList(Sequence[str], mode=QUrl.TolerantMode) List[QUrl] 将多个地址转换成 QUrl列表
[static]fromUserInput(str) QUrI 将不是很符合规则的文本转换成QUrl
[static]fromEncoded(bytes,mode=QUrl.TolerantMode) QUrl 将编码形式的二进制数据转换成QUrl
toDisplayString(options=QUrI.PrettyDecoded) str 转换成字符串
toLocalFile() str 转换成本机地址
toString(options=QUrl.PrettyDecoded) Str 转换成字符串
[static]toStringList(Sequence[QUrl], options=QUrl.PrettyDecoded) List[str] 转换成字符串列表
toEncoded(options=QUrl.FullyEncoded) QByteArray 转换成编码形式
isLocalFife() bool 获取是否是本机文件
isValid() bool 获取 URL地址是否有效
isEmpty() bool 获取 URL地址是否为空
errorString() str 获取解析地址时的出错信息
clear() None 清空内容

窗口/窗口控件、对话框以及相关功能类

窗口QWidget

1
2
3
QWidget(self, 
parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None,
f: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

QWidget是所有可视化组件的基类,所有可视组件直接或间接继承,QWidget继承 QObject,拥有其所有特性,

一个最简单的空白控件,接收各种事件(鼠标键盘),绘制在桌面上, 展示给用户看。

  • 每个控件都是矩形的,它们按Z轴顺序排序。
  • 控件由其父控件和前面的控件剪切
  • 没有父控件的控件, 称之为窗口,系统会自动把之作为窗口处理

QWidget常用方法

QWidget的方法及参数类型 返回值的类型 说 明
[slot]show() None 显示窗口,等同于setVisible(True)
[slot]setHidden(bool) None 设置隐藏状态
[slot]hide() None 隐藏窗口
setVisible(bool) None 设置窗口是否可见
[slot]raise_() None 提升控件,放到控件栈的顶部
[slot]lower() None 降低控件,放到控件栈的底部
[slot]close() bool 关闭窗口,如果成功则返回 True
setWindowIcon(QIcon) None 设置窗口的图标
windowIcon() QIcon 获取窗口的图标
[slot]setWindowTitle(str) None 设置窗口的标题文字
windowTitle() str 获取窗口标题的文字
[slot]setWindowModified(bool) None 设置文档是否修改过,可依此在退出程 序时提示保存
isWindowModified() Bool 获取窗口的内容是否修改过
setWindowIconText(str) None 设置窗口图标的文字
windowIconText() Str 获取窗口图标的文字
setWindowModality(Qt.WindowModality) None 设置窗口的模式特征
isModal() bool 获取窗口是否有模式特征
setWindowOpacity(float) None 设置窗口的不透明度;参数值从0到1
windowOpacity() float 获取窗口的不透明度
setWindowState(Qt.WindowState) None 设置窗口的状态
windowState() Qt.WindowState 获取窗口的状态,如最大化状态
windowType() Qt.WindowType 获取窗口类型
activateWindow() None 设置成活动窗口,活动窗口可以获得键 盘输入
isActiveWindow() bool 获取窗口是否是活动窗口
setMaximun Width(maxw:int) None 设置窗口或控件的最大宽度
setMaximumHeight(minh:int) None 设置窗口或控件的最大高度
setMaximumSize(maxw: int,maxh: int) None 设置窗口或控件的最大宽度和高度
setMaximumSize(QSize) None 设置窗口或控件的最大宽度和高度
setMinimumWidth(minw: int) None 设置窗口或控件的最小宽度
setMinimumHeight(minh:int) None 设置窗口或控件的最小高度
setMinimumSize(minw:int,minh: int) None 设置窗口或控件的最小宽度和高度
setMinimumSize(QSize) None 设置窗口或控件的最小宽度和高度
setFixedHeight(h:int) None 设置窗口或控件的固定高度
setFixedWidth(w:int) None 设置窗口或控件的固定宽度
setFixedSize(QSize) None 设置窗口或控件的固定宽度和高度
setFixedSize(w:int,h: int) None 设置窗口或控件的固定宽度和高度
[slot]showFullScreen() None 全屏显示
[slot]showMaximized() None 最大化显示
[slot]showMinimized() None 最小化显示
[slot]showNormal() None 最大化或最小化显示后回到正常显示
isMaximized() bool 是否处于最大化状态
isMinimized() bool 是否处于最小化状态
isFullScreen() bool 获取窗口是否为全屏状态
setAutoFillBackGround(bool) None 设置是否自动填充背景
autoFillBackground() bool 获取是否自动填充背景
setObjectName(name:str) None 设置窗口或控件的名称
setFont(QFont) None 设置字体
font() QFont 获取字体
setPalette(QPalette) None 设置调色板
palette() QPalette 获取调色板
setUpdatesEnabled(bool) None 设置是否可以对窗口进行刷新
[slot]update() None 刷新窗口
uPdate(Union[QRegion, QPolygon, QRect]) None 刷新窗口的指定区域
uPdate(x:int.y:int.w;int,h:int) None 刷新窗口的指定区域
setCursor(QCursor) None 设置光标
cursor() QCursor 获取光标
unsetCursor() None 重置光标,使用父窗口的光标
setContextMenuPolicy(policy: Qt.ContextMenuPolicy) None 设置右键快捷菜单的弹出策略
addAction(action: QAction) None 添加动作,以便形成右键快捷菜单
addActions(actions: Sequence[QAction]) None 添加多个动作
insertAction(before: QAction,QAction) None 插入动作
insertActions(before: QAction, actions: None 插入多个动作
Sequence[QAction]) actions() List[QAction] 获取窗口或控件的动作列表
[slot]repaint() None 调用paintEvent事件重新绘制窗口
repaint(x:int,y: int,w:int,h: int) None 重新绘制指定区域
repaint(Union[QRegion, QPolygon, QRect]) None 重新绘制指定区域
scroll(dx: int,dy:int) None 窗口中的控件向左、向下移动指定的像 素,参数可为负
scroll(dx:int,dy:int,QRect) None 窗口中指定区域向左、向下移动指定的 像素
resize(QSize)、resize(int,int) None 重新设置窗口工作区的尺寸
size() QSize 获取工作区尺寸
move(QPoint)、move(x:int,y:int) None 移动左上角到指定位置
pos() QPoint 获取窗口左上角的位置
x()、y() int 获取窗口左上角的x和y坐标
frameGeometry() QRect 获取包含标题栏的外框架区域
frameSize() QSize 获取包含标题栏的外框架的尺寸
setGeometry(QRect) None 设置工作区的矩形区域
setGeometry(x;int, y:int, w: int, h:.int) None 设置工作区的矩形区域
geometry() QRect 获取不包含框架和标题栏的工作区域
width()、height() int 获取工作区的宽度和高度
rect() QRect 获取工作区域
childrenRect() QRect 获取子控件占据的区域
baseSize() QSize 如果设置了 sizeIncrement属性,获取控 件的合适尺寸
setBaseSize(basew:int,baseh:int) None 设置控件的合适尺寸
setBaseSize(QSize) None 设置控件的合适尺寸
sizeHint() QSize 获取系统推荐的尺寸
isVisible() bool 获取窗口是否可见
[slot]setDisabled(bool) None 设置失效状态
[slot]setEnabled(bool) None 设置是否激活
isEnabled() bool 获取激活状态
isWindow() bool 获取是否是独立窗口
window() QWidget 返回控件所在的独立窗口
setToolTip(str) None 设置提示信息
childAt(QPoint) QWidget 获取指定位置处的控件
childAt(x:int,y:int) QWidget 获取指定位置处的控件
setLayout(QLayout) None 设置窗口或控件内的布局
layout() QLayout 获取窗口或控件内的布局
setL ayoutDirection(Qt.LayoutDirection) None 设置布局的排列方向
setParent(parent: QWidget) None 设置控件的父窗体
setParent(QWidget,f:Qt.WindowFlags) None 设置控件的父窗体
parentWidget() QWidget 获取父窗体
[slot]setFocus() None 设置获得焦点
setSizelncrement(w: int.h: int) None 设置窗口变化时的增量值
setSizeIncrement(QSize) None 设置窗口变化时的增量值
sizeIncrement() QSize 获取窗口变化时的增量值
[slot]setStyleSheet(str) None 设置窗口或控件的样式表
setMask(QBitmap) None 设置遮掩,白色部分不显示,黑色部分 显示
setStyle(QStyle) None 设置窗口的风格
setContentsMargins(left: int,top: int, right: int,bottom:int) None 设置左、上、右、下的页边距
setContentsMargins(QMargins) None 设置左、上、右、下的页边距
setAttribute(Qt.WidgetAttribute.on=True) None 设置窗口或控件的属性
setAcceptDrops(bool) None 设置是否接受鼠标的拖放
setToolTip(str) None 设置提示信息
set ToolTipDuration(int) None 设置提示信息持续的时间(毫秒)
setWhats This(str) None 设置按ShiftF1键时的提示信息
setMouseTracking(enable:bool) None 设置是否跟踪鼠标的移动事件
hasMouseTracking() bool 获取是否有鼠标跟踪事件
underMouse() bool 获取控件是否处于光标之下
setWindowFilePath(str) None 在窗口上记录一个路径,例如打开文件 的路径
mapFrom(QWidget,QPoint) QPoint 将父容器中的点映射成控件坐标系下的点
mapFrom(QWidget,QPointF) QPointF 将父容器中的点映射成控件坐标系下的点
mapFromGlobal(QPoint) QPoint 将屏幕坐标系中的点映射成控件的点
mapFromGlobal(QPointF) QPointF 将屏幕坐标系中的点映射成控件的点
mapFromParent(QPoint) QPoint 将父容器坐标系下中的点映射成控件的点
mapFromParent(QPointF) QPointF 将父容器坐标系下中的点映射成控件的点
mapTo(QWidget,QPoint) QPoint 将控件的点的点映射成父容器坐标系下中
mapTo(QWidget,QPointF) QPointF 将控件的点的点映射成父容器坐标系下中
mapToGlobal(QPoint) QPoint 将控件的点映射到屏幕坐标系下的点
mapToGlobal(QPointF) QPointF 将控件的点映射到屏幕坐标系下的点
mapToParent(QPoint) QPoint 将控件的点映射到父容器坐标系下的点
mapToParent(QPointF) QPointF 将控件的点映射到父容器坐标系下的点
grab(rectangle: QRect=QRect(0,0, -1,-1)) QPixmap 截取控件指定范围的图像,默认为整个 控件
grabKeyboard() None 获取所有的键盘输入事件,其他控件不 再接收键盘输入事件
releaseKeyboard() None 不再获取键盘输人事件
grabMouse() None 获取所有的鼠标输人事件,其他控件不 再接收鼠标输入事件
grabMouse(Union[QCursor,QPixmap]) None 获取所有的鼠标输入事件并改变光标 形状
releaseMouse() None 不再获取鼠标输入事件
[static]find(int) QWidget 根据控件的识别ID号或句柄ID号获取 控件
[static]keyboardGrabber() QWidget 返回键盘获取的控件
[static]mouseGrabber() QWidget 返回鼠标获取的控件
[static]setTabOrder(QWidget,QWidget) None 设置窗口上的控件的Tab 键顺序
  • ·窗口的显示与关闭。用show()方法可以显示窗口,用hide()方法可以隐藏窗口,也可以用setVisible(bool)方法和 setHidden(bool)方法设置窗口的可见性,用isVisible()和 isHidden()方法判断窗口是否可见,用close()方法可以关闭窗口。当窗口被关闭时,首先向这个窗口发送一个关闭事件closeEvent(event:QCloseEvent),如果事件被接受,则窗口被隐藏;如果事件被拒绝,则什么也不做。如果创建窗口时用setAttribute(Qt.WA_QuitOnClose,on=True)方法设置了Qt.WA_QuitOnClose属性,则窗口对象会被析构(删除),大多数类型的窗口都默认设置了这个属性。close()方法的返回值bool表示关闭事件是否被接受,也就是窗口是否真的被关闭了。
  • 窗口的提升与降级。如果显示多个窗口,则窗口之间是有先后顺序的,用raise_()方法可把窗口放到前部,用lower()方法可以把窗口放到底部。
  • 窗口的状态。独立窗口有正常、全屏、最大化、最小化几种状态,用isMinimized()方法判断窗口是否为最小化,用isMaximized()方法判断窗口是否为最大化,用isFullScreen()方法 判断窗口是否为全屏,用showMinimized()方法设置以最小化方式显示窗口,用showMaximized()方法设置以最大化方式显示窗口,用showFullScreen()方法设置以全屏方式显示窗口,用showNormal()方法设置以正常方式显示窗口。另外用setWindowState(Qt.WindowStates)方法也可以设置窗口的状态,其中参数Qt.WindowStates 可以取Qt.WindowNoState(无标识,正常状态)、Qt.WindowMinimized(最小化状态)、Qt.WindowMaxmized(最大化状态)、Qt.WindowFullScreen(全屏状态)或 Qt.WindowActive(激活状态);用windowState()方法可以获取状态。

image-20230215235226837

  • 窗口的几何参数。QWidget如果作为独立窗口,则有标题栏、框架和工作区;如果作为控件,则没有标题栏。QWidget 提供了设置和获取窗口与工作区尺寸的方法。窗口尺寸的设置是在屏幕坐标系下进行的,屏幕坐标系的原点在左上角,向右表示x方向,向下表示y方向。窗口几何参数的意义如图3-2所示,用x()、y()和pos()方法可以获得窗口左上角的坐标,用frameGeometry()方法可以获得窗口框架的几何参数,用frameSize()方法可以获得框架的宽度和高度,用geometry()方法可以获得工作区的几何参数,包括左上角的位置和宽度、高度,用rect()、size(),width()和height()方法可以获得工作区的宽度、高度。用move(int:x,int:y)方法可以将窗口左上角移动到坐标(x,y)处,用move(QPoint)方法可以将窗口左上角移动到QPoint处,用resize(w:int,h:int)方法可以设置工作区的宽度和高度,用resize(QSize)方法可以将工作区宽度和高度设置成QSize,用setGeometry(x:int,y:int,w:int,h:int)方法可以将工作区的左上角移动到(x,y)处,宽度改为w,高度改为h。

  • 焦点。焦点用来控制同一个独立窗口内哪一个控件可以接受键盘事件,同一时刻只能有一个控件获得焦点。用setFocus()方法可以使一个控件获得焦点,用clearFocus()方法可以使控件失去焦点,用hasFocus()方法可以获取控件是否有焦点。

  • 活跃。当有多个独立窗口同时存在时,只有一个窗口能够处于活跃状态。系统产生的键盘、鼠标等输入事件将被发送给处于活跃状态的窗口。一般来说,这样的窗口会被提升到堆叠层次的最上面,除非其他窗口有总在最上面的属性。用activateWindow()方法可以使窗口活跃,用isActiveWindow()方法可以查询窗口是否活跃。

  • 激活。处于激活状态的窗口才有可能处理键盘和鼠标等输入事件;反之,处于禁用状态的窗口不能处理这些事件。用setEnabled(bool)方法或 setDisabled(bool)方法可以使窗口激活或失效,用isEnabled()方法可以查询窗口是否处于激活状态。

  • 窗口标题和图标。用setWindowTitle(str)方法可以设置窗口的标题文字,用setWindowIcon(QIcon)方法可以设置窗口的图标,用setWindowIconText(str)方法可以设置图标的文字,用windowTitle()方法和 windowIcon()方法可以获取窗口的标题文字和图标。

  • 字体和调色板。用setFont(QFont)和 setPalette(QPalette)方法可以设置窗口的字体和调色板,用font()和 palette()方法可以获取字体和调色板。

  • 窗口的布局。用setLayout(QLayout)方法可以设置窗口的布局,用layout()方法可以获取窗口的布局,用setLayoutDirection(Qt.LayoutDirection)方法可以设置布局的方向,其中参数Qt.LayoutDirection 可以取 Qt.LeftToRight、Qt.RightToLeft或Qt.LayoutDirectionAuto。

  • 光标。用setCursor(QCursor)方法可以为窗口或控件设置光标,用cursor()方法可以获取光标,用unsetCursor()方法可以重置光标,重置后的光标使用父窗口的光标。

  • 父窗口。用setParent(QWidget)方法可以设置控件的父窗口或容器,用parentWidget()方法可以获取父窗口或容器。

  • 窗口属性。用setAttribute(Qt.WidgetAttribute,on=True)方法可以设置窗口的属性,用testAttribute(Qt.WidgetAttribute)方法可以测试是否设置了某个属性,其中参数Qt.WidgetAttribute的常用取值如表3-4所示。

    Qt.WidgetAttribute的取值 说 明
    Qt.WA_DeleteOnClose 调用close()方法时删除窗口而不是隐藏窗口
    Qt.WA_QuitOnClose 最后一个窗口如果有Qt.WA_DeleteOnClose 属性,则执行 close()方法时退出程序
    Qt.WA_AcceptDrops 接受鼠标拖放的数据
    Qt.WA_AlwaysShowToolTips 窗口失效时也显示提示信息
    Qt.WA_Disabled 窗口处于失效状态,不接收键盘和鼠标的输入
    Qt.WA_DontShowOnScreen 窗口隐藏
    Qt.WA_ForceDisabled 即使父窗口处于激活状态,窗口也强制失效
    Qt.WA_TransparentForMouseEvents 窗口和其子窗口忽略鼠标事件
    Qt.WA_RightToLeft 布局方向从右向左
    Qt.WA_ Show WithoutActivating 当不激活窗口时,显示窗口
  • 右键快捷菜单的弹出策略。在窗口或控件上右击鼠标时,将弹出右键快捷菜单(上下文菜单)

    • 用setContextMcenuPolicy(policy: Qt.ContextMenuPolicy)方法设置弹出快捷菜单的策略和处理方式,其中 policy 是 Qt.ContextMenuPolicy的枚举值,可取值如下表所示。

      Qt.ContextMenuPolicy的取值 说 明
      Qt.NoContextMenu 0 控件没有自己特有的快捷菜单,使用控件父窗口或父容器 的快捷菜单
      Qt.DefaultContextMenu 1 鼠标右键事件交给控件的contextMenuEvent()函数处理
      Qt.ActionsContextMenu 2 右键快捷菜单是控件或窗口的actions()方法获取的动作
      Qt.CustomContextMenu 3 用户自定义快捷菜单,右击鼠标时,发射 customContextMenuRequested(QPoint)信号,其中 QPoint 是鼠标右击时光标的位置
      Qt.PreventContextMenu 4 鼠标右键事件交给控件的mousePressEvent()和 mouseReleaseEvent()函数进行处理
    • policy 取 Qt.DefaultContextMenu 或 Qt.PreventContextMenu时,鼠标右击事件交给控件的事件处理函数进行处理,有关事件处理方面的内容详见事件处理章节;

    • policy 取 Qt.CustomContextMenu 时,右击鼠标时会发射customContextMenuRequested(QPoint)信号,此时用户可以在槽函数中编写菜单,用菜单的popup(pos:QPoint)方法弹出菜单,pos是菜单的弹出位置,有关菜单的内容见3.2节,policy 取Qt.ActionsContextMenu时,快捷菜单由窗口或控件的动作构成,有关动作的内容菜单节

    • 用窗口或控件的addAction(action:QAction)或addActions(actions: Sequence[QAction])方法可以添加动作,

    • 用insertAction(before: QAction, action: QAction)或 insertActions(before: QAction.actions:Sequence[QAction])方法可以插入动作,用actions()方法获取动作列表。

顶层窗口设置

窗口控件的创建和样式设置

创建窗口
1
__init__(self, parent=None, flags)

创建控件的时候, 设置父控件, 以及标志位,调整整个应用程序窗口外观

  • parent 父控件,没有父控件的控件,即顶层控件,控件 一般指非窗口控件
  • flags 标志位,创建时直接传入 type: PySide6.QtCore.Qt.WindowType即可见下面窗口外观标志表
创建窗口后设置窗口标志

不同于直接创建窗口时传入标志后面设置样式,创建后设置和创建时设置窗口WindowType效果一样

1
2
3
4
5
6
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QWidget

win=QWidget(parent=None, f=Qt.WindowType.Widget)

win.setWindowFlags(Qt.WindowType.Dialog)
方法 说明
window.setWindowFlags(type: PySide6.QtCore.Qt.WindowType) 设置窗口样式,WindowType见标志表
windowFlags() 获取当前窗口标志
窗口类型Qt.WindowsFlaga
Qt.WindowFlags的取值 说明
Qt.Widget 这是默认值,如果QWidget有父容器或窗口,它成为一个控件;如果没有, 则它会成为独立的窗口
Qt.Window 不管QWidget是否有父容器或窗口,它都将成为一个有窗口框架和标题栏 的窗口
Qt.Dialog QWidget将成为一个对话框窗口(QDialog)。对话框窗口在标题栏上通常 没有最大化按钮和最小化按钮,如果是从其他窗口中弹出了对话框窗口,可 以通过 setWindowModality()方法将其设置成模式窗口。在关闭模式窗口之前,不允许对其他窗口进行操作
Qt.Sheet 在 Mac系统中,QWidget 将是一个表单(sheet)
Qt.Drawer 在 Mac 系统中,QWidget 将是一个抽屉(drawer)
Qt.Popup QWidget是弹出式顶层窗口,这个窗口是带模式的,常用来做弹出式菜单
Qt.Tool QWidget 是一个工具窗,工具窗通常有比正常窗口小的标题栏,可以在其上 面放置按钮。如果QWidget 有父窗口,则QWidget 始终在父窗口的顶层
Qt.ToolTip QWidget是一个提示窗,没有标题栏和边框
Qt.SplashScreen QWidget是一个欢迎窗,这是 QSplashScreen的默认值
Qt.Desktop QWidget是个桌面,这是QDesktopWidget的默认值
Qt.SubWindow QWidget 是子窗口,例如QMidSubWidow窗口
Qt.ForeignWindow QWidget是其他程序创建的句柄窗口
Qt.CoverWindow QWidget是一个封面窗口,当程序最小化时显示该窗口
影响窗口外观的Qt.WindowFlags的取值
Qt.WindowFlags的取值 说 明
Qt.MSWindowsFixedSizeDialogHint 对于不可调整尺寸的对话框Qdialog添加窄的边框
Qt.MSWindowsOwnDC 为Windows 系统的窗口添加上下文菜单
Qt.BypassWindowManagerHint 窗口不受窗口管理协议的约束,与具体的操作系统有关
Qt.X11BypassWindowManagerHint 无边框窗口,不受任务管理器的管理。如果不是用activateWindow()方法激活,不接受键盘输人
Qt.FramelessWindowHint 无边框和标题栏窗口,无法移动和改变窗口的尺寸
Qt.NoDropShadowWindowHint 不支持拖放操作的窗口
Qt.CustomizeWindowHint 自定义窗口标题栏,不显示窗口的默认提示信息,以下6 个可选值可配合该值一起使用
Qt.WindowTitleHint 有标题栏的窗口
Qt.WindowSystemMenuHint 有系统菜单的窗口
Qt.WindowMinimizeButtonHint 有最小化按钮的窗口
Qt.WindowMaximizeButtonHint 有最大化按钮的窗口
Qt.WindowMinMaxButtonsHint 有最小化和最大化按钮的窗口
Qt.WindowCloseButtonHint 有关闭按钮的窗口
Qt.WindowContextHelpButtonHint 有帮助按钮的窗口
Qt.MacWindowToolBarButtonHint 在 Mac 系统中,添加工具栏按钮
Qt.WindowFullscreenButtonHint 有全屏按钮的窗口
Qt.WindowShadeButtonHint 在最小化按钮处添加背景按钮
Qt.WindowStaysOnTopHint 始终在最前面的窗口
Qt.WindowStaysOnBottomHint 始终在最后面的窗口
Qt.WindowTransparentForInput 只用于输出,不能用于输入的窗口
Qt.WindowDoesNotAcceptFocus 不接受输入焦点的窗口
Qt.MaximizeUsingFullscreenGeometryHint 窗口最大化时,最大化地占据屏幕

下面举一个有关窗口类型的实例,程序运行的界面如图所示。

运行下面的程序,先出现一个欢迎界面,窗口类型是Qt.SplashScreen,这个界面上没有标题栏,只有一个标签和一个按钮,

单击”进入>>”按钮后,弹出两个新的窗口,这两个窗口的类型分别是Qt CustomizeWindowHint和Qt.Window。窗口类型是 Qt.CustomizeWindowHint 时将不会有标题栏,程序中用竖直布局在窗口上部放置QWidget 控件作为标题栏,并添加一个QLabel 和一个 QPushButton,可以放置更多的控件以丰富标题栏。窗口现在还不能移动,可以为窗口编写鼠标按键事件,以便在拖动标题栏时窗口能移动。

image-20230215220829930

image-20230215220902958image-20230215220914624

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QFrame, QVBoxLayout, QHBoxLayout
from PySide6.QtCore import Qt
from PySide6.QtGui import QFont


class MyWindow(QWidget):
def __init__(self, parent=None, f=Qt.Widget):
super().__init__(parent, f)
self.setStyleSheet("border : 0px")
self.setContentsMargins(0, 0, 0, 0)
self.resize(400, 300)
self.move(300, 200)
font=QFont()
font.setPointSize(10)

# 自定义标题栏
title=QLabel("欢迎来到我的世界")
title.setFont(font)
closeBtn=QPushButton("关闭")
closeBtn.clicked.connect(self.close)
closeBtn.setFixedSize(30, 15)
closeBtn.setFont(font)
closeBtn.setContentsMargins(0, 0, 0, 0)

titleBar=QWidget()
titleBar.setFixedHeight(13)
H=QHBoxLayout(titleBar)
H.setAlignment(Qt.AlignTop)
H.setContentsMargins(0, 0, 0, 0)
H.setSpacing(0)

H.addWidget(title)
H.addWidget(closeBtn)
workArea=QFrame()
V=QVBoxLayout(self)
V.setSpacing(0)
V.addWidget(titleBar)
V.addWidget(workArea)
V.setContentsMargins(0, 0, 0, 0)
# add more...,下面创建有父窗口的窗口,窗口类型是Qt.windows
test_window=QWidget(parent=self, f=Qt.Window)
test_window.setWindowTitle("Test Window")
test_window.show()
test_window.resize(300, 100)


class WelcomeWindoes(QWidget):
def __init__(self, parent=None, f=Qt.Widget):
super().__init__(parent, f)
self.resize(300, 100)
self.setupUi()

def setupUi(self):
label=QLabel("欢迎来到我的世界!")
label.setParent(self)
label.setGeometry(70, 30, 200, 30)
font=label.font()
font.setPointSize(15)
label.setFont(font)
btn=QPushButton("进入>>", self)
btn.setGeometry(200, 70, 70, 20)
btn.clicked.connect(self.enter)

def enter(self):
self.win=MyWindow(f=Qt.FramelessWindowHint) # 无边框窗口
self.win.show() # 显示另一个窗口
self.close()


if __name__=='__main__':
app=QApplication(sys.argv)
welcome=WelcomeWindoes(parent=None, f=Qt.SplashScreen) # 欢迎窗口
welcome.show()
sys.exit(app.exec())

窗口图标

方法 说明
setWindowIcon(QIcon(“resource/header_icon.png”)) 设置窗口图标
windowIcon() 获取窗口图标

窗口标题

方法 说明
setWindowTitle(“title”) 设置窗口标题
windowTitle() 获取窗口标题

窗口不透明度

方法 说明
setWindowOpacity(level) 设置窗口不透明度, level限制0-1,1为完全不透明
windowOpacity() 获取窗口不透明度

窗口状态

方法 说明
setWindowState(self, state: PySide6.QtCore.Qt.WindowState) -> None 设置窗口状态 WindowState可为状态值对象表
windowState() 获取窗口状态

状态值对象表

说明
Qt.WindowNoState 无状态(默认)
Qt.WindowMinimized 最小化
Qt.WindowMaximized 最大化
Qt.WindowFullScreen 全屏,不显示任务栏标题栏等全屏显示(慎用最好配好相关快捷键切换其他状态)
Qt.WindowActive 活动窗口

最大化最小化

控制
方法 说明
showFullScreen() 全屏显示 不包含窗口框架
showMaximized() 最大化 包括窗口框架
showMinimized() 最小化
showNormal() 正常
判定
方法 说明
isMinimized() 是否是最小化窗口
isMaximized() 是否是最大化窗口
isFullScreen() 是否全屏

大小位置

189ecbc4f448edfa25f173fc4682aeed5ed33b188f50d8b3e9965b4a9f15cbf8

方法 说明
x() 相对于父控件的x位置,包含窗口框架。顶层控件(没有父控件)则相对于桌面的x位置
y() 相对于父控件的y位置,包含窗口框架。顶层控件(没有父控件)则相对于桌面的y位置
pos() x和y的组合,包含窗口框架返回QPoint(x, y)
width() 控件的宽度,不包含任何窗口框架
height() 控件的高度,不包含任何窗口框架
size() width和height的组合,不包含任何窗口框架,QSize(width, height)
geometry() 用户区域相对于父控件的位置和尺寸组合,QRect(x, y, width, height)
rect() 0, 0, width, height的组合,QRect(0, 0, width, height)
frameSize() 框架大小
frameGeometry() 框架尺寸
minimumWidth() 最小尺寸的宽度
minimumHeight() 最小尺寸的高度
minimumSize() 最小尺寸
maximumWidth() 最大尺寸的宽度
maximumHeight() 最大尺寸的高度
maximumSize() 最大尺寸
move(x, y) 操控的是x, y;也就是pos包括窗口框架
resize(width, height) 操控的是宽高 不包括窗口框架
setGeometry(x_noFrame, y_noFrame, width, height) 注意,此处参照为用户区域
adjustSize() 根据内容自适应大小
setFixedSize() 设置固定尺寸
setMaximumWidth() 设置最大宽度
setMaximumHeight() 设置最大高度
setMaximumSize() 设置最大尺寸
setMinimumWidth() 设置最小宽度
setMinimumHeight() 设置最小高度
setMinimumSize() 设置最小尺寸

==注意: 控件显示完毕之后, 具体的位置或者尺寸数据才会正确==

内容边距

调整控件内容边距, 使得显示更自然

方法 说明
setContentsMargins(左, 上, 右, 下) 设置内容边距
getContentsMargins() 获取内容边距,返回(左, 上, 右, 下)
contentsRect() 获取内容区域

==必须是控件本身留够对应的大小==

控件区域鼠标形状

  • 设置鼠标形状:setCursor(sizexxCursor)
  • 重置形状,恢复设置鼠标原样:qwidget.unsetCursor()
1
setCursor(arg__1: Union[PySide6.QtGui.QCursor, PySide6.QtCore.Qt.CursorShape, PySide6.QtGui.QPixmap]) -> None

设置鼠标形状

CursorShape需要导入 from PySide6.QtCore import Qt

支持以下形状:

参数 形状 参数 形状 参数 形状
Qt.CursorShape.ArrowCursor image-20230205001240998 Qt.CursorShape.UpArrowCursor image-20230205001255960 Qt.CursorShape.CrossCursor image-20230205001307176
Qt.CursorShape.IBeamCursor image-20230205001350176 Qt.CursorShape.WaitCursor image-20230205001401876 Qt.CursorShape.BusyCursor image-20230205001411942
Qt.CursorShape.ForbiddenCursor image-20230205001422983 Qt.CursorShape.PointingHandCursor image-20230205001437064 Qt.CursorShape.WhatsThisCursor image-20230205001452317
Qt.CursorShape.SizeVerCursor image-20230205001505884 Qt.CursorShape.SizeHorCursor image-20230205001515383 Qt.CursorShape.SizeBDiagCursor image-20230205001526173
Qt.CursorShape.SizeAllCursor image-20230205001536781 Qt.CursorShape.SplitVCursor image-20230205001544693 Qt.CursorShape.SplitHCursor image-20230205001552120
Qt.CursorShape.OpenHandCursor image-20230205001601361 Qt.CursorShape.ClosedHandCursor image-20230205001610114 Qt.CursorShape.BlankCursor 不显示空白
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QWidget, QApplication, QComboBox

cur={
"ArrowCursor": Qt.CursorShape.ArrowCursor,
"UpArrowCursor": Qt.CursorShape.UpArrowCursor,
"CrossCursor": Qt.CursorShape.CrossCursor,
"IBeamCursor": Qt.CursorShape.IBeamCursor,
"WaitCursor": Qt.CursorShape.WaitCursor,
"BusyCursor": Qt.CursorShape.BusyCursor,
"ForbiddenCursor": Qt.CursorShape.ForbiddenCursor,
"PointingHandCursor": Qt.CursorShape.PointingHandCursor,
"WhatsThisCursor": Qt.CursorShape.WhatsThisCursor,
"SizeVerCursor": Qt.CursorShape.SizeVerCursor,
"SizeHorCursor": Qt.CursorShape.SizeHorCursor,
"SizeBDiagCursor": Qt.CursorShape.SizeBDiagCursor,
"SizeAllCursor": Qt.CursorShape.SizeAllCursor,
"SplitVCursor": Qt.CursorShape.SplitVCursor,
"SplitHCursor": Qt.CursorShape.SplitHCursor,
"OpenHandCursor": Qt.CursorShape.OpenHandCursor,
"ClosedHandCursor": Qt.CursorShape.ClosedHandCursor,
"BlankCursor": Qt.CursorShape.BlankCursor
}


def change_cur(win, _cur):
win.setCursor(cur[_cur])


app=QApplication(sys.argv) # 初始化界面

qwidget=QWidget() # 生成一个主窗口
qwidget.resize(500, 500)
qwidget.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

cue_l=list(cur.keys())
qcombobox=QComboBox(qwidget)
qcombobox.resize(300, 35)
qcombobox.move((qwidget.width() - qcombobox.width()) // 2,(qwidget.height() - qcombobox.height()) // 4)
qcombobox.addItems(cue_l)

qcombobox.activated.connect(lambda: change_cur(qwidget, qcombobox.currentText()))

qwidget.show() # 显示窗口以及其子控件

sys.exit(app.exec()) # 主循环和退出

自定义QCursor对象

获取鼠标

导入:from PySide6.QtGui import QCursor, QPixmap

获取QCursor对象

1
2
3
4
5
QCursor(self) -> None
QCursor(self, bitmap: Union[PySide6.QtGui.QBitmap, str], mask: Union[PySide6.QtGui.QBitmap, str], hotX: int=-1, hotY: int=-1) -> None
QCursor(self, cursor: Union[PySide6.QtGui.QCursor, PySide6.QtCore.Qt.CursorShape, PySide6.QtGui.QPixmap]) -> None
QCursor(self, pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str], hotX: int=-1, hotY: int=-1) -> None
QCursor(self, shape: PySide6.QtCore.Qt.CursorShape) -> None

以上是方法注释

自定义鼠标形状

自定义 QCursor对象

后通过 setCursor(QCursor)设置自定义形状

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys
from PySide6.QtCore import Qt
from PySide6.QtGui import QCursor, QPixmap
from PySide6.QtWidgets import QWidget, QApplication

app = QApplication(sys.argv) # 初始化界面

qwidget = QWidget() # 生成一个主窗口
qwidget.resize(500, 500)
qwidget.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

shape = QPixmap(../../Resources/Images/d8.png") # QPixmap对象鼠标形状
qcursor = QCursor(shape) # 获取QCursor对象
qwidget.setCursor(qcursor) # 设置鼠标形状为自定义QCursor对象

qwidget.show() # 显示窗口以及其子控件

sys.exit(app.exec()) # 主循环和退出

image-20230205003929570

设置自定义鼠标大小

通过设置 QPixmap对象设置

1
2
shape=QPixmap("./d8.png")  # QPixmap对象鼠标形状
shape=shape.scaled(50, 50) # scaled修改尺寸需要注意返回的是一个新的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys
from PySide6.QtCore import Qt
from PySide6.QtGui import QCursor, QPixmap
from PySide6.QtWidgets import QWidget, QApplication

app = QApplication(sys.argv) # 初始化界面

qwidget = QWidget() # 生成一个主窗口
qwidget.resize(500, 500)
qwidget.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

shape = QPixmap(../../Resources/Images/d8.png") # QPixmap对象鼠标形状
shape = shape.scaled(50, 50)

qcursor = QCursor(shape) # 获取QCursor对象
qwidget.setCursor(qcursor) # 设置鼠标形状为自定义QCursor对象

qwidget.show() # 显示窗口以及其子控件

sys.exit(app.exec()) # 主循环和退出

对比上一个自定义发现明显变小

image-20230205004819229

设置自定义鼠标热点位置

默认自定义时鼠标形状时间可点击位置为鼠标图标中间

在获取QCursor对象时传入参数hotX、hotY即可

1
2
3
4
qcursor=QCursor(shape, 0, 0)
"""
QCursor(self, pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str], hotX: int=-1, hotY: int=-1) -> None
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys
from PySide6.QtCore import Qt
from PySide6.QtGui import QCursor, QPixmap
from PySide6.QtWidgets import QWidget, QApplication

app = QApplication(sys.argv) # 初始化界面

qwidget = QWidget() # 生成一个主窗口
qwidget.resize(500, 500)
qwidget.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

shape = QPixmap(../../Resources/Images/d8.png") # QPixmap对象鼠标形状
shape = shape.scaled(50, 50)

qcursor = QCursor(shape, 25, 50) # 获取QCursor对象
qwidget.setCursor(qcursor) # 设置鼠标形状为自定义QCursor对象

qwidget.show() # 显示窗口以及其子控件

sys.exit(app.exec()) # 主循环和退出

image-20230205005708964

鼠标跟踪

所谓的鼠标跟踪,其实就是设置检测鼠标移动事件的条件.

不跟踪 鼠标移动时,必须处于按下状态,才会触发mouseMoveEvent事件 跟踪 鼠标移动时,不处于按下状态,也会触发mouseMoveEvent事件

  • hasMouseTracking() 判定是否设置了鼠标跟踪
  • setMouseTracking(bool) 设置鼠标是否跟踪

事件

当一个控件被触发了一个特定的行为时, 就会调用特定的方法, 来将事件传递给开发人员, 方便处理 重写这些事件方法, 就可以监听相关的信息

事件 说明
显示和关闭事件 showEvent(QShowEvent) 控件显示时调用``closeEvent(QCloseEvent) 控件关闭时调用
移动事件 moveEvent(QMoveEvent) 控件移动时调用
调整大小 moveEvent(QMoveEvent) 控件移动时调用``resizeEvent(QResizeEvent) 控件调整大小时调用
鼠标事件 enterEvent(QEvent) 鼠标进入时触发 leaveEvent(QEvent) 鼠标离开时触发mousePressEvent(QMouseEvent) 鼠标按下时触发 mouseReleaseEvent(QMouseEvent) 鼠标释放时触发mouseDoubleClickEvent(QMouseEvent) 鼠标双击时触发 mouseMoveEvent(QMouseEvent) 鼠标按下后移动时触发 setMouseTracking(True) 追踪设置后,没有按下的移动也能触发
键盘事件 keyPressEvent(QKeyEvent) 键盘按下时调用``keyReleaseEvent(QKeyEvent) 键盘释放时调用
焦点事件 focusInEvent(QFocusEvent) 获取焦点时调用``focusOutEvent(QFocusEvent) 失去焦点时调用
拖拽事件 dragEnterEvent(QDragEnterEvent) 拖拽进入控件时调用dragLeaveEvent(QDragLeaveEvent) 拖拽离开控件时调用dragMoveEvent(QDragMoveEvent) 拖拽在控件内移动时调用``dropEvent(QDropEvent) 拖拽放下时调用
绘制事件 paintEvent(QPaintEvent) 显示控件, 更新控件时调用
改变事件 changeEvent(QEvent) 窗体改变, 字体改变时调用
右键菜单 contextMenuEvent(QContextMenuEvent) 访问右键菜单时调用
输入法 inputMethodEvent(QInputMethodEvent) 输入法调用

父子关系

方法 说明
childAt(x, y) 获取在指定坐标的控件
parentWidget() 获取指定控件的父控件
childrenRect() 所有子控件组成的边界矩形(左上X, 左上Y, 右下X, 右下Y)

用法扩展:

  • 点击哪个标签, 就让哪个标签背景变红,利用鼠标点击事件和childAt()(监听标签的点击事件也可以代码比较麻烦)

层级控制

同级控件需要调整控件Z轴顺序用

方法 说明
lower() 将控件降低到最底层
raise_() 将控件提升到最上层
a.stackUnder(b) 让a放在b下面

交互状态

是否可用

方法 说明
setEnabled(bool) 设置控件是否禁用
isEnabled() 获取控件是否可用

是否显示/隐藏

方法 说明
setVisible(bool) 设置控件是否绘制(默认是绘制的),不绘制则不可见,配合绘制事件一起使用
绘制是先绘制父控件后绘制子控件,未绘制父控件子控件也不展示,控件被遮挡覆盖也是会绘制的
setVisible(True) 绘制
setVisible(False) 不绘制
setHidden(bool) 设置控件是否隐藏,同样需要父控件绘制了才能展示,本质还是调用setVisible(bool)
setHidden(False)展示控件``setHidden(True)隐藏控件
show() 展示控件,效果同 setVisible(False)setHidden(True)
hide() 隐藏控件,效果同 setVisible(True)setHidden(False)
isHidden() 判定控件是否被隐藏,无论是否绘制父控件 没有直接对控件设置 setVisible(True)setHidden(False)isHidden()均是True
isVisible() 判定控件是否设置绘制,当控件的父控件和自身均被绘制才会返回True
isVisibleTo(widget) 判断控件是否会随着widget控件显示和隐藏同步变化

注意 visible:代表控件最终的状态, 是否被我们所见(被其他控件遮挡也属于可见)
hide:可理解为相对于父控件是否可见

隐藏的一定是不可见的, 反之不然

显示正在编辑状态

方法 说明
setWindowModified(bool) 设置窗口是否是被编辑状态
仅支持在设置 [*]其他符号不支持
应用:设置如窗口标题等在设置标题str中任意索引位置加入 [*],当设置 setWindowModified(True)时会自动显示 *,反之则不显示 *
image-20230205194310858
isWindowModified() 获取是否是被编辑状态

是否为活跃窗口

方法 说明
isActiveWindow() 是否为活跃窗口,主要用于多窗口当前焦点出口则处是活跃的
会自动在活跃窗口周围加上光效阴影
层级控制也不会影响活跃状态

关闭

方法 说明
close() 关闭窗口,效果同隐藏
但设置 setAttribute(Qt.WA_DeleteOnClose, True)后会在隐藏的同时销毁原对象
setAttribute(Qt.WA_DeleteOnClose, True) 设置 close()时并一同销毁对象会触发销毁事件

信息提示

状态栏提示

需要添加状态栏才能使用

方法 说明
statusTip() 获取状态栏提示
setStatusTip(str) 鼠标停在控件上时, 展示在状态栏

工具提示

方法 说明
toolTip() 获取工具提示
setToolTip(str) 设置工具提示
toolTipDuration() 获取工具提示时长
setToolTipDuration(msec) 设置提示时长,单位毫秒

whatsThis提示

需要更改状态flags, 进入?模式

方法 说明
whatsThis()
setWhatsThis(str) 切换到”查看这是啥”模式, 点击该控件时显示

焦点控制

单个控件角度

方法 说明
setFocus() 指定控件获取焦点
setFocusPolicy(Policy) 设置焦点获取策略
Policy枚举 说明
Qt.TabFocus 通过Tab键获得焦点
Qt.ClickFocus 通过被单击获得焦点
Qt.StrongFocus 可通过上面两种方式获得焦点
Qt.NoFocus 不能通过上两种方式获得焦点(默认值),setFocus仍可使其获得焦点
clearFocus() 取消焦点,系统会自动给第一个控件赋予焦点

父控件角度

结合程序的业务逻辑, 来调整焦点的操作。如按下TAB时切换到下一个输入框等

方法 说明
clearFocus() 取消焦点
focusWidget() 获取子控件中当前聚焦的控件
focusNextChild() 聚焦下一个子控件
focusPreviousChild() 聚焦上一个子控件
focusNextPrevChild(bool) True下一个; False上一个
setTabOrder(pre_widget, next_widget) 静态方法 设置子控件获取焦点的先后顺序

属性

setAttribute(Qt :: WidgetAttribute 属性,bool on=true)

遮罩

QWidget :: mask()const

返回当前在小部件上设置的遮罩。如果没有设置掩码,返回值将是一个空白区域。

另请参阅setMask(),clearMask(),QRegion :: isEmpty()和形状时钟示例。

内容拖拽

1
2
setAcceptDrops()
acceptDrops()

交互控制

1
2
scroll(int dx,int dy)
repaint()

状态控件

1
2
3
4
5
6
keyboardGrabber()
mouseGrabber()
grabMouse()
nextInFocusChain()
previousInFocusChain()
releaseKeyboard()

快捷方式

1
2
3
setShortcutAutoRepeat(int id,bool enable=true)
setShortcutEnabled(int id,bool enable=true)
grabShortcut()和releaseShortcut()

坐标转换

方法 返回参数 说明
mapFrom(QWidget,QPoint) QPoint 将父容器中的点映射成控件坐标系下的点
mapFrom(QWidget,QPointF) QPointF 将父容器中的点映射成控件坐标系下的点
mapFromGlobal(QPoint) QPoint 将屏幕坐标系中的点映射成控件的点
mapFromGlobal(QPointF) QPointF 将屏幕坐标系中的点映射成控件的点
mapFromParent(QPoint) QPoint 将父容器坐标系下中的点映射成控件的点
mapFromParent(QPointF) QPointF 将父容器坐标系下中的点映射成控件的点
mapTo(QWidget,QPoint) QPoint 将控件的点的点映射成父容器坐标系下中
mapTo(QWidget,QPointF) QPointF 将控件的点的点映射成父容器坐标系下中
mapToGlobal(QPoint) QPoint 将控件的点映射到屏幕坐标系下的点
mapToGlobal(QPointF) QPointF 将控件的点映射到屏幕坐标系下的点
mapToParent(QPoint) QPoint 将控件的点映射到父容器坐标系下的点
mapToParent(QPointF) QPointF 将控件的点映射到父容器坐标系下的点

信号

QWidget的信号及参数类型 说 明
objectNameChanged(str) 当控件的名称改变时发送信号
windowlconChanged(QIcon) 窗口图标改变时发送信号
windowlconTextChanged(str) 窗口图标的文字改变时发送信号
windowTitleChanged(str) 窗口标题改变时发送信号
customContextMenuRequested(QPoint) 通过setContextMenuPolicy(Qt.CustomContextMenu)方法设 置快捷菜单是自定义菜单,此时右击鼠标时发送信号,参数是 右击鼠标时光标的位置
destroyed() QObject对象析构时,先发送信号,然后才析构它的所有控件
destroyed(QObject) QObject对象析构时,先发送信号,然后才析构它的所有控件

窗口QMainWindow

image-20230212204033874
image-20230212204042293

主窗口QMainWindow 通常由一个菜单栏、一个状态栏、一个中心控件、多个可以停靠的工具栏和可停靠控件QDockWidget构成,中心控件为主显示区,工具栏和可停靠控件可以用鼠标进行拖拽、悬浮和停靠操作。

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

1
2
3
4
from PySide6.QtWidgets import QMainWindow

QMainNindow(parent=None)
QMainWindow(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

主窗口QMainWindow 的常用方法

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

  • 对中心控件的设置。

    • setCentralWidget(QWidget)方法可以将某个控件设置成中心控件;
    • takeCentralWidget()方法可以将中心控件从布局中移除,使用这种方法中心控件只是从布局移走,并没有真正被删除。
  • 对菜单栏的设置。

    • QMainWindow 提供了创建菜单栏的方法menuBar(),用这个方法可以获取或创建新菜单栏并返回新创建的菜单栏,可以往菜单栏中添加菜单和动作。
    • setMenuBar(menubar:QMenuBar)把已经创建好的菜单栏设置成QMainWindow 的菜单栏,用自己创建的菜单栏替换主窗口提供的菜单栏。
    • 不想把菜单栏中的菜单显示出来,可以用setMenuWidget(menubar:QWidget)方法在菜单栏中添加控件。
  • 对状态栏的设置。

    • QMainWindow 提供了创建状态栏的方法 statusBar(),用这个方法可以创建新状态栏并返回新创建的状态栏,可以往状态栏中添加控件。
    • 把已经创建好的状态栏设置成 QMainWindow 的状态栏,需要用到 setStatusBar(QStatusBar)方法,用自己创建的状态栏替换主窗口提供的状态栏。
    • setStatusBar(None)方法可以删除状态栏。
  • 对工具栏的设置。.

    • QMainWindow 可以有一个或多个工具栏,而且工具栏可以拖放到上、下、左、右不同的停靠区。

      • addToolBar(str)方法可以新建名称为str的工具栏,并返回新建的工具栏;
      • addToolBar(QToolBar)方法可以在主窗口的顶部放置已经定义好的工具栏;
      • addToolBar(Qt.ToolBarArea,QToolBar)方法可以在指定位置放置已经定义好的工具栏,其中参数Qt.ToolBarArea 的取值为Qt.Left ToolBarArea,Qt.RightToolBarArea,Qt.TopToolBarArea .Qt.BottomToolBarArea、Qt.AllToolBarAreas 或 Qt.NoToolBarArea;
      • toolBarArea(QToolBar)方法可以返回工具栏的停靠区位置;
      • removeToolBar(QToolBar)方法可以从布局中移除工具栏。
      • 通常在一个停靠区放置多个工具栏时,工具栏成一行或一列状态,如果要在一个停靠区使多个工具栏成多行或多列停放,需要用addToolBarBreak(ares:Qt.ToolBarArea=Qt.TopToolBarArea)方法为停靠区设置断点;也可以用insertToolBarBreak(before:QToolBar)方法在某个工具栏前添加断点,用removeToolBarBreak(before:QToolBar)方法移除工具栏前的断点。
    • 停靠控件设置。

      • QDockWidget(str,parent=None,Qt.WindowType)方法可以创建停靠控件,停靠控件通常作为容器使用;

      • 用停靠控件的setWidget(QWidget)方法可以为停靠控件设置控件,通常设置为容器类控件。

      • 在主窗口中用addDockWidget(Qt.DockWidgetArea,QDockWidget)方法或addDockWidget(Qt.DockWidgetArea,QDockWidget,Qt.Orientation)方法可以在指定停靠区域添加停靠控件,其中参数Qt.DockWidgetArea 可以取以下值:

        • Qt.LeftDockWidgetArea
        • Qt.RightDockWidgetArea
        • Qt.TopDockWidgetArea
        • Qt.BottomDockWidgetArea
        • Qt.AllDockWidgetAreas
        • Qt.NoDockWidgetArea

        Qt.Orientation 可以取 Qt.Horizontal或 Qt.Vertical;

      • removeDock Widget(QDockWidget)方法可以从布局中移除停靠控件。如果在一个停靠区域内放置多个停靠控件,通常用QTabWidget 控件的形式将多个停靠控件层叠在一起;如果要在一个停靠区内并排或并列放置停靠控件,需要用setDockNestingEnabled(bool)方法进行设置。

      • setTabPosition(Qt.Dock WidgetArea,QTabWidget.TabPosition)方法设置多个停靠控件层叠时 Tab 标签的位置,其中参数 QTabWidget.TabPosition 可以取以下值(分别表示上,下、右和左):

        • QTabWidget.North
        • QTabWidget.South
        • QTabWidget.East
        • QTabWidget.West
    • 用setTabShape(QTabWidget.TabShape)方法设置Tab 标签的形状,其中参数QTabWidget.TabShape 可以取以下值:

      • QTabWidget.Rounded 圆角
      • QTabWidget.Triangular 三角形。
  • 用tabifyDockWidget(first:QDockWidget,second:QDockWidget)方法可以将两个停靠控件放到一个停靠区层叠显示;tabifiedDockWidgets(QDockWidget)方法可以获取停靠区中与指定的停靠控件层叠显示的停靠控件列表List[QDockWidget]。

  • 当拖动停靠控件到其他停靠区时,中心控件和其他控件会进行缩放或移动,腾出停靠空间。

    • setAnimated(bool)方法可以设置腾出停靠空间的过程中,中心控件或其他控件的缩放比较连贯。
    • setDock()ptions(QMainWindow.DockOption)方法可以设置停靠控件的停靠参数,其中QMainWindow.DockOption可以取以下值:
      • QMainWindow.AnimatedDocks(功能与 setAnimated(True)相同)
      • QMainWindow.AllowNestedDocks(功能与setDockNestingEnabled(True)相同)
      • QMainWindow.AllowTabbedDocks(多个停靠控件可以层叠显示,也可以并排显示)
      • QMainWindow.ForceTabbedDocks(多个停靠控件必须层叠显示,AllowNestedDocks 属性失效)
      • QMainWindow.VerticalTabs(Tab标签竖直显示,默认在底部水平显示)。
    • restoreDockWidget(QDockWidget)方法可以使停靠控件复位,成功则返回True。
  • 主窗口上的工具栏和可停靠控件的状态可以保存起来,必要时可以恢复其状态

    • saveStare(version: int=0)方法保存界面状态到 QByteArray 中,
    • restoreState.(QByteArray,version:int=0)方法使界面状态复位,成功则返回True。
  • 用setCorner(Qt.Corner, Qt.DockWidgetArea)方法可以设置停靠区重叠部分属于哪个停靠区域的一部分,其中参数Qt.Corner 可以取:

    • Qt.TopRightCorner
    • Qt.BottomRightCorner
    • Qt.TopLeftCorner
    • Qt.BottomLeftCorner
  • corner(Qt.Corner)方法可以获取角落所属的停靠区域Qt.DockWidgetArea。

主窗口QMainWindow的常用方法如表所示。

QMainWindow的方法及参数类型 返回值的类型 说 明
setCentralWidget(QWidget) None 设置中心控件
centralWidget() QWidget 获取中心控件
takeCentralWidget() QWidget 将中心控件从布局中移除
setMenuBar(menubar:QMenuBar) None 设置菜单栏
menuBar() QMenuBar 新建菜单栏,并返回菜单栏
setMenuWidget(menubar: QWidget) None 设置菜单栏中的控件
menuWidget() QWidget 获取菜单栏中的控件
createPopupMenu() QMenu 创建弹出菜单,并返回菜单
setStatusBar(QStatusBar) None 设置状态栏
statusBar() QStatusBar 获取状态栏,如状态栏不存在,则创建新 状态栏
addToolBar(Qt.ToolBarArea ,QToolBar) None 在指定位置添加工具栏
addToolBar(QToolBar) None 在顶部添加工具栏
addToolBar(title; str) QToolBar 添加工具栏并返回新建的工具栏
insertToolBar(QToolBar,QToolBar) None 在第1个工具条前插入工具条
addToolBarBreak(area: Qt.ToolBarArea=Qt.TopToolBarArea) None 添加工具条放置区域,两个工具栏可以 并排或并列显示
insertToolBarBreak(before:QToolBar) None 在某个工具条前插人放置区域
removeToolBarBreak(before:QToolBar) None 移除工具栏前的放置区域
toolBarArea(QToolBar) Qt.ToolBarArea 获取工具栏的停靠区
toolBarBreak(QToolBar) bool 获取工具栏区是否分割
removeToolBar(QToolBar) None 从布局中移除工具栏
setToolButtonStyle(Qt.ToolButtonStyle) None 设置按钮样式
toolButtonStyle() Qt.ToolButtonStyle 获取按钮样式
aadDockWidget(Qi.DockWidgetAre, QDockWidget) None 在指定停靠区域添加停靠控件
gdDockWidget(Qt.DockWidgetArea, QDockWidget.Qt.Orientation) None 在指定停靠区域添加停靠控件,同时可 设置方向
removeDockWidge(QDockWidget) bool 从布局中移除停靠控件
dockWidgetArea(QDockWidget) Qt.DockWidgetArea 获取停靠控件的停靠位置
[sIot]setDockNestingEnabled(bool) None 设置停靠区是否可容纳多个控件
isDockNestingEnabled() bool 获取停靠区是否只可放一个控件
restoreDockWidget(QDockWidget) bool 停靠控件复位,成功则返回True
saveState(version:int=0) QByteArray 保存界面状态
restoreState(QByteArray,version: int=0) bool 界面状态复位,成功则返回True
[slot]setAnimated(bool) None 设置动画状态,动画状态下腾出停靠区 比较连贯,否则捕捉停靠区
isAnimated() Bool 是否是动画样式
setCorner(Qt.Corner, Qt.DockWidgetArea) None 设置某个角落属于哪个停靠区的一部分
corner(Qt.Corner) Qt.DockWidgetArea 获取角落所属的停靠区域
setDockOptions(QMainWindow.DockOption) None 设置停靠参数
setDocumentMode(bool) None 设置Tab标签是否是文档模式
documentMode() bool 获取 Tab 标签是否是文档模式
setIconSize(QSize) None 设置工具栏上的按钮图标尺寸
iconSize() QSize 获取图标尺寸
setTabPosition(Qt.DockWidgetArea, QTabWidget.TabPosition) None 多个停部控件重叠时,设置Tab标签的 位置,默认在底部
setTabShape(QTabWidget.TabShape) None 多个停靠控件重叠时,设置Tab标签的 形状
splitDockWidget(after: QDockWidget, dockwidget: QDockWidget, orientation: Qt.Orientation) None 将被挡住的停靠控件分成两部分
tabifiedDockWidgets(QDockWidget) List[QDockWidget] 获取停靠区中停靠控件列表
tabifyDockWidget(first:QDockWidget, second: QDockWidget) None 将第二个停靠控件放在第一个停靠控件 的上部,通常创建停靠区

主窗口 QMainWindow 的信号

QMaimWindcw的信号及参数类型 主窗口QMainWindow的信号 说 明
iconSizeChanged(QSize) 当工具栏按钮的尺寸发生变化时发送信号
tabifiedDockWidgetActivated(QDockWidget) 重叠的停靠控件激活时发送信号
toolButtonStyleChanged(Qt.TcolButtonStyle) 工具栏按钮的样式发生变化时发送信号

主窗口QMainWindow 的应用实例

下面的程序在主窗口中建立一个菜单栏、一个中心控件、两个工具栏、两个悬停控件和一个状态栏,工具栏和悬停控件可以拖放到其他位置。悬停控件中一个用于控制字体和字体大小,另一个用于控制字体的颜色。程序运行界面如图所示。

image-20230217023545921

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:28
# File_name: 02-主窗口QMainWindow 的应用实例.py
import sys, os
from PySide6.QtWidgets import(QApplication, QPlainTextEdit, QLabel, QMainWindow, QDockWidget, QSlider, QFontComboBox, QComboBox, QVBoxLayout, QWidget, QFileDialog)
from PySide6.QtGui import QIcon, QColor, QPalette
from PySide6.QtCore import Qt


class MyWindows(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("QMainWindow")
self.setupUi()

def setupUi(self):
self.plainText = QPlainTextEdit(self)
self.setCentralWidget(self.plainText) # 设置中心控件
menuBar = self.menuBar() # 创建菜单栏

file_menu = menuBar.addMenu("文件(&F)") # 创建菜单
act_new = file_menu.addAction(QIcon("../../Resources/animal/m1.png"), "新建(N)")
act_open = file_menu.addAction(QIcon("../../Resources/animal/m2.png"), "打开(O)")
act_save = file_menu.addAction(QIcon("../../Resources/animal/m3.png"), "保存(S)")

file_menu.addSeparator()
act_exit = file_menu.addAction(QIcon("../../Resources/animal/m4.png"), "退出(T)")

edit_menu = menuBar.addMenu("编辑(&E)")
act_copy = edit_menu.addAction(QIcon("../../Resources/animal/m5.png"), "复制(C)")
act_paste = edit_menu.addAction(QIcon("../../Resources/animal/m6.png"), "粘贴(V)")
act_cut = edit_menu.addAction(QIcon("../../Resources/animal/m7.png"), "剪贴(X)")

file_toolbar = self.addToolBar("文件") # 创建工具栏
file_toolbar.addAction(act_new)
file_toolbar.addAction(act_open)
file_toolbar.addAction(act_save)
file_toolbar.addSeparator() # 添加分割线
file_toolbar.addAction(act_exit)

self.addToolBarBreak(Qt.ToolBarArea.TopToolBarArea) # 添加断点
edit_toolbar = self.addToolBar("编辑")
edit_toolbar.addAction(act_copy)
edit_toolbar.addAction(act_paste)
edit_toolbar.addAction(act_cut)

self.statusbar = self.statusBar() # 添加状态栏
label = QLabel("版本号:1.0")
self.statusbar.addPermanentWidget(label)

# 信号和自定义槽链接
act_new.triggered.connect(self.act_new_triggered)
act_open.triggered.connect(self.act_open_triggered)
act_save.triggered.connect(self.act_save_triggered)

act_copy.triggered.connect(self.plainText.cut)
act_paste.triggered.connect(self.plainText.paste)
act_cut.triggered.connect(self.plainText.cut)
act_exit.triggered.connect(self.close)

act_new.hovered.connect(self.act_new_hovered)
act_open.hovered.connect(self.act_open_hovered)
act_save.hovered.connect(self.act_save_hovered)

act_copy.hovered.connect(self.act_copy_hovered)
act_paste.hovered.connect(self.act_paste_hovered)
act_cut.hovered.connect(self.act_cut_hovered)

self.dock_font = QDockWidget("字体", self) # 创建停靠控件
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock_font) # 主窗口中添加停靠控件
self.dock_font.setFeatures(QDockWidget.DockWidgetFeature.NoDockWidgetFeatures) # 设置停靠控件特征
self.dock_font.setFeatures(QDockWidget.DockWidgetFeature.DockWidgetFloatable | QDockWidget.DockWidgetFeature.DockWidgetMovable | QDockWidget.DockWidgetFeature.DockWidgetFloatable) # 设置停靠控件特征

fw = QWidget() # 创建悬停控件上的控件
self.dock_font.setWidget(fw) # 设置悬停控件上的控件
fv = QVBoxLayout(fw) # 在控件上添加布局

self.fontcombobox = QFontComboBox()
self.sizecombox = QComboBox()
self.sizecombox.addItems(str(i) for i in list(range(5, 50)))
self.sizecombox.setCurrentText(str(self.plainText.font().pointSize()))
fv.addWidget(self.fontcombobox) # 布局添加控件
fv.addWidget(self.sizecombox)

self.fontcombobox.currentTextChanged.connect(self.font_name_changed)
self.sizecombox.currentTextChanged.connect(self.font_size_changed)

self.dock_color = QDockWidget("颜色", self) # 创建悬停控件
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock_color)
self.dock_color.setFeatures(QDockWidget.DockWidgetFeature.NoDockWidgetFeatures | QDockWidget.DockWidgetFeature.DockWidgetMovable | QDockWidget.DockWidgetFeature.DockWidgetFloatable) # 设置停靠控件特征
self.tabifyDockWidget(self.dock_font, self.dock_color) # 把两个悬停控件层叠

self.red_slider = QSlider(Qt.Orientation.Horizontal)
self.green_slider = QSlider(Qt.Orientation.Horizontal)
self.blue_slider = QSlider(Qt.Orientation.Horizontal)
self.red_slider.setRange(0, 255)
self.green_slider.setRange(0, 255)
self.blue_slider.setRange(0, 255)

cw = QWidget()
self.dock_color.setWidget(cw)
cv = QVBoxLayout(cw)
cv.addWidget(self.red_slider)
cv.addWidget(self.green_slider)
cv.addWidget(self.blue_slider)
self.red_slider.valueChanged.connect(self.color_slider_changed)
self.green_slider.valueChanged.connect(self.color_slider_changed)
self.blue_slider.valueChanged.connect(self.color_slider_changed)

self.setAnimated(True)
self.setCorner(Qt.Corner.TopLeftCorner, Qt.DockWidgetArea.LeftDockWidgetArea)
self.setDockNestingEnabled(True)

def font_name_changed(self, name):
font = self.plainText.font()
font.setFamily(name)
self.plainText.setFont(font)

def font_size_changed(self, size):
font = self.plainText.font()
font.setPointSize(int(size))
self.plainText.setFont(font)

def color_slider_changed(self, value):
color = QColor(self.red_slider.value(), self.green_slider.value(), self.blue_slider.value())
palette = self.plainText.palette()
palette.setColor(QPalette.ColorRole.Text, color)
self.plainText.setPalette(palette)

def act_new_triggered(self):
self.plainText.clear()

def act_open_triggered(self):
filename, filter = QFileDialog.getOpenFileName(self, "打开", ".", "文本文件(*.txt)")
if os.path.exists(filename):
self.plainText.clear()
fp = open(filename, mode="r", encoding="utf-8")
string = fp.readlines()
for i in string:
i = i.strip()
self.plainText.appendPlainText(i)
fp.close()

def act_save_triggered(self):
filename, filter = QFileDialog.getSaveFileName(self, "打开文件", ".", "文本文件(*.txt)")
string = self.plainText.toPlainText()
if filename != "":
if os.path.exists(filename):
fp = open(filename, mode="r", encoding="utf-8")
fp.writelines(string)
fp.close()
else:
fp = open(filename, "w", encoding="UTE-8")
fp.writelines(string)
fp.close()

def act_new_hovered(self):
self.statusbar.showMessage("新建文档", 5000)

def act_open_hovered(self):
self.statusbar.showMessage("打开文档", 5000)

def act_save_hovered(self):
self.statusbar.showMessage("保存文档", 5000)

def act_copy_hovered(self):
self.statusbar.showMessage("复制文档", 5000)

def act_paste_hovered(self):
self.statusbar.showMessage("复制选中的内容", 5000)

def act_cut_hovered(self):
self.statusbar.showMessage("剪贴选中的内容", 5000)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindows()

win.show()
sys.exit(app.exec())

子窗口QMdiSubWindow

QMdiSubWindow是从QWidget类继承而来的。

1
2
3
from PySide6.QtWidgets import QMdiSubWindow

QMdiSubWindow(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

子窗口QMdiSubWindow 的常用方法

  • 用QMdiSubWindow 的setWidget(QWidget)方法可以往子窗口上添加控件;用widget()方法可以获取子窗口上的控件。

  • 用QMdiSubWindow 的 showShaded()方法可以把子窗口折叠起来,只显示标题栏。

  • 用QMdiSubWindow 的 setOption(QMdiSubWindow.SubWindowOption,bool)方法可以设置子窗口缩放或移动时只显示外轮廓,参数 QMdiSubWindow.SubWindowOption 可以取:

    • QMdiSubWindow.RubberBandResize(缩放时只显示外轮廓)
    • QMdiSubWindow.RubberBandMove(移动时只显示外轮廓)

子窗口QMdiSubWindow 的常用方法:

QMdiSubWindow的方法及参数类型 返回值的类型 说明
setWidget(QWidget) None 设置子窗口中的控件
widget() QWidget 获取子窗口中的控件
[slot]showShaded() None 只显示标题栏
isShaded() bool 获取子窗口是否处于只显示标题栏状态
mdiArea() QMdiArea 返回子窗口所在的多文档区域
setSystemMenu(QMenu) None 设置系统菜单
systemMenu() QMenu 获取系统菜单
[slot]showSystemMenu() None 在标题栏的系统菜单图标下显示系统 菜单
setKeyboardPageStep(step:int) None 设置用键盘Page 键控制子窗口移动或 缩放时的增量步
keyboardPageStep() int 获取用键盘Page键控制子窗口移动或 缩放时的增量步
setKeyboardSingleStep(step:int) None 设置用键盘箭头键控制子窗口移动或缩 放时的增量步
keyboardSingleStep() int 获取用键盘箭头键控制子窗口移动或缩 放时的增量步
setOption(QMdiSubWindow.SubWindowOption, bool) None 设置选项,bool 默认为 True

子窗口 QMdiSubWindow的信号

子窗口 QMdiSubWindow 的信号有 aboutToActivate()windowStateChanged(oldState,newState)

  • 当子窗口活跃时发送aboutToActivate()信号
  • 主窗口状态发生变化时发送 windowStateChanged(oldState: Qt.WindowStates,newState: Qt.WindowStates)信号,其中枚举值 Qt.WindowStates 可取:
    • Qt.WindowNoState(正常状态)
    • Qt.WindowMinimized(最小化状态)
    • Qt.WindowMaximized(最大化状态)
    • Qt.WindowFullScreen(全屏状态)
    • Qt.WindowActive(活跃状态)。

对话框QDialog

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

  • QAbstractPrintDialog
  • QPageSetupDialog
  • QPrintDialog
  • QPrintPreviewDialog
  • QColorDialog
  • QErrorMessage
  • QFileDialog
  • QFontDialog
  • QInputDialog
  • QMessageBox
  • QProgressDialog
  • QWizard

按照运行时是否可以和其他窗口进行交互操作,对话框分为模式(或模态)对话框和非模式对话框。

对于带有模式的对话框,只有在关闭该对话框的情况下才可以对其他窗口进行操作;而对于非模式对话框,在没有关闭对话框的情况下,既可以对该对话框进行操作,也可以对其他窗口进行操作,例如记事本中的查询对话框和替换对话框就是非模式对话框。

为方便编程,PySide6 提供了一些常用的标准对话框,例如文件打开保存对话框QFileDialog、字体 对话框 QFontDialog、颜色 对话框 QColorDialog、信息对话框QMessageBox等,用户可以直接调用这些对话框,而无须再为这些对话框编写代码。

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

自定义对话框QDialog

利用QDialog类,用户可以创建自己的对话框,在对话框上放置控件,实现特定的目的。

QDialog 是从 QWidget 类继承而来的,用QDialog 类创建一般对话框实例的方法如下,其中parent是QDialog 对话框的父窗口,Qt.WindowFlags的取值参考QWidget窗口讲解部分。通常将QDialog对话框作为顶层窗口使用,在主程序界面中进行调用。

1
2
3
from PySide6.QtWidgets import QDialog

QDialog(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, f: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

自定义对话框QDialog的常用方法

自定义对话框QDialog ,主要方法介绍如下。

  • 对话框的模式特性设置。

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

    • Qt.NonModal(非模式,可以和程序的其他窗口进行交互操作)
    • Qt.WindowModal(窗口模式,在未关闭当前对话框时,将阻止该窗口与父窗口的交互操作)
    • Qt.ApplicationModal(应用程序模式,在未关闭当前对话框时,将阻止与任何其他窗口的交互操作)
    • 用windowModality()方法可以获取窗口的模式特性;
    • 用isModel()方法可以获取窗口是否有模式特性;
    • 用setModal(True)方法设置模式特性,默认是窗口模式。
  • 对话框的显示方法。

    • 显示对话框的方法有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(int)方法会隐藏对话框,并把对话框的返回值设置成int。
      • 其实accept()方法调用的就是done(QDialog.Accepted)方法,reject()方法调用的就是done(QDialog.Rejected)方法。
    • 如果对话框是用exec()方法显示的,则exec()方法会返回对话框的值,而show()和open()方法不会返回对话框的值。

自定义对话框QDialog 的常用方法如表所示:

QDialog的方法及参数类型 返回值的类型 说 明
[slot]open() None 以模式方法显示对话框
[slot]exec() int 以模式方法显示对话框,并返回对话框的值
[slot]accept() None 隐藏对话框,并将返回值设置成 QDialog.Accepted,同时发送 accepted()和 finished(int) 信号
[slot]done(int) None 隐藏对话框,并将返回值设置成int,同时发送 finished(int)信号
[slot]reject() None 隐藏对话框,并将返回值设置成QDialog.Rejected,同时发送 accepted()和finished(int)信号
setModal(bool) None 设置对话框为模式对话框
isModal() boo1 获取对话框是否是模式对话框
setResult(result:int) None 设置对话框的返回值
result() int 获取对话框的返回值
setSizeGripEnabled(bool) None 设置对话框的右下角是否有三角形
isSizeGripEnabled() boo1 获取对话框的右下角是否有三角形
setVisible(bool) None 设置对话框是否隐藏

自定义对话框QDialog的信号

自定义对话框QDialog 的信号如表所示。

  • 当执行QDialog的accept()方法时会发送 accepted()信号
  • 执行 reject()方法时会发送 rejected()信号
  • 执行 accept()、reject()或done(int)方法时都会发送 finished(result:int)信号

其中参数 result 是对话框的返回值,用hide()或 setVisible(False)方法隐藏对话框时,不会发送信号。

QDialog的信号及参数类型 说 明
accepted() 执行accept()和 done(int)方法时发送信号
finished(result:int) 执行accept()、reject()和 done(int)方法时发送信号
rejected() 执行 reject()和done(int)方法时发送信号

自定义对话框QDialog的应用实例

下面的程序用于输人学生成绩,其界面如图所示。

在主界面上建立菜单,单击菜单中的”输人成绩”,弹出对话框,用于输人姓名、学号和成绩。单击对话框中的”应用”按钮,将输入的信息在主界面上显示,并不退出对话框,继续输人新的信息;单击”确定”按钮,将输入的信息在主界面上显示,并退出对话框;单击”取消”按钮,放弃输入的内容,并退出对话框。单击主界面上菜单中的”保存”,将显示的内容保存到 txt 文件中,单击”退出”退出整个程序。

image-20230218021008661

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import sys
from PySide6.QtWidgets import QApplication, QWidget, QDialog, QPushButton, QLineEdit, QMenuBar, QTextBrowser, QVBoxLayout, QHBoxLayout, QFormLayout, QFileDialog


class MyWindows(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("学生成绩输人系统")
self.widget_setupUi()
self.dialog_setupUi()

def widget_setupUi(self): # 建立主程序界面
menuBar=QMenuBar(self) # 定义菜单栏
file_menu=menuBar.addMenu("文件(&F)") # 定义菜单
action_input=file_menu.addAction("输人成绩(&I)") # 添加动作
action_save=file_menu.addAction("保存(&S)") # 添加动作
file_menu.addSeparator()
action_exit=file_menu.addAction("退出(SE)") # 添加动作
self.textBrowser=QTextBrowser(self) # 显示数据控件

v=QVBoxLayout(self) # 主程序界面的布局
v.addWidget(menuBar)
v.addWidget(self.textBrowser)

action_input.triggered.connect(self.action_input_triggered) # 信号与槽函数连接
action_save.triggered.connect(self.action_save_triggered) # 信号与槽函数连接
action_exit.triggered.connect(self.close) # 信号与槽雨数连接

def dialog_setupUi(self): # 建立对话框界面
self.dialog=QDialog(self)
self.btn_apply=QPushButton("应用")
self.btn_ok=QPushButton("确定")
self.btn_cancel=QPushButton("取消")
h=QHBoxLayout()
h.addWidget(self.btn_apply)
h.addWidget(self.btn_ok)
h.addWidget(self.btn_cancel)

self.line_name=QLineEdit()
self.line_number=QLineEdit()
self.line_chinese=QLineEdit()
self.line_math=QLineEdit()
self.line_english=QLineEdit()

f=QFormLayout(self.dialog)
f.addRow("姓名:", self.line_name)
f.addRow("学号:", self.line_number)
f.addRow("语文:", self.line_chinese)
f.addRow("数学:", self.line_math)
f.addRow("英语:", self.line_english)
f.addRow(h)

self.btn_apply.clicked.connect(self.btn_apply_clicked) # 信号与槽函数连接
self.btn_ok.clicked.connect(self.btn_ok_clicked) # 信号与槽函数连接
self.btn_cancel.clicked.connect(self.dialog.close) # 信号与槽函数连接

def action_input_triggered(self):
self.dialog.open()

def action_save_triggered(self):
string=self.textBrowser.toPlainText()
if len(string) > 0:
filename, filter=QFileDialog.getSaveFileName(self, "保存文件", ".", "文本文件(*.txt)")
if len(filename) > 0:
fp=open(filename, "+", encoding="UTF-8")
fp.writelines(string)
fp.close()

def btn_apply_clicked(self): # 自定义槽函数,单击"应用"按钮
template="姓名:{} 学号:{} 语文:{} 数学:{} 英语:{}"
string=template.format(self.line_name.text(), self.line_number.text(), self.line_chinese.text(), self.line_math.text(), self.line_english.text())
self.textBrowser.append(string)
self.line_name.clear()
self.line_number.clear()
self.line_chinese.clear()
self.line_math.clear()
self.line_english.clear()

def btn_ok_clicked(self):
self.btn_apply_clicked()
self.dialog.close()


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWindows()

win.show()
sys.exit(app.exec())

字体对话框QFontDialog

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

QFontDialog

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

1
2
3
4
from PySide6.QtWidgets import QFontDialog

QFontDialog(initial: Union[PySide6.QtGui.QFont, str, Sequence[str]], parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QFontDialog(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

字体对话框QFontDialog 的常用方法

字体对话框 QFontDialog 主要方法介如下:

  • 创建字体对话框

    • 一种方法是先创建对话框实例对象,设置对话框的属性,然后用show()open()或 exec()方法显示对话框
    • 另一种法是直接用getFont()方法getFont()方法是静态方法,可直接使用”类名getFont()”方法调用也可用实例对调用
  • setOption(QFontDialog.FoniDinlogOption[,on=True])方法设置宇体对话框的选项,其中QFontDialog.FontDialogOption 可以取:

    • QFontDialog,NoButtons(不显示 OK 和Cancel按纽)
    • QFontDialog.DontUseNativeDialog(在 Mac 机上不使用本机字体对话框,使用PySide6 的字体对话框)
    • QFontDialog.ScalableFonts(显亲可缩放字体)
    • QFontDialog.NonScalableFonts(显示不可缩放字体)
    • QFontDialogMonospacedFonts(显示等宽字体)
    • QFontDialog.ProportionalFonts(显示比宇体)
  • 用selectedFont()方法可以获取在单击 OK 按后,最终选中的字体。在对话中单击 OK 按钮时,同时也发送信号 fontSelected(QFont),其中参数 QFont 是最后中的宇体。

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

  • getFont(initial: QFont, widget=None, title="", QFontDialog.FontDialogOption)方法可以用模式方式显示对话框,获取字体,其中参数:

    • initial是初始化字体
    • title是对话框标题,返回值是元组 Tuple[bool,QFont]。

    如在对话中单击 OK按钮,bool为True,单击 Cancel按钮,bool为 False,返回的字体是初始化字体。如果用getFont(widget=None)方法不能设置初始字体,则单击 Cancel按钮后返回的是默认字体。

字体对话框 QFontDialog 的常用方法如表所示:

QFoniDialog的方法及参数类型 返回值的类型 说 明
selectedFont() QFont 获取在对话框中单击OK 按钮后,最终选 中的字体
setCurrentFont(QFont) None 设置字体对话框中当前的字体,用于初始 化字体对话框
currentFont() QFont 获取字体对话框中当前的字体
setOption(QFontDialog.FontDialogOption:boo=True],[on:bool=True])) None 设置对话框的选项
testOption(QFontDialog.FontDialogOption) bool 测试是否设置了属性
[static]getFont(initial: QFont, widget=None, title=’’, QFontDialog.FontDialogOption) Tuple[bool,QFont] 用模式方式显示对话框,获取字体,参数 initial是初始化字体,title 是对话框标题, 返回值是元组 Tuple[bool,QFont]
[static]getFont(widget: QWidget=None) Tuple[bool,QFont] 用模式方式显示对话框,获取字体,参数 initial是初始化字体,title 是对话框标题, 返回值是元组 Tuple[bool,QFont]

字体对话框 QFontDialog 的信号

字体对话框QFontDialog 的信号有 currentFontChanged(QFont)和 fontSelected(QFont)

  • 在对话框中选择字体时发送 currentFontChanged(QFont)信号,在最终确定之前,可能会选择不同的字体
  • 单击 OK 按钮时,发送 fontSelected(QFont)信号,参数是最选择的字体。

QFontDialog例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/14 23:14
# File_name: 04-QFontDialog 例子.py
"""
QFontDialog 控件是一个常用的字体选择对话框,可以让用户选择所显示文本的字号、样式和格式。
使用QFontDialog 的函数getFont(),可以从字体选择对话框中选择显示文本的字号、样式和格式。

这个案例的代码非常简单,先通过getFont()函数获取字体,然后通过QLabelL.setfont()函数设置字体,如下所示:
还可以通过QWidget.setFont()设置窗口字体
"""

import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class FontDialogDemo(QWidget):
def __init__(self, parent=None):
super(FontDialogDemo, self).__init__(parent)
layout = QVBoxLayout()

self.fontLabel = QLabel("Hello,我来显示字体效果")
layout.addWidget(self.fontLabel)

self.fontButton1 = QPushButton("设置QLabel字体")
self.fontButton1.clicked.connect(self.set_label_font)
layout.addWidget(self.fontButton1)

self.fontButton2 = QPushButton("设置Qwidget字体")
self.fontButton2.clicked.connect(lambda: self.setFont(QFontDialog.getFont(self.font(), self)[1]))
layout.addWidget(self.fontButton2)

self.setLayout(layout)
self.setWindowTitle("Font Dialog 例子")
# self.setFont(QFontDialog.getFont(self.font(),self)[1])

def set_label_font(self):
ok, font = QFontDialog.getFont()
if ok:
self.fontLabel.setFont(font)


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = FontDialogDemo()
demo.show()
sys.exit(app.exec())

颜色对话框QColorDialog

QColorDialog

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

用QColorDialog 类创建标准颜色对话框的方法如下,其中参数 QColor 用于初始化对话框,还可以用Qt.GlobalColor 和 QGradient 初始化颜色

1
2
3
4
from PySide6.QtWidgets import QColorDialog

QColorDialog(initial: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QColorDialog(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

颜色对话框QColorDialog 的常用方法

颜色对话框 QColorDialog 的常用方法如表所示,大部分与字体对话的用法相同。

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

  • 用setOption(QColorDialog.ColorDialogOption[,on=True])方法设置颜色,对话框的选项(默认情况下所有选项都是禁用的),其中 QColorDialog.ColorDialogOption 可以取 :

    • QColorDialog.ShowAlphaChannel(在对话据上显示 Alpha 通道)
    • QColorDialog.NoButtons(不显示0K Cancel 按钮)
    • QColorDialog.DontUseNativeDialog(使用Qt的标准颜色对话框,不使用本机的对话框)。
  • 颜色对话中有标准的颜色,可以用standardColor(index:int)方法获取标准颜色,用setStandardColor(index:int,QColor)方法设置标准颜色

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

QColorDialog的方法及参数类型 返回值的类型 说 明
selectedColor() QColor 获取颜色对话框中单击 OK 按钮后 选中的颜色
setCurrentColor(QColor) None 设置颜色对话框中当前颜色,用于 初始化对话框
currentColor() QColor 获取对话框中当前的颜色
setOption(QColorDialog.ColorDialogOption[,on=True]) .None 设置颜色对话框的选项
testOption(QColorDialog.ColorDialogOption) bool 测试是否设置了选项
[static]setCustomColor(index:int, QColor) None 设置用户颜色
[static]customColor(index: int) QColor 获取用户颜色
[static]customCount() Int 获取用户颜色的数量
[static]setStandardColor(index: int,QColor) None 设置标准颜色
[static]standardColor(index:int) QColor 获取标准颜色
[static]getColor(initial: QColor=Qt.white, parent:QWidget=None, title: str=””,options: QColorDialog.ColorDialogOptions) QColor 显示对话框,获取颜色

颜色对话框 QColorDialog 的信号

颜色对话框 QColorDialog 的信号有 currentColorChanged(QColor)和 colorSelected(QColor)

  • 在对话框中选择颜色时发送 currentColorChanged(QColor)信号,在最终确定之前,可能会选择不同的颜色;
  • 在对话框中单击 OK 按钮时发送colorSelected(QColor)信号参数是最终选择的颜色。

颜色对话框 QColorDialog 的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/14 23:27
# File_name: 05-QColorDialog 例子.py


import sys
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *


class ColorDlg(QDialog):

def __init__(self, parent=None):
super(ColorDlg, self).__init__(parent)
self.setWindowTitle('QColorDialog案例')

layout = QVBoxLayout()
self.setLayout(layout)

self.colorLabel = QLabel('显示颜色效果')
layout.addWidget(self.colorLabel)

colorButton = QPushButton("QColorDialog.get&Color()")
colorButton.clicked.connect(self.setColor)
layout.addWidget(colorButton)

# 颜色选项
self.colorDialogOptionsWidget = DialogOptionsWidget()
self.colorDialogOptionsWidget.addCheckBox("使用Qt对话框(非系统)", QColorDialog.DontUseNativeDialog)
self.colorDialogOptionsWidget.addCheckBox("显示透明度alpha", QColorDialog.ShowAlphaChannel)
self.colorDialogOptionsWidget.addCheckBox("不显示buttons", QColorDialog.NoButtons)
layout.addWidget(self.colorDialogOptionsWidget)

# 自定义颜色设置
layout.addSpacerItem(QSpacerItem(100, 20))
self.label2 = QLabel('设置自定义颜色')
layout.addWidget(self.label2)
self.combobox = QComboBox(self, minimumWidth=100)
item_list =['#ffffff', '#ffff00', '#ff0751', '#52aeff']
index_list =[2, 3, 4, 5]
for i in range(len(item_list)):
self.combobox.addItem(item_list[i], index_list[i])
self.combobox.activated.connect(lambda: self.on_activate(self.combobox))
layout.addWidget(self.combobox)

def setColor(self):
options = self.colorDialogOptionsWidget.value()
if options:
color = QColorDialog.getColor(Qt.green, self, "Select Color", options)
else:
color = QColorDialog.getColor(Qt.green, self, "Select Color")
if color.isValid():
self.colorLabel.setText(color.name())
self.colorLabel.setPalette(QPalette(color))
self.colorLabel.setAutoFillBackground(True)

def on_activate(self, combobox):
color = QColor(combobox.currentText())
index = combobox.currentData()
QColorDialog.setCustomColor(index, color)
self.label2.setText('QColorDialog在位置{} 已经添加自定义颜色{}'.format(index, combobox.currentText()))
self.label2.setPalette(QPalette(color))
self.label2.setAutoFillBackground(True)


class DialogOptionsWidget(QWidget):

def __init__(self, parent=None):
super(DialogOptionsWidget, self).__init__(parent)

self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.checkBoxList =[]

def addCheckBox(self, text, value):
checkBox = QCheckBox(text)
self.layout.addWidget(checkBox)
self.checkBoxList.append((checkBox, value))

def value(self):
result = 0
for checkbox_tuple in self.checkBoxList:
if checkbox_tuple[0].isChecked():
result = checkbox_tuple[1]
return result


if __name__ == '__main__':
app = QApplication(sys.argv)
form = ColorDlg()
form.show()
app.exec()

文件对话框QFileDialog

QFileDialog

文件对话框 QFileDialog 用于打开或保存文件时获取文件路径和文件名。

在文件对话框中可以根据文件类型对文件进行过滤,只显示具有某些扩展名的文件。

文件对话框的界面分为两种,,一种是 PySide6 提供的界面另一种是本机操作系统提供的界面,可以通过文件对话框的 setOption(QFileDialog.DontUseNativeDialog,bool)方法设置显示的是哪种界面。

对话框上的标签和按钮名称都可以通过对话框的属性进行修改。

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

  • caption 用于设置对话框的标题
  • directory设置默认路径
  • filter 设置只显示具有某种扩展名的文件,filter 的取值则见下面的内容
1
2
3
4
from PySide6.QtWidgets import QFileDialog

QFileDialog(parent: PySide6.QtWidgets.QWidget, f: PySide6.QtCore.Qt.WindowType) -> None
QFileDialog(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, caption: str='', directory: str='', filter: str='') -> None

文件对话框QFileDialog 的常用方法

文件对话框QFileDialog 主要方法介绍如下:

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

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

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

    用fileMode()方法可以获取文件模式。

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

    • QFileDialog.ShowDirsOnly(只显示文件夹)
    • QFileDialog.DontResolveSymlinks(不解析链接)
    • QFileDialog.DontConfirmOverwrite(存盘时若选择了存在的文件,不提示覆盖信息)
    • QFileDialog.DontUseNativeDialog(不使用操作系统的对话框)
    • QFileDialogReadOnly(只读)
    • QFileDialog.HideNameFilterDetails(隐藏名称过滤器的详细信息)
    • QFileDialog.DontUseCustomDirectoryIcons(不使用用户的目录图标,有些系统允许使用)。
  • 用setAcceptMode(QFileDialog.AcceptMode)方法设置文件对话框是打开对话框还是保存对话框,参数 QFileDialog.AcceptMode 可取QFileDialog.AcceptOpen 或QFileDialog.AcceptSave。

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

    • QFileDialog.Detail(详细显示)
    • QFileDialog.List(列表显示,只显示图标和名称)。
  • 用setDefaultSuffix(str)方法设置默认的扩展名,例如在保存文件时只需输入文件名,系统自动会附加默认的扩展名。

  • 用selectFile(str)方法可以设置对话框中初始选中的文件,用setDirectory(str)setDirectory(QDir)方法设置对话框的初始路径,关于QDir 的内容见数据读写和文件管理相关章节

  • 设置过滤器 filter。

    • 过滤器的作用是在文件对话框中只显示某些类型的文件,例如通过方法setNameFilter(“Picture(*.png *.bmp *.jpeg *jpg”)设置过滤器之后,对话框只显示扩展名为 png、bmp、jpeg 和jpg 的文件。
    • 创建过滤器时,过滤器间用空格隔开,如果有括号,则用括号中的内容作为过滤器,多个过滤器用两个分号”;;”隔开,例如 setNameFilter(“Picture(* ,png .bmp);; text(.txt)”)。
    • 用setNameFilter(str)方法或 setNameFilters(Sequence[str])方法设置对话框中的过滤器。
    • 用selectedFiles()方法可以获得最终选中的文件名(含路径)的列表
    • 用selectedNameFilter()方法可以获得最终选中的过滤器对话框上的标签和按钮的文字
    • 用setLabelText(QFileDialog.DialogLabel,str)方法重新设置,其中参数 QFileDialog.DialogLabel可以取 :
      • QFileDialog.LookInQFileDialogFileName
      • QFileDialog.FileType
      • QFileDialog.Accept
      • QFileDialog.Reject
  • 用QFileDialog 的静态方法快速显示文件对话框,这些静态方法的格式如下所示:

    • caption 是对话框的标题,
    • dir 是初始路径,
    • ilter 是对话框中可选的过滤器
    • selectedFilter 是对话框中已经选中的过滤器,

    这些静态函数的返回值除getExistingDirectory()和 getExistingDirectoryUrl()外其都是元组,元组的第 1个元素是文件名或文件名列表,第 2个元素是选中的过滤器。

    1
    2
    3
    4
    5
    6
    7
    8
    getExistingDirectory(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, caption: str='', dir: str='', options: PySide6.QtWidgets.QFileDialog.Option=Instance(PySide6.QtWidgets.QFileDialog.Option.ShowDirsOnly)) -> str
    getExistingDirectoryUrl(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, caption: str='', dir: Union[PySide6.QtCore.QUrl, str]=Default(QUrl), options: PySide6.QtWidgets.QFileDialog.Option=Instance(PySide6.QtWidgets.QFileDialog.Option.ShowDirsOnly), supportedSchemes: Sequence[str]=[]) -> PySide6.QtCore.QUrl
    getOpenFileName(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: str='', filter: str='', selectedFilter: str='', options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options)) -> Tuple
    getOpenFileNames(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: str='', filter: str='', selectedFilter: str='', options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options)) -> Tuple
    getOpenFileUrl(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: Union[PySide6.QtCore.QUrl, str]='', filter: str=Default(QUrl), selectedFilter: str='', options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options), supportedSchemes: Sequence[str]=[]) -> Tuple
    getOpenFileUrls(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: Union[PySide6.QtCore.QUrl, str]='', filter: str=Default(QUrl), selectedFilter: str='', options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options), supportedSchemes: Sequence[str]=[]) -> Tuple
    getSaveFileName(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: str='', filter: str='', selectedFilter: str='', options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options)) -> Tuple
    getSaveFileUrl(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: Union[PySide6.QtCore.QUrl, str]='', filter: str=Default(QUrl), selectedFilter: str='', options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options), supportedSchemes: Sequence[str]=[]) -> Tuple

文件对话框QFileDialog 的常用方法如表所示:

QFileDialog的方法及参数类型 返回值的类型 说明
serAcceptMode(QFileDialog.AceptMode) None 设置是打开还是保存对话框
setDefaultSuffix(str) None 设置默认的扩展名
defaultSuffix() Str 获取默认的扩展名
saveState() QByteArray 保存对话框状态到 QByteArray 中
restoreState(QByteArray) bool 恢复对话框的状态
selectFile(str) None 设置初始选中的文件,可当作默认文件
selectedFiles() List[str] 获取被选中的文件的绝对文件路径列表, 如果没有选择文件,则返回值只有路径
selectNameFilter(str) None 设置对话框初始名称过滤器
selectedNameFilter() stI 获取当前选择的名称过滤器
selectUrl(url: Union[QUrl,str]) None 设置对话框中初始选中的文件
selectedUrls() ListLQUrlJ 获取被选中的文件的绝对文件路径列表, 如果没有选择文件,则返回值只有路径
directory() QDir 获取对话框的当前路径
directoryUrl() QUrl 获取对话框的当前路径
setDirectory(directory: Union[QDir, str]) None 设置对话框的初始路径
setFileMode(QFileDialog.FileMode) None 设置文件模式,对话框是用于选择路径、单 个文件还是多个文件
setHistory(paths:Sequence[str]) None 设置对话框的浏览记录
history() List[str] 获取对话框的浏览记录列表
setLabelText(QFileDialog.DialogLabel, str) None 设置对话框上各标签或按钮的名称
labelText(QFileDialog.DialogLabel) str 获取对话框上标签或按钮的名称
setNameFilter(str) None 根据文件的扩展名设置过滤器
setNameFilters(Sequence[str]) None 设置多个过滤器
nameFilters() List[str] 获取过滤器列表
setFilter(filters: QDir.Filters) None 根据文件的隐藏、已被修改、系统文件等特 性设置过滤器
setOption(QFileDialog.Option,on=True) None 设置对话框的外观选项
testOption(QFileDialog.Option) bool 测试是否设置了某种外观样式
setViewMode(QFileDialog.ViewMode) None 设置对话框中文件的视图方式,是列表显 示还是详细显示
getExistingDirectory(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, caption: str=’’, dir: str=’’, options: PySide6.QtWidgets.QFileDialog.Option=Instance(PySide6.QtWidgets.QFileDialog.Option.ShowDirsOnly)) -> str str 打开文件对话框,获取路径或文件及过滤器
getExistingDirectoryUrl(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, caption: str=’’, dir: Union[PySide6.QtCore.QUrl, str]=Default(QUrl), options: PySide6.QtWidgets.QFileDialog.Option=Instance(PySide6.QtWidgets.QFileDialog.Option.ShowDirsOnly), supportedSchemes: Sequence[str]=[]) -> PySide6.QtCore.QUrl QUrl 打开文件对话框,获取路径或文件及过滤器
getOpenFileName(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: str=’’, filter: str=’’, selectedFilter: str=’’, options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options)) -> Tuple Tuple 打开文件对话框,获取路径或文件及过滤器
getOpenFileNames(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: str=’’, filter: str=’’, selectedFilter: str=’’, options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options)) -> Tuple Tuple 打开文件对话框,获取路径或文件及过滤器
getOpenFileUrl(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: Union[PySide6.QtCore.QUrl, str]=’’, filter: str=Default(QUrl), selectedFilter: str=’’, options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options), supportedSchemes: Sequence[str]=[]) -> Tuple Tuple 打开文件对话框,获取路径或文件及过滤器
getOpenFileUrls(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: Union[PySide6.QtCore.QUrl, str]=’’, filter: str=Default(QUrl), selectedFilter: str=’’, options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options), supportedSchemes: Sequence[str]=[]) -> Tuple Tuple 打开文件对话框,获取路径或文件及过滤器
getSaveFileName(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: str=’’, filter: str=’’, selectedFilter: str=’’, options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options)) -> Tuple Tuple 打开文件对话框,获取路径或文件及过滤器
getSaveFileUrl(parent: PySide6.QtWidgets.QWidget, caption: Union[str, NoneType]=None, dir: Union[PySide6.QtCore.QUrl, str]=’’, filter: str=Default(QUrl), selectedFilter: str=’’, options: PySide6.QtWidgets.QFileDialog.Option=Default(QFileDialog.Options), supportedSchemes: Sequence[str]=[]) -> Tuple Tuple 打开文件对话框,获取路径或文件及过滤器

QFileDialog的信号

文件对话框 QFileDialog 的信号如表所示。

  • 用户在文件对话框中选择不同的文件或目录时会发送currentChanged(file:str)信号,其中参数 file是包含文件名的完整路径
  • 在对话框中单击 open 按钮或 save 按钮后会发送fileSelected(file;str)或者 filesSelected(files: List[str])信号
  • 在对话框中更改路径时会发送 directoryEntered(directory:str)信号。
QFileDialog的信号及参数类型 说 明
currentChanged(file: str) 在对话框中所选择的文件或路径发生改变时发送信号,参数是当前 选择的文件或路径
currentUrlChanged(QUrl) 在对话框中所选择的文件或路径发生改变时发送信号,,传递的参数是 QUrl
directoryEntered(directory:str) 进入新路径时发送信号,参数是新路径
directoryUrlEntered(QUrl) 进入新路径时发送信号,传递的参数是QUrl
fileSelected(file: str) 单击open或save按钮后发送信号,参数是选中的文件
urlSelected(QUrI) 单击open或save按钮后发送信号,传递的参数是 QUrl
filesSelected(files:List[str]) 单击open或save按钮后发送信号,参数是选中的文件列表
urlsSelected(List[QUrl]) 单击open或save按钮后发送信号,传递的参数是List[QUr1]
filterSelected(str) 选择新的过滤器后发送信号,参数是新过滤器

QFileDialog 例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/14 23:19
# File_name: 10-QFileDialog 例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import os


class filedialogdemo(QWidget):
def __init__(self, parent=None):
super(filedialogdemo, self).__init__(parent)
layout = QVBoxLayout()
self.label = QLabel("此处显示文件信息")
layout.addWidget(self.label)
self.label2 = QLabel()
layout.addWidget(self.label2)

self.button_pic_filter1 = QPushButton("加载图片-过滤1(静态方法)")
self.button_pic_filter1.clicked.connect(self.file_pic_filter1)
layout.addWidget(self.button_pic_filter1)

self.button_pic_filter2 = QPushButton("加载图片-过滤2(实例化方法)")
self.button_pic_filter2.clicked.connect(self.file_pic_filter2)
layout.addWidget(self.button_pic_filter2)

self.button_pic_filter3 = QPushButton("加载图片-过滤3(实例化方法)")
self.button_pic_filter3.clicked.connect(self.file_pic_filter3)
layout.addWidget(self.button_pic_filter3)

self.button_MultiFile1 = QPushButton("选择多个文件-过滤1(静态方法)")
self.button_MultiFile1.clicked.connect(self.file_MultiFile1)
layout.addWidget(self.button_MultiFile1)

self.button_MultiFile2 = QPushButton("选择多个文件-过滤2(实例化方法)")
self.button_MultiFile2.clicked.connect(self.file_MultiFile2)
layout.addWidget(self.button_MultiFile2)

self.button_file_mode = QPushButton("file_mode示例:选择文件夹")
self.button_file_mode.clicked.connect(self.file_mode_show)
layout.addWidget(self.button_file_mode)

self.button_directory = QPushButton("选择文件夹(静态方法)")
self.button_directory.clicked.connect(self.directory_show)
layout.addWidget(self.button_directory)

self.button_save = QPushButton("存储文件")
self.button_save.clicked.connect(self.file_save)
layout.addWidget(self.button_save)

self.setLayout(layout)
self.setWindowTitle("File Dialog 例子")

def file_pic_filter1(self):
fname, _ = QFileDialog.getOpenFileName(self, caption='Open file1', dir=os.path.abspath('.') + '\\images',
filter="Image files(*.jpg *.png);;Image files2(*.ico *.gif);;All files(*)")
self.label.setPixmap(QPixmap(fname))
self.label2.setText('你选择了:\n' + fname)

def file_pic_filter2(self):
file_dialog = QFileDialog(self, caption='Open file2', directory=os.path.abspath('.') + '\\images',
filter="Image files(*.jpg *.png);;Image files2(*.ico *.gif);;All files(*)")

if file_dialog.exec():
file_path_list = file_dialog.selectedFiles()
self.label.setPixmap(QPixmap(file_path_list[0]))
self.label2.setText('你选择了:\n' + file_path_list[0])

def file_pic_filter3(self):
file_dialog = QFileDialog()
file_dialog.setWindowTitle('Open file3')
file_dialog.setDirectory(os.path.abspath('.') + '\\images')
file_dialog.setNameFilter("Image files(*.jpg *.png);;Image files2(*.ico *.gif);;All files(*)")

if file_dialog.exec():
file_path_list = file_dialog.selectedFiles()
self.label.setPixmap(QPixmap(file_path_list[0]))
self.label2.setText('你选择了:\n' + file_path_list[0])

def file_MultiFile1(self):
file_path_list, _ = QFileDialog.getOpenFileNames(self, caption='选择多个文件', dir=os.path.abspath('.'),
filter="All files(*);;Python files(*.py);;Image files(*.jpg *.png);;Image files2(*.ico *.gif)")
self.label.setText('你选择了如下路径:\n' + ';\n'.join(file_path_list))
self.label2.setText('')

def file_MultiFile2(self):
file_dialog = QFileDialog(self, caption='选择多个文件', directory=os.path.abspath('.'),
filter="All files(*);;Python files(*.py);;Image files(*.jpg *.png);;Image files2(*.ico *.gif)")
file_dialog.setFileMode(file_dialog.ExistingFiles)
if file_dialog.exec():
file_path_list = file_dialog.selectedFiles()
self.label.setText('你选择了如下路径:\n' + ';\n'.join(file_path_list))
self.label2.setText('')

def file_mode_show(self):
file_dialog = QFileDialog(self, caption='file_mode示例:选择文件夹', directory=os.path.abspath('.'))
file_dialog.setFileMode(file_dialog.Directory)
if file_dialog.exec():
file_path_list = file_dialog.selectedFiles()
self.label.setText('你选择了如下路径:\n' + ';\n'.join(file_path_list))
self.label2.setText('')

def directory_show(self):
directory_path = QFileDialog.getExistingDirectory(caption='获取存储路径', dir=os.path.abspath('.'))
self.label.setText('获取目录:\n' + directory_path)
self.label2.setText('')

def file_save(self):
file_save_path, _ = QFileDialog.getSaveFileName(self, caption='获取存储路径', dir=os.path.abspath('.'),
filter="All files(*);;Python files(*.py);;Image files(*.jpg *.png);;Image files2(*.ico *.gif)")
self.label.setText('存储路径如下:\n' + file_save_path)
self.label2.setText('')


if __name__ == '__main__':
app = QApplication(sys.argv)
ex = filedialogdemo()
ex.show()
sys.exit(app.exec())

输入对话框QInputDialog

QInputDialog

输人对话框 QImputDialog 用于输人简单内容或选择内容,分为整数输入框浮点数输人框、文本输人框、多行文本输入框和下拉列表输入框5种,它们的界面如图所示输人对话框由一个标签、一个输入控件和两个按钮构成。

  • 如果是整数输人框,输人控件息QSpinBox;
  • 如果是浮点数输人框,输入控件是 QDoubleSpinltox;
  • 如果是单行文本输人框输入控件是 QlineEdit;
  • 如果是多行文本输人框,输人控件是 QPinTextEdit,
  • 如果是下物列表输入框,输入控件是 QComboBox 或 QListViw。

输人的类型用setInputMode(QInputDialog.InputMode)方法设置。

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

1
2
3
from PySide6.QtWidgets import QInputDialog

QInputDialog(self, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

输入对话框QInputDialog 的常用方法

输人对话框 QInputDialog 主要方法介绍如下:

  • 输人对话框分为整数输入对话框、浮点数输人对话框和文本输人对话框,其中文本输人对话框又分为单行文本输人对话框、多行文本输人对话框和列表输人对话框列表输入对话框通常是从 QComboBox 控件或 QListWiew 控件中选择内容。

    • 用setInputMode(QInputDialog.InputMode)方法设置输人对话框的类型,其中参数QInputDialog.InputMode 可以取:
      • QInputDialog.IntInput(整数输人对话框)
      • QInputDialog.Double(浮点数输入对话框)
      • InputQInputDialog,TextInput(文本输入对话框)。
  • 对于整数输入对话框

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

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

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

    • 用setTextValue(str)方法可以设置对话框中初始文本
    • 用textValue()方法获取单击 OK 按后输人对话的值。
    • 当输人控件是 QLineEdit时
      • 用setTextEchoMode(QLineEdit, EchoMode)方法可以设置QLineEidt 控件的输人模式其中QLineEdit.EchoMode 可以取:
        • QLineEdit,Norma(正常显示)
        • QLineEdit.NoEcho(输人文字时,没有任何显示)
        • QLineEdit,Password(输人文学时,按照密码方式显示)
        • QLineEdit,PasswordEchoOnEdit(失去焦点时,密码显示状态,编辑文本时,正常显示)。
      • 用setLabelText(str)方法设置输人对话框中标签显示的名称
      • 用setOkButtonTex(str)方法和 setCancelButtonText(str)方法分别设置 OK 按和 Cancel 按钮的名称
      • 用setOption(QInputDialog.NoButtons)方法设置成没有按钮。
  • 除了用以上方法显示和设置对话框的类型和外观外,还可以直接使用下面的静态数来显示对话框和获得返回值,其中

    • title 是设置对话框的标题名称
    • label是对话中标签的名称。

    在对话框中单击 OK 按钮后,返回值是元组(输人值,True);单击Cancel按钮后,返回值是元组(0,False)或(“”, False)

    1
    2
    3
    4
    5
    getDouble(parent: PySide6.QtWidgets.QWidget, title: str, label: str, value: float=0, minValue: float=-2147483647, maxValue: float=2147483647, decimals: int=1, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags), step: float=1) -> Tuple[float, bool]
    getInt(parent: PySide6.QtWidgets.QWidget, title: str, label: str, value: int=0, minValue: int=-2147483647, maxValue: int=2147483647, step: int=1, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> Tuple[int, bool]
    getItem(parent: PySide6.QtWidgets.QWidget, title: str, label: str, items: Sequence[str], current: int=0, editable: bool=True, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags), inputMethodHints: PySide6.QtCore.Qt.InputMethodHint=Instance(Qt.ImhNone)) -> Tuple[str, bool]
    getMultiLineText(parent: PySide6.QtWidgets.QWidget, title: str, label: str, text: str='', flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags), inputMethodHints: PySide6.QtCore.Qt.InputMethodHint=Instance(Qt.ImhNone)) -> Tuple[str, bool]
    getText(parent: PySide6.QtWidgets.QWidget, title: str, label: str, echo: PySide6.QtWidgets.QLineEdit.EchoMode=Instance(PySide6.QtWidgets.QLineEdit.Normal), text: str='', flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags), inputMethodHints: PySide6.QtCore.Qt.InputMethodHint=Instance(Qt.ImhNone)) -> Tuple[str, bool]

输人对话框 QInputDialog 的常用方法如表所示:

QInputDialog的方法及参数类型 返回值的类型 说 明
setInputMode(QInputDialog.InputMode) None 设置输入对话框的类型
setOption(QInputDialog.InputDialogOption,on=True) None 设置输人对话框的参数
testOption(QInputDialog.InputDialogOption) bool 测试是否设置某些参数
setLabelText(str) None 设置对话框中标签的名称
setOkButtonText(str) None 设置对话框中OK按钮的名称
setCancelButtonText(str) None 设置Cancel按钮的名称
setIntValue(int) None 设置对话框中初始整数
intValue() int 获取对话框中的整数
setIntMaximum(int) None 设置整数的最大值
setIntMinimum(int) None 设置整数的最小值
setlntRange(min: int,max:int) None 设置整数的范围
setIntStep(int) None 设置单击向上或向下箭头时整数调整的 步长
setDoubleValue(float) None 设置对话框中初始浮点数
doubleValue() float 获取对话框中的浮点数
setDoubleDecimals(int) None 设置浮点数的小数位数
setDoubleMaximum(float) None 设置浮点数的最大值
setDoubleMinimum(float) None 设置浮点数的最小值
setDoubleRange(min: float,max: float) None 设置浮点数的范围
setDoubleStep(float) None 设置单击向上或向下箭头时浮点数调整 的步长
setTextValue(str) None 设置对话框中初始文本
setComboBoxItems(Sequence[str]) None 设置下拉列表的值
textValue() Str 获取对话框中的文本
setTextEchoMode(QLineEdit.EchoMode) None 设置QLineEdit控件的输人模式
comboBoxItems() List[str] 获取下拉列表中的值
setComboBoxEditable(bool) None 设置下拉列表是否可编辑,用户是否可 输入数据
[static]getInt(parameters) Tuple[int.bool] 静态函数,显示输入对话框,并返回输入 的值和单击按钮的类型
[static]getDouble(parameters) Tuple[float,bool] 静态函数,显示输入对话框,并返回输入 的值和单击按钮的类型
[static]getText(parameters) Tuple[str,bool] 静态函数,显示输入对话框,并返回输入 的值和单击按钮的类型
[static]getMultiLineText(parameters) Tuple[str,bool] 静态函数,显示输入对话框,并返回输入 的值和单击按钮的类型
[static]getItem(parameters) Tuple[str,bool] 静态函数,显示输入对话框,并返回输入 的值和单击按钮的类型

输入对话框QInputDialog 的信号

输入对话框 QInputDialog 的信号如表所示。

对于3类型的输人对话框

  • 单击 OK按钮时分别发送intValueSelected(int)、doubleValueSelected(float)和 textValueSelected(str)信号
  • 编辑状态会分别发送intValueChanged(int)、doubleValueChanged(float)和 textValueChanged(str)信号
QInputDialog的信号及参数类型 说 明
intValueChanged(int) 输人对话框中的整数值改变时发送信号
intValueSelected(int) 单击OK按钮后发送信号
doubleValueChanged(float) 输人对话框中的浮点数值改变时发送信号
doubleValueSelected(float) 单击OK按钮后发送信号
textValueChanged(str) 输人对话框中的文本改变时发送信号
textValueSelected(str) 单击OK按钮后发送信号

信息对话框QMessageBox

image-20230212211905913 image-20230212211920486 image-20230212211927403 image-20230212211950945 image-20230212211957507

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

image-20230218194355584

用QMessageBox类创建信息对话框的方法如下,设置对话框中的按钮icon和 button的取值见下面的内容

  • icon 是对话框中的图标title是对话框的标题
  • text是对话框中显示的文本buttons
  • flags 设置窗口的类型使用默认值即可。
1
2
3
4
from PySide6.QtWidgets import QMessageBox

QMessageBox(icon: PySide6.QtWidgets.QMessageBox.Icon, title: str, text: str, buttons: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.NoButton), parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Instance(Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)) -> None
QMessageBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

信息对话框 QMessageBox 的常用方法

信息对话框 QMessageBox 的常用方法如表所示

QMessageBox的方法及参数类型 返回值的类型 说 明
setText(str) None 设置信息对话框的文本
text() str 获取信息对话框的文本
setInformativeText(str) None 设置对话框的信息文本
informativeText() str 获取信息文本
setDetailedText sr) None 设置对话框的详细文本
detailedText() str 获取详细文本
setTextFormat(QL.TextFormat) None 设置文本的格式, 是纯文本还是富文本
seIcon(QMessageBox.Icon) None 设置标准图标
setIconPixmap(QPixmap) None 设置自定义图标
icon(QMessageBox.Icon) QMessageBox.Icon 获取标准图标的图像
iconPixmap() QPixmap 获取图标的图像
setCheckBox(QCheckBox) None 信息对话框中添加QCheckBox控件
checkBox() QCheckBox 获取QCheckBox控件
addButton(button:QAbstractButton, role: QMessageBox.ButtonRole) None 对话框中添加按钮, 并设置按钮的作用
addButton(text: str, QMessageBox ButtonRole) QPushButton 对话框中添加新建的按钮, 并返回新建的 按钮
addButton(QMessageBox.StandardButton) QPushButton 添加标准按钮, 标准按钮有固定的角色(作 用)
buttons() List[QAbstractButtonJ 获取对话框中按钮列表
button(QMessageBox StandardButton) QAbstractButton 获取对话框中标准按钮
buttonText(button:int) Str 获取按钮上的文本
removeButton(QAbstractButton) None 移除按钮
buttonRole(button: QAbstractButton) QMessageBox ButtonRole 获取按钮的角色
setDefaultButton(QPushButton) None 设置默认按钮
setDefaultButton(QMessageBox.StandardButton) None 将某标准按钮设置成默认按钮
defaultButton() QPushButton 获取默认按钮
setEscapeButton(QAbstractButton) None 设置按 Esc键对应的按钮
setEscapeButton(QMessageBox.StandardButton) None 将某标准按钮设置成 Esc键对应的按钮
escapeButton() QAbstractButton 获取Esc键对应的按钮
clickedButton() QAbstractButton 获取被单击的按钮
[static]about(QWidget, title: str, text: str) None 构建”关于”对话框
parameters参数可选如下:
parent:指定父窗口
title:对话框标题
text:对话框文本
Lstatic]information(parameters) QMessageBox.StandardButton 或 int 静态函数, 快速构建消息对话框, 并返回被 单击的按钮
parameters参数可选如下:
parent:指定父窗口
title:对话框标题
text:对话框文本
buttons:多个标准按钮,默认为ok按钮
defaultButton:默认选中的标准按钮,默认是第一个标准按钮
[static]question(parameters) QMessageBox.StandardButton 或 int 静态函数, 快速构建消息对话框, 并返回被 单击的按钮
parameters参数可选如下:
parent:指定父窗口
title:对话框标题
text:对话框文本
buttons:多个标准按钮,默认为ok按钮
defaultButton:默认选中的标准按钮,默认是第一个标准按钮
[static]warning(parameters) QMessageBox.StandardButton 或 int 静态函数, 快速构建消息对话框, 并返回被 单击的按钮
parameters参数可选如下:
parent:指定父窗口
title:对话框标题
text:对话框文本
buttons:多个标准按钮,默认为ok按钮
defaultButton:默认选中的标准按钮,默认是第一个标准按钮
[static]critical(parameters) QMessageBox.StandardButton 或 int 静态函数, 快速构建消息对话框, 并返回被 单击的按钮
parameters参数可选如下:
parent:指定父窗口
title:对话框标题
text:对话框文本
buttons:多个标准按钮,默认为ok按钮
defaultButton:默认选中的标准按钮,默认是第一个标准按钮

信息对话框 QMessageBox主要方法介绍如下

  • 信息对话框的创建方法有两种

    • 一种是先创建信息对话框的实例对象,然后往实例对象中添加文本、图标和按钮,最后用show() open()或 xec()方法把信息对话框显示出来
    • 另一种是用QMessageBox 提供的静态函数来创建信息对话框
  • 信息对话框上显示的文本分为 text、informativeText 和 detailedText

    • 如果设置detailedText,会出现”Show Details…”按钮
      • 3个文本分别用setText(str)、setInformativeText(str)和 setDetailedText(str)方法设置。
    • detailedText 文本只能以纯文本形式显示,text 和 informativeText 文本可以用纯文本或富文本的形式易示
    • 用setTextFormat(Qt.TextFormat)方法设置是用纯文本还是富文本显示其中参数 Qt.TextFormat 可以取:
      • Qt.PlainText(纯文本)
      • Qt.RichText(富文本)
      • QtAutoText(由系统决定)
      • Qt.MarkdownText(Markdown 文本)。
  • 信息对话框的图标可以由用户自己定义,也可以使用QMessageBox 提供的标准图标。

    • 自定义图标需要用setIconPixmap(QPixmap)方法定义,标准图标用setIcon(QMessageBox.Icon)方法设置,其中 QMessageBox.Icon 可以取以下值,这几种图标的样式如上面开头介绍图所示
      • QMessageBox.Nolcon 该消息框没有任何按钮
      • QMessageBox.Question 询问问号图标
      • QMessageBox.Information 信息图标
      • QMessageBox.Warning 警告图标
      • QMessageBox,Critical 标识非常严重问题图标
  • 信息对话框的按钮分为自定义按钮和标准按钮,不论哪种按钮都要赋予角色,按钮的角色用来说明按钮的作用。按钮的角色由枚举类型QMessageBox.ButtonRole确定,QMessageBoxButtonRole 可以取的值如下表所示:

    QMessageBox.ButtonRole的取值 说 明
    QMessageBox.InvalidRole -1 不起作用的按钮
    QMessageBox.AcceptRole 0 接受对话框内的信息,例如OK按钮
    QMessageBox.RejectRole 1 拒绝对话框内的信息,例如Cancel按钮
    QMessageBox.DestructiveRole 2 重构对话框
    QMessageBox.ActionRole 3 使对话框内的控件产生变化
    QMessageBox.HelpRole 4 显示帮助的按钮
    QMessageBox.YesRole 5 Yes 按钮
    QMessageBox.NoRole 6 No按钮
    QMessageBox.ResetRole 7 重置按钮,恢复对话框的默认值
    QMessageBox ApplyRole 8 确认当前的设置,例如Apply 按钮
  • 在信息对话框中添加的按钮可以是自定义的按钮,也可以是标准按钮。

    • 用addButton(button:QAbstractButton,role: QMessageBox.ButtonRole)方法方法自定义按钮,将一个已经存在的按钮加人到对话框中,

    • 或者用addButton(text:str, QMessageBox.ButtonRole)方法自定义按钮,创建名称是 text 的按钮,同时返回该按钮;

    • 用addButton(QMessageBox.StandardButton)方法可以添加标准按钮,并返回按钮添加按钮后可以为按钮设置槽函数。标准按钮已经有角色,参数 QMessageBox.StandardButton 用于设置标准按钮,标准按钮与其对应的角色如表所示,用removeButton(QAbstractButton)方法可以移除按钮。信息对话框中也可添加QCheckBox 控件,方法是 setCheckBox(QCheckBox)

      标准按钮 标准按钮的角色 描述
      QMessageBox.Ok AcceptRole 确定按钮
      QMessageBox.Open AcceptRole 打开按钮
      QMessageBox.Save AcceptRole 保存按钮
      QMessageBox.Cancel RejectRole 取消按钮
      QMessageBox.Close RejectRole 关闭按钮
      QMessageBox.Discard DestructiveRole 根据平台定义的放弃或者不保存按钮
      QMessageBox.Apply ApplyRole 应用按钮
      QMessageBox.Reset ResetRole 重置按钮
      QMessageBox.RestoreDefaults ResetRole 恢复默认值按钮
      QMessageBox.Help HelpRole 帮助按钮
      QMessageBox.SaveAIl AcceptRole 全部保存按钮
      QMessageBox.Yes YesRole 是按钮
      QMessageBox.YesToAll YesRole 全部同意按钮
      QMessageBox.No NoRole 否按钮
      QMessageBox.NoToAll NoRole 全部拒绝按钮
      QMessageBox.Abort RejectRole 终止按钮
      QMessageBox.Retry AcceptRole 重试按钮
      QMessageBox.Ignore AcceptRole 忽略按钮
      QMessageBox.NoButton 无效的按钮
  • 默认按钮是按 Enter 键时执行动作的按

    • 默认按用stDefaultButton(QPushButton)方法或 setDefaultButton(QMessageBox StandardButton)方法设置
    • 若未指定,则根据按钮的角色来确定默认按钮。
      • Esc 按钮是按 Esc 键时执行动作的按钮,Esc按钮用setEscapeButton(QAbstractButton)方法或 setEscapeButton(QMessageBoxStandardButton)方法设置。
      • 如果没有设置 Esc 按钮,则将角色是CancelRole的按钮作为 Esc 按钮,如果只有一个按钮则将这个按作为 Esc按钮。
  • 对话框上被单击的按钮可以用clickedButton()方法获得也可通过信号buttonClicked(QAbstractButton)获得,单击按钮后发送该信号,并传递被单击的按钮。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    about(parent: PySide6.QtWidgets.QWidget, title: str, text: str) -> None
    critical(parent: PySide6.QtWidgets.QWidget, title: str, text: str, button0: PySide6.QtWidgets.QMessageBox.StandardButton, button1: PySide6.QtWidgets.QMessageBox.StandardButton) -> int
    critical(parent: PySide6.QtWidgets.QWidget, title: str, text: str, buttons: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.Ok), defaultButton: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.NoButton)) -> PySide6.QtWidgets.QMessageBox.StandardButton
    information(parent: PySide6.QtWidgets.QWidget, title: str, text: str, button0: PySide6.QtWidgets.QMessageBox.StandardButton, button1: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.NoButton)) -> PySide6.QtWidgets.QMessageBox.StandardButton
    information(parent: PySide6.QtWidgets.QWidget, title: str, text: str, buttons: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.Ok), defaultButton: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.NoButton)) -> PySide6.QtWidgets.QMessageBox.StandardButton
    question(parent: PySide6.QtWidgets.QWidget, title: str, text: str, button0: PySide6.QtWidgets.QMessageBox.StandardButton, button1: PySide6.QtWidgets.QMessageBox.StandardButton) -> int
    question(parent: PySide6.QtWidgets.QWidget, title: str, text: str, buttons: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)), defaultButton: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.NoButton)) -> PySide6.QtWidgets.QMessageBox.StandardButton
    warning(parent: PySide6.QtWidgets.QWidget, title: str, text: str, button0: PySide6.QtWidgets.QMessageBox.StandardButton, button1: PySide6.QtWidgets.QMessageBox.StandardButton) -> int
    warning(parent: PySide6.QtWidgets.QWidget, title: str, text: str, buttons: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.Ok), defaultButton: PySide6.QtWidgets.QMessageBox.StandardButton=Instance(QMessageBox.StandardButton.NoButton)) -> PySide6.QtWidgets.QMessageBox.StandardButton
    parameters参数可选如下:
    parent:指定父窗口
    title:对话框标题
    text:对话框文本
    buttons:多个标准按钮,默认为ok按钮
    defaultButton:默认选中的标准按钮,默认是第一个标准按钮
  • 自定义对话框,如果标准的消息框无法满足需求,则可以自定义消息框。

    • 使用setText0函数可以设置消息框文本。

    • 使用setlnformativeText()函数可以设置更多信息,主要用来补充text()函数的内容,向用户提供更多信息。

    • 使用setStandardButtonsO函数可以添加标准的按钮控件,标准按钮信息请参考上面的表格。

    • 使用 setDetailedTextO函数可以设置详细信息区域要显示的纯文本信息,默认是空字符串

    • 使用setIconO函数可以添加消息框的标准图标,默认无图,支持的参数见上面

      • 使用setlconPixmap()函数可以设置一个自定义的图标,适用于标准图标不能满足需求的情况。
    • 使用 addButton0函数可以添加自定义按钮,适用于标准按钮不能满足需求的情况。

信息对话框QMessageBox 的信号

信息对话框 QMessageBox 只有一个按钮,在对话框中单击任意按钮时发送buttonClicked(button:QAbstractButton)信号,参数是被单击的按钮。

错误消息对话框QErrorMessage

QErrorMessage

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

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

1
2
3
from PySide6.QtWidgets import QErrorMessage

QErrorMessage(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

错误信息对话框只有两个重载型槽函数 showMessage(message: str)和 showMessage(message: str,type: str),执行该方法后立即显示对话框

  • message参数是错误信息
  • type参数指定错误信息的类型。

如果用户在对话框中不勾选”Show this messageagain”,则遇到相同的错误信息或相同类型的错误信息时,将不再弹出对话框。

进度对话框QProgressDialog

QProgressDialog

进度对话框 QProgressDialog 用于表明某项任务正在进行及任务的完成进度。

进度对话框的界面如图所示,由 1个标签 QLabel1个进度条 QProgressBar 和 1个按钮QPushButton 构成。

进度对话框可以与定时器一起工作每隔一段时间获取一项任务的完成值,再设置进度条的当前值。当然,如果任务能自动输出其完成值,可直接与进度条的槽函数setValue(int)连接。

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

  • 第1个 str 是进度对话窗口的标题栏
  • 第 2个 str 是签的文本
  • 第 1个 int 是进度条的最小值
  • 第2个int 是进度条的最大值。
1
2
3
4
from PySide6.QtWidgets import QProgressDialog

QProgressDialog(labelText: str, cancelButtonText: str, minimum: int, maximum: int, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None
QProgressDialog(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

进度对话框QProgressDialog 的常用方法

进度对话框 QProgressDialog 的常用方法如表所示:

QProgressDialog的方法及参数类型 返回值的类型 说 明
setMinimumDuration(int) None 设置对话框从创建到显示出来的过渡时间
minimumDuration() int 获取从创建到显示时的时间
[slot]setValue(int) None 设置进度条的当前值
value int 获取进度条的当前值
[slot]setMaximum(int) None 设置进度条的最大值
maximum() int 获取进度条的最大值
[slot]setMinimum(int) None 设置进度条的最小值
minimum() int 获取进度条的最小值
[slot]setRange(int,int) None 设置进度条的最小值和最大值
[slot]setLabelText(str) None 设置对话框中标签的文本
labelText() Str 获取进度条中标签的文本
[slot]setCancelButtonText(str) None 设置”取消”按钮的文本
[slot]cancel() Str 取消对话框
wasCanceled() bool 获取对话框是否被取消了
[slot]forceShow() None 强制显示对话框
[slot]reset() None 重置对话框
setAutoClose(bool) None 调用reset()方法时,设置是否自动隐藏
autoClose() 6001 获取是否自动隐藏
setAutoReset(bool) None 进度条的值达到最大时,设置是否自动重置
autoReset() bool 获取进度条的值达到最大时,是否自动重置
setBar(QProgressBar) None 重新设置对话框中的进度条
setCancelButton(QPushButton) None 重新设置对话框中的”取消”按钮
setLabel(QLabel) None 重新设置对话框中的标签按钮

进度对话框 QProgressDialog主要方法介绍如下:

  • 进度对话框显示
    • 进度对话框显示可以不用show()等方法来显示在创建进度对话后,经过某段时间后对话框会自动显示出来,这段时间是通过 setMinimumDuration(int)来设置的。参数 int 的单位是毫秒,默认是 4000 毫秒如果设置为0,则立即显示对话。
    • 可以forceShow()方法强制显示对话框。设置这个显示时间的目的是防止任务进展大快,进度对话框一闪而过。
  • 进度条需要设置最小值和最大值及当前值
    • 最小值和最大值分别用setMinimum(int)方法和 setMaximum(int)方法设置默认是0和100;
    • 进度条的最小值和最大值也可以用setRange(int,int)方法来设置。
    • 进度条的当前值用setValue(int)方法设置。
    • 进度条上显示的百分比用公式(valueminumum)/(maximum-minimum)来计算,
  • 对话框如果设置了 setAutoClose(True),调用reset()方法重置进度条时,会自动隐藏对话框。
  • 对话框如果设置了 setAutoReset(True)则进度条的值达到最大值时会调用reset()方法重置进度条;如果设置了 setAutoClose(True),会隐藏对话框
  • 用setLabelText(str)方法和 setCancelButtonText(str)方法可以设置对话框中标签和按钮显示的文字
  • 当单击对话框中的 Cancel 按钮或执行 cancel()方法时会取消对话框,并且会重置和隐藏对话框,同时 wasCanceled()的值为 True。

进度对话框QProgressDialog 的信号

进度对话框 QProgressDialog 只有一个信号 canceled(),单击对话中的 Cancel 按时发送信号。

进度对话框QProgressDialog 的应用实例

下面的程序将进度对话框和定时器相结合,定时器每隔 200 毫秒发送一个信息。进度条的值随时间的推移逐渐增大,当超过进度条的最大值或单击 Cancel 按钮后,进度条被隐藏和重置。

image-20230218203332772

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import sys
from PySide6.QtWidgets import QApplication, QWidget, QProgressDialog
from PySide6.QtCore import QTimer


class MyWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.pd=QProgressDialog("Copying...", "Cancel", 0, 100, self)
self.pd.canceled.connect(self.cancel)
self.t=QTimer(self)
self.t.setInterval(200)
self.t.timeout.connect(self.perform)
self.t.start()
self.steps=0

def perform(self):
self.pd.setValue(self.steps)
self.steps=self.steps + 1

if self.steps > self.pd.maximum():
self.t.stop()

def cancel(self):
self.t.stop()
self.close()


if __name__=='__main__':
app=QApplication(sys.argv)

window=MyWindow()

window.show()

sys.exit(app.exec())

QProgressDialog(Bar) 例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/14 23:29
# File_name: 03-QProgressDialog(Bar) 例子.py


from PySide6.QtCore import Qt.QTimer
from PySide6.QtWidgets import *

import sys
import time


class Main(QMainWindow):

def __init__(self):
super().__init__()
self.setWindowTitle("QProgressDialog Demo")
widget = QWidget()
self.setCentralWidget(widget)
layout = QVBoxLayout()
widget.setLayout(layout)
self.label = QLabel('显示进度条取消信息')
layout.addWidget(self.label)

button_modeless = QPushButton('显示无模式进度条,不会阻断其他窗口', self)
button_modeless.clicked.connect(self.show_modeless)
layout.addWidget(button_modeless)

button_model = QPushButton('模式进度条,会阻断其他窗口', self)
button_model.clicked.connect(self.show_modal)
layout.addWidget(button_model)

button_auto = QPushButton('不会自动关闭和重置的进度条', self)
button_auto.clicked.connect(self.show_auto)
layout.addWidget(button_auto)

# 自定义进度条,
button_custom = QPushButton('自定义QProgressDialog', self)
button_custom.clicked.connect(self.show_custom)
layout.addWidget(button_custom)

# 水平滑块
self.pd_slider = QProgressDialog("滑块进度条:点击滑块我会动", "Cancel", 10, 100, self)
self.pd_slider.move(300, 400)
self.pd_slider.canceled.connect(lambda: self.cancel(self.pd_slider))
self.slider_horizon = QSlider(Qt.Horizontal)
self.slider_horizon.setRange(10, 120)
layout.addWidget(self.slider_horizon)
self.slider_horizon.valueChanged.connect(lambda: self.valuechange(self.slider_horizon))
bar = QProgressBar(self) # QProgressBar
bar.valueChanged.connect(lambda value: print('自定义Bar的Value值:', value))
bar.setRange(1, 80)
self.slider_horizon.valueChanged.connect(lambda value: bar.setValue(value))
layout.addWidget(bar)
# self.slider_horizon.valueChanged.connect(self.pd_slider.setValue)

self.resize(300, 200)

def show_modeless(self):
pd_modeless = QProgressDialog("无模式进度条:可以操作父窗口", "Cancel", 0, 12)
pd_modeless.move(300, 600)

self.steps = 0

def perform():
pd_modeless.setValue(self.steps)
self.label.setText(
'当前进度条值: {}\n最大值: {}\n是否取消(重置)过进度条: {}'.format(pd_modeless.value(), pd_modeless.maximum(), pd_modeless.wasCanceled()))

# // perform one percent of the operation
self.steps += 1
if self.steps > pd_modeless.maximum():
self.timer.stop()

self.timer = QTimer(self)
self.timer.timeout.connect(perform)
self.timer.start(1000)

pd_modeless.canceled.connect(lambda: self.cancel(pd_modeless))
pd_modeless.canceled.connect(self.timer.stop)

def show_modal(self):
max = 10
pd_modal = QProgressDialog("模式进度条:不可以操作父窗口", "终止", 0, max, self)
pd_modal.move(300, 600)
pd_modal.setWindowModality(Qt.WindowModal)
# pd_modal.setWindowModality(Qt.ApplicationModal)
pd_modal.setMinimumDuration(1000) # 一秒后出现对话框

# 信号和槽要放在计时器后面,否则不会被执行
pd_modal.canceled.connect(lambda: self.cancel(pd_modal))

for i in range(max + 1):
pd_modal.setValue(i)
self.label.setText('当前进度条值: {}\n最大值: {}\n是否取消(重置)过进度条: {}'.format(pd_modal.value(), pd_modal.maximum(), pd_modal.wasCanceled()))
if pd_modal.value() >= pd_modal.maximum() or pd_modal.wasCanceled():
break
# print('you can do something here')
time.sleep(1)
# pd_modal.setValue(max)

def get_pd_auto(self):
if not hasattr(self, 'pd_auto'):
max = 5
self.pd_auto = QProgressDialog("我不会自动关闭和重置,哈哈", "终止", 0, max, self)
self.pd_auto.move(300, 600)
self.pd_auto.setWindowModality(Qt.ApplicationModal)
self.pd_auto.setMinimumDuration(1000)
# self.pd_auto.setValue(0)

self.pd_auto.setAutoClose(False) # 取消满值自动关闭(默认情况下满值自动重置)
self.pd_auto.setAutoReset(False) # 取消自动重置 (默认情况下满值自动重置)

self.pd_auto.canceled.connect(lambda: self.cancel(self.pd_auto))
return self.pd_auto

def show_auto(self):
pd_auto = self.get_pd_auto()

for i in range(1000):
if pd_auto.value() >= pd_auto.maximum() or pd_auto.wasCanceled():
self.label.setText('当前进度条值: {}\n最大值: {}\n是否取消(重置)过进度条: {}'.format(pd_auto.value(), pd_auto.maximum(), pd_auto.wasCanceled()))
break
pd_auto.setValue(pd_auto.value() + 1)
self.label.setText('当前进度条值: {}\n最大值: {}\n是否取消(重置)过进度条: {}'.format(pd_auto.value(), pd_auto.maximum(), pd_auto.wasCanceled()))
# print('you can do something here')
time.sleep(1)
# pd_auto.setValue(max)

def show_custom(self):

pd_custom = QProgressDialog(self)
bar = QProgressBar()
bar.setMaximum(9)
bar.setMinimum(2)
bar.valueChanged.connect(lambda value: print('自定义Bar的Value值:', value))
pd_custom.setBar(bar)
pd_custom.setLabel(QLabel('自定义进度条,使用自定义的QProgressBar'))
pd_custom.setCancelButton(QPushButton('取消按钮'))

pd_custom.move(300, 600)
pd_custom.setWindowModality(Qt.WindowModal)
# pd_custom.setWindowModality(Qt.ApplicationModal)
pd_custom.setMinimumDuration(1000) # 一秒后出现对话框

# 信号和槽要放在计时器后面,否则不会被执行
pd_custom.canceled.connect(lambda: self.cancel(pd_custom))

for i in range(-1, bar.maximum() + 1):
pd_custom.setValue(i)
self.label.setText('当前进度条值: {}\n最大值: {}\n是否取消(重置)过进度条: {}'.format(pd_custom.value(), pd_custom.maximum(), pd_custom.wasCanceled()))
if pd_custom.value() >= pd_custom.maximum() or pd_custom.wasCanceled():
break
# print('you can do something here')
time.sleep(1)
# pd_modal.setValue(max)

def cancel(self, pg):
self.statusBar().showMessage('你手动取消了进度条: “%s”' % pg.labelText(), 3000)

def valuechange(self, slider):
size = slider.value()
self.pd_slider.setValue(size)
self.label.setText(
'当前进度条值: {}\n最大值: {}\n是否取消(重置)过进度条: {}'.format(self.pd_slider.value(), self.pd_slider.maximum(), self.pd_slider.wasCanceled()))


if __name__ == "__main__":
app = QApplication(sys.argv)
window = Main()
window.show()
sys.exit(app.exec())

向导对话框QWizard

image-20230218203746444

向导对话框 QWizard 由多页构成,可以引导客户按步骤完成某项工作

向导对话框在 ModernStyle 风格界面中,对话框的顶部是横幅(banner),横幅中有标题、子标题和logo,左侧是水印区(watermark),底部有一排按钮,右侧是向导页的内容

在MacStyle风格界面中,顶部没有 logo.左侧用背景(background)代替。

../../_images/qtwizard-nonmacpage.png qtwizard-macpage.png

与其他对话框不同的是,向导对话框由多页构成,同一时间只能显示其中的一页,单击next按或 Back 按钮可以向后或向前显示其他页。对话框中的页是向导页WizzrdPage.向导页有自己的布局和控件,向导会为向导页分配从0开始的ID号

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

1
2
3
4
from PySide6.QtWidgets import QWizard, QWizardPage

QWizard(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None
QWizardPage(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

向导对话框QWizard 和向导页 QWizardPage 的常用方法

向导对话框QWizard的常用方法如表所示:
QWizard的方法及参数类型 返回值的类型 说明
addPage(page: QWizardPage) int 添加向导页,并返回D号
setPage(id:int, page: QWizardPage) None 用指定的ID号添加向导页
removePage(id: int) None 移除ID是int的向导页
currentId() int 获取当前向导页的ID号
currentPage() QWizardPage 获取当前向导页
basVisitedPage(int) bool 获取向导页是否被访问过
[slot]restart() None 回到初始页
[slot]back() None 显示上一页
[slot]next() None 显示下一页
page(id:int) QWizardPage 获取指定ID号的向导页
pageIds() ListCint] 获取向导页的ID列表
setButton(which: QWizard.WizardButton, button:QAbstractButton) None 添加某种用途的按钮
button(QWizard.WizardButton) QAbstractButton 获取某种用途的按钮
setButtonLayout(Sequence[QWizard.WizardButton]) None 设置按钮的布局(相对位置)
setButtonText(QWizard.WizardButton, str) None 设置按钮的文本
buttonText(which: QWizard.WizardButton) str 获取按钮的文本
setField(name:str,value:Any) None 设置字段的值
field(name: str) Any 获取字段的值
setOption(QWizard.WizardOption, on=True) None 设置向导对话框的选项
options() WizardOptions 获取向导对话框的选项
testOption(QWizard.WizardOption) bool 测试是否设置了某个选项
setPixmap(which: QWizard.WizardPixmap, pixmap:Union[QPixmap,Qlmage,str]) None 在对话框的指定区域设置图片
pixmap(which: QWizard.WizardPixmap) QPixmap 获取指定位置处的图片
setSideWidget(QWidget) None 在向导对话框左侧设置控件
setStartId(id:int) None 用指定ID号的向导页作为起始页,默认用ID值最小的页作为起始页
startId() int 获取起始页的ID号
setSubTitleFormat(format: Qt.TextFormat) None 设置子标题的格式
setTitleFormat(format: Qt.TextFormat) None 设置标题的格式
setWizardStyle(style:QWizard.WizardStyle) None 设置向导对话框的风格
wizardStyle() WizardStyle 获取向导对话框的风格
visitedIds() ListCint] 获取访问过的向导页ID列表
cleanupPage(id:int) None 清除内容,恢复默认值
initializePage(id:int) None 初始化向导页
nextId() int 获取下一页的ID号
validateCurrentPage() bool 验证当前页的输入是否正确
向导页QWizardPage的常用方法如表所示:
QWizardPage的方法及参数类型 返回值的类型 说 明
setButtonText(QWizard.WizardButton,str) None 设置某种用途按钮的文字
buttonText(which: QWizard.WizardButton) str 获取指定用途的按钮的文本
setCommitPage(commitPage:bool) None 设置成提交页
isCommitPage() bool 获取是否是提交页
setFinalPage(bool) None 设置成最后页
isFinalPage() bool 获取是否是最后页
setPixmap(which: QWizard.WizardPixmap,pixmap:QPixmap) None 在指定区域设置图片
pixmap(which: QWizard.WizardPixmap) QPixmap 获取指定区域的图片
setSubTitle(subTitle:str) None 设置子标题
setTitle(title:str) None 设置标题
subTitle() str 获取子标题
title() Str 获取标题
registerField(name: str, widget: QWidget, property: str=None, changedSignal: str=None) None 创建字段
setField(name: str,value: Any) None 设置字段的值
field(name:str) Any 获取字段的值
setDefaultProperty(classNane: str, property: str,changedSignal:str) None 设置某类控件的某个属性与某个信号相 关联
validatePage() bool 验证向导页中的输入内容
wizard() QWizard 获取向导页所在的向导对话框
cleanupPage() None 清除页面的内容,恢复默认值
initializePage() None 用于初始化向导页
isComplete() bool 获取是否完成输人,以便激活Next 按钮或 Finish 按钮
validatePage() bool 验证向导页中的内容,若为True则显示下 一页
nextId() int 获取下一页的ID号
向导对话框QWizar和向导页QWizardPage主要方法介绍
  • 向导对话框的风格

    • 用setWizardStyle(style;QWizard.WizardStyle)方法设置,其中参数 style是QWizard,WizardStyle 的枚举值,可以取:
      • QWizard.ClassicStyle
      • QWizard.ModernStyle
      • QWizard.MacStyle
      • QWizard.AeroStyle。
  • 添加向导页

    • 用向导对话框的 addPage(page:QWizardPage)方法可以添加向导页,并返回向导页的ID号
    • 也可用setPage(id;int,page:QWizardPage)方法用指定的ID号添加向导页。
  • 向导对话框的标题和子标题

    • 向导页的 setTitle(title; str)方法和 setSubTitle(subTitle: str)方法设置标题和子标题
    • 虽然由向导页设置标题和子标题,但是它们会显示在向导对话框的横幅中。
    • 标题和子标题的格式由向导对话框的setTitleFormat(format:Qt.TextFormat)法和 setSubTitleFormat(format:Qt.TextFormat)方法设置,其中参数 format 的取值是 QtTextFormat 举值可以取:
      • Qt.PlainText(纯文本)
      • Qt.RichText(富文本)
      • Qt.AutoText(由系统决定)
      • Qt.MarkdownText(Markdown 文本)
  • 向导对话框的选项由 setOption(QWizard,WizardOption,on=True)方法设置中QWizard.WizardOption 参数是枚举类型,其可以取的值如表所示:

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

    • 向导对话框和向导页都可以用setPixmap(which:QWizard.WizardPixmappixmap:QPixmap)方法设置向导对话框中显示的图片
    • 用向导对话框设置的图片作用于所有页,用向导页设置的图片只作用于向导页所在的页面,其中参 which的取值是QWizard,WizardPixmap 的校举值,用于设置图片放置的位置,可以取:
      • QWizard.WatermarkPixmap
      • QWizard.LogoPixmap
      • QWizard.BannerPixmap
      • QWizard.BackgroundPixmap。
  • 往对话框中添加按钮

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

      Qwizard.wizard Button 的取值 说 明 Qwizard.wizard Button 的取值 说 明
      QWizard.BackButton Back 按钮 QWizard.HelpButton Help 按钮
      QWizard.NextButton Next 按钮 QWizard.CustomButtonl 用户自定义第1个按钮
      QWizard.CommitButton Commit 按钮 QWizard.CustomButton2 用户自定义第2个按钮
      QWizard.FinishButton Finish按钮 QWizard.CustomButton3 用户自定义第3个按钮
      QWizard.CancelButton Cancel按钮 QWizard.Stretch 布局中的水平伸缩器
    • 对话框中最多可以添加3个自定义的按钮,要使自定义按钮可见,还需要用setOption()方法把自定义按钮显示出米。通常情况下 Next 按钮和 Finish 按钮是互斥的

  • 提交页

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

    • 用向导页的 setFinalPage(bool)方法可以把向导页设置成最后页,最后页上用Finish 按钮替换 Next 按钮,此时用nextld()方法取下一页的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 valueChanged(int)
      QComboBox currentIndex currentIndexChanged(int)
      QDateTimeEdit dateTime dateTimeChanged(QDatetime)
      QLLineEdit text textChanged(str)
      QListWidget currentRow currentRowChanged(int)
      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号,从而控制页面显示的顺序

向导对话框QWizard 和向导页QWizardPage的信号

向导页 QWizardPage 只有一个信号completeChanged()当 isCompleted()的返回值发生变化时发送该信号。

向导对话框 QWizard 的信号如表所示:

QWizard的信号 说 明
currentIdChanged(ID) 当前页发生变化时发送信号,参数是新页的ID
customButtonCIicked(which) 单击自定义按钮时发送信号,参数 which 可能是 CustomButtonl、 CustomButton2 或 CustomButton3
helpRequested() 单击 Help 按钮时发送信号
pageAdded(ID) 添加向导页时发送信号,参数是新页的ID
pageRemoved(ID) 移除向导页时发送信号,参数是被移除页的ID

向导对话框QWizard 和向导页QWizardPage 的应用实例

下面的程序建立由3个向导页构成的导航对话框,通过单击菜单显示出对话框,用于人学生基本信息、联系方式和考试成绩。

其中第 1个向导页输人姓名和学号,在这个向导页中重写了 isComplete()函数和 validatePage()函数,当姓名和学号中都输人了内容时isComplete()的返回值是True。

这时”下一步”按钮会激活单击”下一步”按钮时,会验学号中输人的内容是否为数字如果是则 validatePage()的返回值是True,显示下一个导航页;

如果不是会弹出警告信息对话框,validatePage()的返回值是 False,不会显示下一个导页。其他向导页也可作类似的处理。在最后一页中单击”完成”按钮,通过字段获取输人的值,并输出到界面上。

image-20230218221901369

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import sys
from PySide6.QtWidgets import(QApplication, QWidget, QMenuBar, QPlainTextEdit, QVBoxLayout, QWizard, QWizardPage, QMessageBox, QPushButton, QLineEdit, QFormLayout)


class QWizardPage_1(QWizardPage): # 第1个向导页类
def __init__(self, parent=None):
super().__init__(parent)
form=QFormLayout(self)
self.line_name=QLineEdit()
self.line_number=QLineEdit()
form.addRow("姓名:", self.line_name)
form.addRow("学号:", self.line_number)

self.setTitle("学生成绩输入系统")
self.setSubTitle("基本信息")

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) # 创建字段创建字段#重写isComplete()函数
self.registerField("number", self.line_number)

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

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

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


class QWizardPage_2(QWizardPage): # 第2个向导页类
def __init__(self, parent=None):
super().__init__(parent)

form=QFormLayout(self)
self.line_telephone=QLineEdit()
self.line_address=QLineEdit()
form.addRow("电话:", self.line_telephone)
form.addRow("地址:", self.line_address)

self.setTitle("学生成绩输人系统")
self.setSubTitle("联系方式")
self.registerField("telephone", self.line_telephone)
self.registerField("address", self.line_address)


class QWizardPage_3(QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
form=QFormLayout(self)
self.line_chinese=QLineEdit()
self.line_math=QLineEdit()
self.line_english=QLineEdit()

form.addRow("语文:", self.line_chinese)
form.addRow("数学:", self.line_math)
form.addRow("英语:", self.line_english)

self.setTitle("学生成绩输入系统")
self.setSubTitle("考试成绩")

self.registerField("chinese", self.line_chinese) # 创建字段
self.registerField("math", self.line_math) # 创建字段
self.registerField("english", self.line_english) # 创建字段


class QWizard_studentnumber(QWizard): # 向导对话框

def __init__(self, parent=None):
super().__init__(parent)

self.setWizardStyle(QWizard.WizardStyle.ModernStyle)
self.addPage(QWizardPage_1(self)) # 添加向导页
self.addPage(QWizardPage_2(self)) # 添加向导页
self.addPage(QWizardPage_3(self)) # 添加向导页

self.btn_back=QPushButton("上一步")
self.btn_next=QPushButton("下一步")
self.btn_finish=QPushButton("完成")

self.setButton(QWizard.WizardButton.BackButton, self.btn_back) # 添加按钮
self.setButton(QWizard.WizardButton.FinishButton, self.btn_finish)
self.setButton(QWizard.WizardButton.NextButton, self.btn_next) # 添加按钮

self.setButtonLayout([self.WizardButton.Stretch, self.WizardButton.BackButton, self.WizardButton.NextButton, self.WizardButton.FinishButton])


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.widget_setupUi() # 建立主界面
self.wizard=QWizard_studentnumber(self) # 实例化向导对话框
self.wizard.btn_finish.clicked.connect(self.btn_finish_clicked) # 完成按钮信号与槽的连接

def widget_setupUi(self): # 建立主程序界面
menuBar=QMenuBar(self) # 定义菜单栏
file_menu=menuBar.addMenu("文件(&F)") # 定义文件菜单
action_enter=file_menu.addAction("进入")
action_enter.triggered.connect(self.action_enter_triggered) # 动作的信号与槽函数的连接
self.plainText=QPlainTextEdit(self) # 显示数据控件

v=QVBoxLayout(self) # 主界面的布局
v.addWidget(menuBar)
v.addWidget(self.plainText)

def action_enter_triggered(self):
self.wizard.setStartId(0)
self.wizard.restart()
self.wizard.open()

def btn_finish_clicked(self): # 单击最后一页的"完成"按钮,输人的数据在plainText中显示
template="姓名:{} 学号:{} 电话:{} 地址:{} 语文:{} 数学:{} 英语:{}"
string=template.format(self.wizard.field("name"), self.wizard.field("number"), self.wizard.field("telephone"), self.wizard.field("address"), self.wizard.field("chinese"), self.wizard.field("math"), self.wizard.field("english")) # 获取字段值, 格式化输出文本
self.plainText.appendPlainText(string)


if __name__=='__main__':
app=QApplication(sys.argv)
window=MyWindow()
window.show()
sys.exit(app.exec()) # 动作的槽函数

打印

应用程序一般都有打印功能,可以将重要内容打印成纸质资料。PySide支持打印操作,它可以识别系统中已经安装的打印机,驱动打印机进行工作,可以用与打印机有关的类直接打印,也可通过打印对话框进行打印,还可对打印的内容在打印前进行打印预览。与打印有关的类主要在QtPrintSupport模块中。

PySide提供识别打印机硬件的类QPrinterInfo和进行打印的类QPrinter,将QPrinter 作为QPainter的绘图设备,可以将图形、文字和图像等用打印机进行输出,保存到纸质介质上。

打印机信息 QPrinterInfo

打印机信息QPrinterInfo代表本机上可以使用的一台打印机,通过QPrinterInfo可以获取打印机的参数。用QPrinterInfo创建打印机信息实例对象的方法如下所示。

1
2
3
4
5
6
from PySide6.QtPrintSupport import QPrinterInfo

QPrinterInfo(self) -> None
QPrinterInfo(other: PySide6.QtPrintSupport.QPrinterInfo) -> None
QPrinterInfo(printer: PySide6.QtPrintSupport.QPrinter) -> None
QPrinterInfo()

打印机信息QPrinterInfo的常用方法如表所示

QPrinterInfo的方法及参数类型 返回值的类型 说 明
[static]availablePrinterNames() List[str] 获取可用的打印机名称列表
[static]availablePrinters() List[QPrinterInfo] 获取可用的打印机列表
[static]defaultPrinter() QPrinterInfo 获取当前默认的打印机
[static]defaultPrinterName() str 获取当前默认打印机的名称
[static]printerInfo(printerName: str) QPrinterInfo 根据打印机名称获取打印机
isDefault() bool 获取是否是默认的打印机
isNull() bool 获取是否不含打印机信息
isRemote() bool 获取是否是远程网络打印机
defaultColorMode() QPrinter.ColorMode 获取打印机默认的颜色模式
defaultDuplexMode() QPrinter.DuplexMode 获取默认的双面打印模式
description() Str 获取对打印机的描述信息
location() Str 获取打印机的位置信息
makeAndModel() str 获取打印机的制造商和型号
defaultPageSize() QPageSize 获取默认的打印纸尺寸
maximumPhysicalPageSize() QPageSize 获取支持的最大打印纸尺寸
minimumPhysicalPageSize() QPageSize 获取支持的最小打印纸尺寸
printerName() str 获取打印机的名称
state() QPrinter.PrinterState 获取打印机的状态
supportedColorModes() List[QPrinter.ColorMode] 获取打印机支持的颜色模式
supportedDuplexModes() List[QPrinter.DuplexMode] 获取打印机支持的双面模式
supportedPageSizes() List[QPageSize] 获取打印机支持的打印尺寸
supportedResolutions() List[int] 获取打印机支持的打印质量
supportsCustomPageSizes() bool 获取打印机是否支持自定义打 印纸尺寸

打印机信息QPrinterInfo的常用方法主要方法介绍如下。

  • 用QPrinterInfo提供的静态方法 availablePrinterNames()和 availablePrinters()可分别获取本机上的打印机名称列表和打印机列表;

  • 用静态方法defaultPrinter()和defaultPrinterName()可分别获取默认的打印机和默认打印机的名称。

  • 用isNull()方法获取QPrinterInfo()对象是否不含打印机信息,例如本机上如果没有安装打印机,则用defaultPrinter()方法获得的打印机是无效的。

  • 用defaultColorMode()方法获取打印机默认的颜色模式,返回值是 QPrinter.ColorMode 的枚举值,可取:

    • QPrinter.GrayScale(值为 0)
    • QPrinter.Color(值为 1)。

    用defaultDuplexMode()方法获取打印机默认的双面打印模式,返回值是 QPrinter.DuplexMode 的枚举值,可取:

    • QPrinter.DuplexNone(单 面 模 式)
    • QPrinter.DuplexAuto(用打印机的默认设置来决定是单面模式还是双面模式)
    • QPrinter.DuplexLongSide(双面模式,打印第2面前沿纸张长边翻面)
    • QPrinter.DuplexShortSide(双面模式,打印第2面前沿纸张短边翻面),对应值分别是0~3。
  • 用state()方法获取打印机当前的状态,返回值是 QPrinter.PrinterState,可取以下值,对应值分别是0~3。

    • QPrinter.Idle
    • QPrinter.Active
    • QPrinter.Aborted(已取消)
    • QPrinter.Error

打印机QPrinter及实例

QPrinter 表示打印出来的纸张,可以作为QPainter的绘图设备来使用,QPainter 可以按照QPrinter绘制图形、文字和图像等内容。

QPrinter 继承自QPagedPaintDevice 和 QPaintDevice。用QPrinter 创建打印机实例的方法如下所示,其中参数 mode 设置打印模式,取值是 QPrinter.PrinterMode的枚举值,可取以下值,取不同的值会影响QPainter的视口。

  • QPrinter.ScreenResolution(使用屏幕分辨率)
  • QPrinter.HighResolution
1
2
3
4
5
from PySide6.QtPrintSupport import QPrinter

QPrinter(mode: PySide6.QtPrintSupport.QPrinter.PrinterMode=Instance(PySide6.QtPrintSupport.QPrinter.PrinterMode.ScreenResolution)) -> None
QPrinter(printer: PySide6.QtPrintSupport.QPrinterInfo,
mode: PySide6.QtPrintSupport.QPrinter.PrinterMode=Instance(PySide6.QtPrintSupport.QPrinter.PrinterMode.ScreenResolution)) -> None
打印机QPrinter的常用方法

打印机QPrinter 的常用方法如表:

QPrinter的方法及参数类型 返回值的类型 说 明
setPrinterName(str) None 设置打印机名称
printerName() str 获取打印机名称
setOutputFileName(str) None 设置打印到文件的文件名
outputFileName() str 获取打印文件名
setOutputFomat(QPrinter.OutputFormat) None 设置打印到文件时的格式
setFullPage(bool) None 设置是否整页模式打印
setPageMargins(margins: Union[QMarginsF, QMargins], units: QPageLayout.Unit=QPageLayout.Millimeter) bool 设置打印页边距
setCopyCount(int) None 设置打印份数
copyCount() int 获取打印份数
setCollateCopies(collate:bool) None 设置是否对照打印
collateCopies() bool 获取对照打印
setPromTo(fromPage: int,toPage:int) None 设置打印页数的范围
fromPage() int 获取打印范围起始页
toPage() int 获取打印范围终止页
setPageOrder(QPrinter.PageOrder) None 设置打印顺序
pageOrder() QPrinter.PageOrder 获取打印顺序
setResolution(int) None 设置打印精度
resolution() int 获取打印精度
setPageOrientation(QPageLayout.Orientation) bool 设置打印方向
newPage() bool 生成新页
abort() bool 取消正在打印的文档
fllPage() bool 获取是否整页模式
isValid() bool 获取打印机是否有效
PaPerRect(QPrinter.Unit) QRectF 获取纸张范围
setPrintRange(tange: QPrinter.PrintRange) None 设置打印范围的模式
printRange() QPrinter.PrintRange 获取打印范围的模式
printerState() QPrinter.PrinterState 获取打印状态
serColorMode(QPrinter.ColorMode) None 设置颜色模式
colorMode() QPrinter.ColorMode 获取颜色模式
setDocName(str) None 设置打印来源文档名
docName() str 获取文档名
setDuplex(duplex: QPrinter.DuplexMode) None 设置双面模式
duplex() QPrinter.DuplexMode 获取双面模式
setFontEmbeddingEnabled(enable: bool) None 设置是否启用内置字体
fontEmbeddingEnabled() b001 获取是否启用内置字体
setPageSize(Union[QPageSize, QPageSize.PageSizeId,QSize]) bool 设置打印纸的尺寸
pageRect(QPrinter.Unit) QRectF 获取打印范围
setPaperSource(QPrinter.PaperSource) None 设置纸张来源
paperSource() QPrinter.PaperSource 获取纸张来源
supportedPaperSources() List[QPrinter.PaperSource] 获取支持的纸张来源列表
setPdfVersion(QPagedPaintDevice.PdfVersion) None 设置 pdf文档的版本
setPageRanges(ranges:QPageRanges) None 设置选中的页数
pageRanges() QPageRanges 获取选中的页数对象
setPageLayout(pageLayout: QPageLayout) bool 设置页面布局
pageLayout() QPageLayout 获取页面布局对象
supportedResolutions() List[int] 获取打印机支持的分辨率列表
supportsMultipleCopies() bool 获取是否支持多份打印

打印机QPrinter主要方法介绍如下。

  • 用QPrinterInfo的静态方法availablePrinterNames()可以获得本机已经安装的打印机名称列表,然后用QPrinter 的setPrinterName(str)方法将其中一台打印机设置成QPrinter。

  • 用setOutputFileName(str)方法设置打印机将打印内容打印到文件中而不是纸质介质上

    • 参数是文件名。如果不设置该内容或设置为空字符串,则将内容打印到纸张上;
    • 如果设置了扩展名是pdf的文件名,则将打印内容输出到pdf文档中;
    • 如果设置的扩展名不是pdf,则将打印内容输出到按照 setOutputFormat(QPrinter.OutputFormat)方法设置的文件格式的文件中,其中QPrinter.OutputFormat枚举值可取:
      • QPrinter.NativeFormat(本机定义格式,值是0)
      • QPrinter.PdfFormat(pdf格式,值是1)。
  • 在打印完第一页后,需要用newPage()方法通知打印机弹出当前正在打印的纸张,继续进行下一页的打印,成功则返回True;用abort()方法取消当前的打印,成功则返回True。

  • 用setFullPage(bool)方法设置是否是整页模式打印。

    • 在setFullPage(True)时,QPainter的坐标原点在可打印区的左上角,与纸张坐标系的原点重合,如图11-1(a)所示,但由于页边距的限制,实际上不能在整张纸上打印;

    • 在 setFullPage(False)时,QPainter的坐标原点在打印区域的左上角。

    • 页边距用setPageMargins(margins: Union[QMarginsF,QMargins],units: QPageLayout.Unit=QPageLayout,Millimeter)方法设置,其中单位 Unit 可取:

      • QPageLayout.Millimeter,QPageLayout.Point(=in/72)、
      • QPageLayout.Inch、QPageLayout.Pica(=in/6)
      • QPageLayout.Didot(=0.375mm)
      • QPageLayout.Cicero(=4.5mm)

      对应值分别是0~6。

    • 用paperRect(QPrinter,Unit)方法和 pageRect(QPrinter.Unit)方法可以分别获取纸张和打印区的矩形区域QRectF,

      • QPrinter.Unit可取以下值,对应值分别是0~6。
        • QPrinter.Millimeter
        • QPrinter.Point
        • QPrinter.Inch
        • QPrinter.Pica
        • QPrinter.Didot
        • QPrinter,Cicero
        • QPrinter.DevicePixel
  • 用setCopyCount(int)方法设置打印份数;

    • 用setCollateCopies(collate:bool)方法设置是否对照打印,在setCollateCopies(False)时,每张都会连续打印指定的份数。
  • 用setResolution(int)方法设置打印精度(分辨率),单位是dpi(dots per inch)。

  • 用setPageOrientation(QPageLayout.Orientation)方法设置打印方向,参数是·QPageLayout.Orientation 的枚举值,可取 QPageLayout.Portrait(纵向,值是0)、QPageLayout.Landscape(横向,值是1)

    • 用setPageOrder(QPrinter.PageOrder)方法设置打印顺序,参数是QPrinter.PageOrder的枚举值,可取:

      • QPrinter.FirstPageFirst(正常顺序,值是0)
      • QPrinter.LastPageFirst(反向顺序,值是1)。
  • 用setPrintRange(range:QPrinter.PrintRange)方法设置打印范围的模式,参数range 可取:

    • QPrinter.AllPages(打印所有页,值是0)
    • QPrinter.Selection(打印选中的页,值是1)
    • QPrinter.PageRange(打印指定范围的页,值是2)
    • QPrinter.CurrentPage(打印当前页,值是3);
  • 用setFromTo(fromPage: int,toPage:int)方法或setPageRanges(ranges: QPageRanges)方法设置打印范围

    • 参数ranges是QPageRanges的对象,可以用QPageRanges的addPage(pageNumber:int)方法或addRange(from_: int,to: int)方法添加要打印的页;
    • 用clear()方法清除已经添加的页数;
    • 用静态方法fromString(ranges:str)将字符串转换成QPageRanges对象,QPageRanges类在QtGui 模块中。
  • 用setPageSize(Union[QPageSize,QPageSize.PageSizeId,QSize])方法可以设置纸张的尺寸,其中枚举值QPageSize.PageSizeld定义了一些常用的纸张尺寸,常用的纸张尺寸如表所示:

    • 也可用QPageSize(pageSizeId: QPageSize.PageSizeId)、QPageSize(size:Union[QSizeF,QSize],units: QPageSize.Unit)方法定义新的尺寸。

    • 用QPageSize的size(units:QPageSize.Unit)方法获取纸张尺寸 QSizeF;

    • 用sizePixels(resolution: int)方法获取用像素表示的尺寸QSize,或用sizePoints()方法获取用点表示的尺寸QSize。

      QPageSize.PageSizeId 的取值 尺寸/(mmXmm) QPageSize.PageSizeId 的取值 尺寸/(mmXmm)
      QPageSize.Letter 0 215.9×279.4 QPageSize.B2 16 500×707
      QPageSize.Legal 1 215.9×355.6 QPageSize.B3 17 353X500
      QPageSize.Executive 2 190.5×254 QPageSize.B4 18 250X353
      QPageSize.A0 3 841X1189 QPageSize.B5 19 176X250
      QPageSize.Al 4 594×841 QPageSize.B6 20 125×176
      QPageSize.A2 5 420×594 QPageSize.B7 21 88X125
      QPageSize.A3 6 297×420 QPageSize.B8 22 62×88
      QPageSize.A4 7 210×297 QPageSize.B9 23 44X62
      QPageSize.A5 8 148X210 QPageSize.B10 24 31X44
      QPageSize.A6 9 105×148 QPageSize.C5E 25 163X229
      QPageSize.A7 10 74X105 QPageSize.Col0E 26 105×241
      QPageSize.A8 11 52×74 QPageSize.DLE 27 110X220
      QPageSize.A9 12 37X52 QPageSize.Folio 28 210X330
      QPageSize.BO 14 1000×1414 QPageSize.Ledger 29 431.8×279.4
      QPageSize, B1 15 707×1000 QPageSize.Tabloid 30 279.4×431.8
  • 用setPaperSource(QPrinter.PaperSource)方法设置纸张来源(位置),参数可取:

    • QPrinter.Auto
    • QPrinter.Cassette
    • QPrinter.Envelope
    • QPrinter.EnvelopeManual
    • QPrinter.FormSource
    • QPrinter.LargeCapacity
    • QPrinter.LargeFormat
    • QPrinter.Lower
    • QPrinter.MaxPageSource
    • QPrinter.Middle
    • QPrinter.Manual
    • QPrinter.OnlyOne
    • QPrinter.Tractor
    • QPrinter.SmallFormat
    • QPrinter.Upper
    • QPrinter.CustomSource
    • QPrinter.LastPaperSource

    用supportedPaperSources()方法获取打印机支持的纸张来源列表。

  • 用setPageLayout(pageLayout:QPageLayout)方法为打印机设置页面布局页面布局QPageLayout 用于设置页面的方向、页面尺寸和页边距。

    • 用QPageLayout 创建页面布局的方法是以下方法:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      from PySide6.QtGui import QPageLayout

      QPageLayout(self) -> None
      QPageLayout(other: PySide6.QtGui.QPageLayout) -> None

      QPageLayout(pageSize: Union[PySide6.QtGui.QPageSize, PySide6.QtGui.QPageSize.PageSizeId, PySide6.QtCore.QSize],
      orientation: PySide6.QtGui.QPageLayout.Orientation,
      margins: Union[PySide6.QtCore.QMarginsF, PySide6.QtCore.QMargins],
      units: PySide6.QtGui.QPageLayout.Unit=Instance(QPageLayout.Unit.Point),
      minMargins: Union[PySide6.QtCore.QMarginsF,
      PySide6.QtCore.QMargins]=Instance(QMarginsF(0, 0, 0, 0))) -> None
    • 利用QPageLayout 的 setPageSize(pageSize: Union[QPageSize,QPageSize.PageSizeld, QSize], minMargins: Union[QMarginsF, QMargins]=QMarginsF(0,0,0,0))方法可以设置纸张尺寸;

    • 用setOrientation(orientation:QPageLayout.Orientation)方法设置方向(横向或纵向);

    • 用setMargins(margins:Union[QMarginsF,QMargins])方法设置 页边距;

    • 用setUnits(units:QPageLayout.Unit)方法设置单位;

    • 用setMode(mode:QPageLayout.Mode)方法设置布局模式,参数mode 可取:

      • QPageLayout.StandardMode(打印范围包含页边距,值是0)
      • QPageLayout.FullPageMode(打印范围不含页边距,值是1)
实例

运行下面的程序,选择合适的打印机、设置打印份数,并可选择是否打印到文件,单击

打印”按钮后开始打印。在每页上打印一个五角星。

image-20230219003411217

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import sys
from PySide6.QtWidgets import QApplication, QWidget, QComboBox, QPushButton, QCheckBox, QLineEdit, QSpinBox, QFormLayout
from PySide6.QtPrintSupport import QPrinter, QPrinterInfo
from PySide6.QtGui import QPen, QPainter, QPageSize, QPageLayout
from PySide6.QtCore import QPointF, QPoint
from math import cos, sin, pi


class MyWidget(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.comboBox=QComboBox()
self.comboBox.currentTextChanged.connect(self.comboBox_currentText) # 信号与槽连接

self.spin_copies=QSpinBox()
self.spin_copies.setRange(1, 100)

self.checkBox=QCheckBox('输出到文件')
self.checkBox.clicked.connect(self.checkBox_clicked)

self.line_file=QLineEdit()
self.line_file.setText('d:/stars.pdf')
self.line_file.setEnabled(self.checkBox.isChecked())

self.btn_printer=QPushButton('打印')
self.btn_printer.clicked.connect(self.btn_printer_clicked) # 信号与槽连接

formLayout=QFormLayout(self)
formLayout.addRow("选择打印机:", self.comboBox)
formLayout.addRow("设置打印份数:", self.spin_copies)
formLayout.addRow(self.checkBox, self.line_file)
formLayout.addRow(self.btn_printer)

printerNames=QPrinterInfo.availablePrinterNames()
self.comboBox.addItems(printerNames)
self.comboBox.setCurrentText(QPrinterInfo.defaultPrinterName())

def comboBox_currentText(self, text): # 槽函数
printInfo=QPrinterInfo.printerInfo(text)

self.printer=QPrinter(printInfo) # 打印机
self.printer.setPageOrientation(QPageLayout.Orientation.Portrait)
self.printer.setFullPage(False)
self.printer.setPageSize(QPageSize.A4)
self.printer.setColorMode(QPrinter.ColorMode.GrayScale)

def checkBox_clicked(self, checked): # 槽函数
self.line_file.setEnabled(checked)

def btn_printer_clicked(self): # 槽函数
self.printer.setOutputFileName(None)

if self.checkBox.isChecked():
self.printer.setOutputFileName(self.line_file.text()) # 设置打印到文件中if self.printer.isValid():
self.painter=QPainter()

if self.painter.begin(self.printer):
pen=QPen() # 钢笔
pen.setWidth(3) # 线条宽度
self.painter.setPen(pen) # 设置钢笔

x=self.printer.paperRect(QPrinter.Unit.DevicePixel).width() / 2 # 中心x坐标
y=self.printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2 # 中心y坐标
r=min(self.printer.pageRect(QPrinter.Unit.DevicePixel).width() / 2, self.printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2) # 外接圆半径

p1=QPointF(r * cos(-90 * pi / 180) + x, r * sin(-90 * pi / 180) + y)
p2=QPointF(r * cos(-18 * pi / 180) + x, r * sin(-18 * pi / 180) + y)
p3=QPointF(r * cos(54 * pi / 180) + x, r * sin(54 * pi / 180) + y)
p4=QPointF(r * cos(126 * pi / 180) + x, r * sin(126 * pi / 180) + y)
p5=QPointF(r * cos(198 * pi / 180) + x, r * sin(198 * pi / 180) + y)
pageCopies=self.spin_copies.value()

for i in range(1, pageCopies + 1):
self.painter.drawPolyline([p1, p3, p5, p2, p4, p1]) # 绘制五角星
print("正在提交第{}页,共{}页".format(i, pageCopies))
if i !=pageCopies:
self.printer.newPage()
self.painter.end()


if __name__=='__main__':
app=QApplication(sys.argv)

win=MyWidget()

win.show()

sys.exit(app.exec())

控件界面打印render

如果要打印窗口或控件的界面,需要利用QWidget的render()函数,它可以把窗口或控件的指定区域打印到纸张或文件中。

render()函数的格式如下所示:

1
2
3
4
5
6
7
8
9
render(painter: PySide6.QtGui.QPainter, 
targetOffset: PySide6.QtCore.QPoint,
sourceRegion: Union[PySide6.QtGui.QRegion, PySide6.QtGui.QBitmap, PySide6.QtGui.QPolygon, PySide6.QtCore.QRect]=Default(QRegion),
renderFlags: PySide6.QtWidgets.QWidget.RenderFlag=Instance(QWidget.RenderFlags(QWidget.RenderFlag.DrawWindowBackground | QWidget.RenderFlag.DrawChildren))) -> None

render(target: PySide6.QtGui.QPaintDevice,
targetOffset: PySide6.QtCore.QPoint=Default(QPoint),
sourceRegion: Union[PySide6.QtGui.QRegion, PySide6.QtGui.QBitmap, PySide6.QtGui.QPolygon, PySide6.QtCore.QRect]=Default(QRegion),
renderFlags: PySide6.QtWidgets.QWidget.RenderFlag=Instance(QWidget.RenderFlags(QWidget.RenderFlag.DrawWindowBackground | QWidget.RenderFlag.DrawChildren))) -> None
  • targetOffset是指在纸张或文件中的偏移量;
  • sourceRegion是指窗口或控件的区域,如果不给出则取rect()的返回值;
  • target是指绘图设备,如 QPixmap; renderFlags 是枚举值QWidget.RenderFlag 取值的组合,可取:
    • QWidget.DrawWindowBackground(打印背景)
    • QWidget.DrawChildren(打印子控件)
    • QWidget.IgnoreMask(忽略mask()函数)。

如果将对话框–>打印–>打印机QPrinter例子中的槽函数btn_printer_clicked(self)作如下的修改,就可以把整个窗口打印到纸上或文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import sys
from PySide6.QtWidgets import QApplication, QWidget, QComboBox, QPushButton, QCheckBox, QLineEdit, QSpinBox, QFormLayout
from PySide6.QtPrintSupport import QPrinter, QPrinterInfo
from PySide6.QtGui import QPen, QPainter, QPageSize, QPageLayout
from PySide6.QtCore import QPointF, QPoint
from math import cos, sin, pi


class MyWidget(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.comboBox=QComboBox()
self.comboBox.currentTextChanged.connect(self.comboBox_currentText) # 信号与槽连接

self.spin_copies=QSpinBox()
self.spin_copies.setRange(1, 100)

self.checkBox=QCheckBox('输出到文件')
self.checkBox.clicked.connect(self.checkBox_clicked)

self.line_file=QLineEdit()
self.line_file.setText(r'C:\Users\Hi\Desktop/stars.pdf')
self.line_file.setEnabled(self.checkBox.isChecked())

self.btn_printer=QPushButton('打印')
self.btn_printer.clicked.connect(self.btn_printer_clicked) # 信号与槽连接

formLayout=QFormLayout(self)
formLayout.addRow("选择打印机:", self.comboBox)
formLayout.addRow("设置打印份数:", self.spin_copies)
formLayout.addRow(self.checkBox, self.line_file)
formLayout.addRow(self.btn_printer)

printerNames=QPrinterInfo.availablePrinterNames()
self.comboBox.addItems(printerNames)
self.comboBox.setCurrentText(QPrinterInfo.defaultPrinterName())

def comboBox_currentText(self, text): # 槽函数
printInfo=QPrinterInfo.printerInfo(text)

self.printer=QPrinter(printInfo) # 打印机
self.printer.setPageOrientation(QPageLayout.Orientation.Portrait)
self.printer.setFullPage(False)
self.printer.setPageSize(QPageSize.A4)
self.printer.setColorMode(QPrinter.ColorMode.GrayScale)

def checkBox_clicked(self, checked): # 槽函数
self.line_file.setEnabled(checked)

def btn_printer_clicked(self): # 新的按钮槽函数
self.printer.setOutputFileName(None)

if self.checkBox.isChecked():
self.printer.setOutputFileName(self.line_file.text()) # 设置打印到文件中

if self.printer.isValid():
self.painter=QPainter()

if self.painter.begin(self.printer):
self.render(self.painter, QPoint(200, 0))
self.painter.end()

def btn_printer_clicked_old(self): # 旧的按钮槽函数,可去掉old对比
self.printer.setOutputFileName(None)

if self.checkBox.isChecked():
self.printer.setOutputFileName(self.line_file.text()) # 设置打印到文件中if self.printer.isValid():
self.painter=QPainter()

if self.painter.begin(self.printer):
pen=QPen() # 钢笔
pen.setWidth(3) # 线条宽度
self.painter.setPen(pen) # 设置钢笔

x=self.printer.paperRect(QPrinter.Unit.DevicePixel).width() / 2 # 中心x坐标
y=self.printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2 # 中心y坐标
r=min(self.printer.pageRect(QPrinter.Unit.DevicePixel).width() / 2, self.printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2) # 外接圆半径

p1=QPointF(r * cos(-90 * pi / 180) + x, r * sin(-90 * pi / 180) + y)
p2=QPointF(r * cos(-18 * pi / 180) + x, r * sin(-18 * pi / 180) + y)
p3=QPointF(r * cos(54 * pi / 180) + x, r * sin(54 * pi / 180) + y)
p4=QPointF(r * cos(126 * pi / 180) + x, r * sin(126 * pi / 180) + y)
p5=QPointF(r * cos(198 * pi / 180) + x, r * sin(198 * pi / 180) + y)
pageCopies=self.spin_copies.value()

for i in range(1, pageCopies + 1):
self.painter.drawPolyline([p1, p3, p5, p2, p4, p1]) # 绘制五角星
print("正在提交第{}页,共{}页".format(i, pageCopies))
if i !=pageCopies:
self.printer.newPage()
self.painter.end()


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWidget()
win.show()
sys.exit(app.exec())

image-20230219223851175

控件内容打印

有些控件中可以输人文本、图片等内容,例如在QTextEdit 中可以输入图像、表格和较长的文本,如果只是想把控件中输入的内容打印出来,就需要用控件提供的打印函数。

能打印控件内容的控件和打印函数如表所示,当打印内容较长时,会自动分成多页内容打印。

控件 控件的打印函数 打印设备
QTextEdit print_(printer:QPrinter) QPrinter
QGraphicsView render(painter: QPainter, target: Union[QRectF,QRect]=Default(QRectF), source: QRect=Default(QRect),aspectRatioMode: Qt.AspectRatioMode=Qt.KeepAspectRatio) QPainter
QWebEngineView print(printer:QPrinter) QPrinter
QSvgWidget render(painter: QPainter, targetOffset: QPoint, sourceRegion: Union[QRegion,QBitmap,QPolygon, QRect]=Default(QRegion), renderFlags=QWidget.DrawWindowBackground | QWidget.DrawChildren) QPainter
QTextLine draw(painter: QPainter,position:Union[QPointF,QPoint]) draw(p: QPainter, pos: Union[QPointF.QPoint], selections: QPainter
QTextLayout Sequence[QTextLayout.FormatRange]), clip: Union[QRectF- QRect]=Default(QRectF)) QPzinter

pdf生成器QPdfWriter

现在越来越多的资料以pdf文档的形式进行保存,PySide可以将QPainter绘制的图形、文字和图像等转换成 pdl文档。

转换成pdf文档的类是QPdfWriter.它继承自QObject和 QPagedPaintDevice。用QPdfWriter 创建实例对象的方法如下所示。

1
2
3
4
from PySide6.QtGui import QPdfWriter

QPdfWriter(device: PySide6.QtCore.QIODevice) -> None
QPdfWriter(filename: str) -> None
pdf文档生成器QPdfWriter 的常用方法

pdf 文档生成器QPdfWriter的常用方法如表所示。

主要方法是用newPage()方法生成新页;

用setPageSize(pageSize:Union[QPageSize,QSize,QPageSize.PageSizeld])方法设置页面尺寸;

用setPageOrientation(QPageLayout.Orientation)友法设置文档的方向(横向或纵向);

用setPageLayout(pageLayout:QPageLayout)方法设置布局(纸张尺寸、页边距和文档方向);

用setPdfVersion(version)方法设置pdf文档的版本,参数version可取 QPdfWriter.PdfVersion_1_4,QPdfWriter, PdfVersion_A1b 或 QPd[Writer.PdfVersion_I_6.对应的值分别是0、1、2。

QPdfWriter的方法及参数类型 返回值的类型 说 明
newPage() bool 生成新页
setCreator(creator:str) None 设置pdi文档的创建者
creator() Str 获取创建者
setPdfVersion(version:QPagedPaintDevice.PdfVersion) None 设置版本号
setResolution(resolution:int) None 设置分辨率(单位是dpi)
resolution() int 获取分辨率
setTitle(title: str) None 设置pdf文档标题
tirle() Str 获取标题
setPageLayout(pageLayout:QPageLayout) bool 设置布局
pageLayout() QPageLayout 获取布局
setPageMargins(margins: Union[QMarginsF, QMargins], units: QPageLayout.Unit=QPageLayout.Millimeter) bool 设置页边距
setPageOrientation(QPageLayout.Orientation) bool 设置文档方向
setPageRanges(ranges:QPageRanges) None 设置页数范围
pageRanges() QPageRanges 获取页数范围
setPageSize(pageSize: Union[QPageSize, QSize, QPageSize.PageSizeId]) bool 设置页面尺寸
pdf文档生成器QPdfWriter 的应用实例

下面的程序创建3页pdf文档,每页中用QPainter绘制一个五角星。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import sys
from PySide6.QtWidgets import QApplication, QWidget, QPushButton
from PySide6.QtGui import QPainter, QPageSize, QPdfWriter, QPagedPaintDevice
from PySide6.QtCore import QPointF
from math import sin, cos, pi


class NyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
btn_printer=QPushButton('Pdf 打印', self)
btn_printer.clicked.connect(self.btn_printer_clicked) # 信号与槽连接

def btn_printer_clicked(self): # 槽函数
pdfWriter=QPdfWriter(r'C:\Users\Hi\Desktop/mystrars.pdf') # 创建 pdf 文档生成器,设置文件名
pageSize=QPageSize(QPageSize.A4) # 纸张尺寸
pdfWriter.setPageSize(pageSize) # 设置纸张尺寸

pdfWriter.setPdfVersion(QPagedPaintDevice.PdfVersion.PdfVersion_1_6) # 设置版本号

painter=QPainter()
if painter.begin(pdfWriter):
size=pageSize.size(QPageSize.Unit.Millimeter)
x=size.width() * 20 # 绘图区中心x坐标
y=size.height() * 20 # 绘图区中心y坐标
r=min(x / 2, y / 2) # 五角星的外接圆半径

p1=QPointF(r * cos(-90 * pi / 180) + x, r * sin(-90 * pi / 180) + y)
p2=QPointF(r * cos(-18 * pi / 180) + x, r * sin(-18 * pi / 180) + y)
p3=QPointF(r * cos(54 * pi / 180) + x, r * sin(54 * pi / 180) + y)
p4=QPointF(r * cos(126 * pi / 180) + x, r * sin(126 * pi / 180) + y)
p5=QPointF(r * cos(198 * pi / 180) + x, r * sin(198 * pi / 180) + y)

pageCopies=3 # 页数for

for i in range(1, pageCopies + 1):
painter.drawPolyline([p1, p3, p5, p2, p4, p1]) # 绘制五角星
print("正在打印第{}页,共{}页.".format(i, pageCopies))
if i !=pageCopies:
pdfWriter.newPage()
painter.end()


if __name__=='__main__':
app=QApplication(sys.argv)
win=NyWidget()
win.show()
sys.exit(app.exec())

打印对话框和打印预览

除了直接用QPrinter 进行打印外,还可以利用打印对话框 QPrintDialog 来打印,在对话框中完成对 QPrinter的设置并进行打印。

一般在打印前需要对打印的内容进行打印预览,打印预览对话框是 QPrintPreviewDialog,还可以利用打印预览控件 QPrintPreiewWidget创建打印预览对话框。PySide提供的 Windows 10平台下的打印对话框和打印预览对话框

打印对话框QPrintDialog

打印对话框QPrintDialog提供了对QPrinter 各种参数的设置功能,例如打印机的选择、打印方向、颜色模式、打印份数、纸张和页边距 等。

QPrintDialog 继承自QAbstractPrintDialog 和QDialog,用QPrintDialog创建打印对话框的方法如下所示,为指定的QPrinter对象创建对话框需要提供QPrinter,如果没有提供QPrinter,将使用系统默认的打印机。

1
2
3
4
from PySide6.QtPrintSupport import QPrintDialog

QPrintDialog(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QPrintDialog(printer: PySide6.QtPrintSupport.QPrinter, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
打印对话框QPrintDialog的常用方法

打印对话框 QPrintDialog的常用方法如表所示,主要方法介绍如下。

  • 一般用exec()方法模式显示对话框,在对话框中单击”打印”按钮,返回值为1,同时发送accepted(printer:QPrinter)信号,在对话框中单击”取消”按钮,返回值为0。也可用setVisible(visible: bool)方法或 show()方法显示对话框,这两种方法没有返回值。
  • 用setOption(option,on:bool=True)方法可以在显示对话框之前预先设置一些选项,其中 option 可取 QPrintDialog.PrintToFile、QPrintDialog.PrintSelection,QPrintDialog.PrintPageRange、QPrintDialog.PrintShowPageSize、QPrintDialog.PrintCollateCopies 或 QPrintDialog.PrintCurrentPage; 用testOption(option)方法测试是否设置了某个选项。
  • 用setPrintRange(range)方法设置打印范围选项,range 可取 QPrintDialog.AllPages、QPrintDialog.Selection、QPrintDialog.PageRange 或 QPrintDialog.CurrentPage;用setFromTo(fromPage: int,toPage:int)方法设置打印页数范围。
QPrintDialog的方法及参数类型 返回值的类型 说明
exec() int 模式显示对话框
setVisible(visible:bool) None 显示打印对话框
setOption(option,on:bool=True) None 设置可选项
setOptions(options) None 设置多个可选项
testOption(option) bool 测试是否设置了某种选项
setPrintRange(range) None 设置打印范围选项
setFromTo(fromPage: int,toPage: int) None 设置打印页数范围
setMinMax(min:int,max: int) None 设置打印页数的最小和最大值
printer() QPrinter 获取打印机
打印对话框QPrintDialog的信号

QPrintDialog只有一个信号 accepted(printer:QPrinter),在对话框中单击”打印”按钮时发送信号,参数是设置了打印参数的QPrinter 对象。

打印对话框QPrintDialog的应用实例

运行下面的程序,单击”打印”按钮,弹出打印对话框,选择系统中的打印机、设置打印份数后,单击对话框中的”打印”按钮后开始打印。

这里打印的是五角星:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import sys
from PySide6.QtWidgets import QApplication, QWidget, QPushButton
from PySide6.QtPrintSupport import QPrinter, QPrintDialog
from PySide6.QtGui import QPen, QPainter
from PySide6.QtCore import QPointF
from math import sin, cos, pi


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.btn_printer=QPushButton('打印', self)
self.btn_printer.clicked.connect(self.btn_printer_clicked)
self.printDialog=QPrintDialog(self)
self.printDialog.accepted.connect(self.printDialog_accepted)

def btn_printer_clicked(self):
self.printDialog.exec()

def printDialog_accepted(self, printer: QPrinter):
if printer.isValid():
painter=QPainter()
if painter.begin(printer):
pen=QPen() # 钢笔
pen.setWidth(3) # 线条宽度
painter.setPen(pen) # 设置钢笔

x=printer.paperRect(QPrinter.Unit.DevicePixel).width() / 2 # 中心x坐标
y=printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2 # 中心y坐标
r=min(printer.pageRect(QPrinter.Unit.DevicePixel).width() / 2, printer.paperRect(QPrinter.Unit.DevicePixel).height() / 2) # 外接圆半径

p1=QPointF(r * cos(-90 * pi / 180) + x, r * sin(-90 * pi / 180) + y)
p2=QPointF(r * cos(-18 * pi / 180) + x, r * sin(-18 * pi / 180) + y)
p3=QPointF(r * cos(54 * pi / 180) + x, r * sin(54 * pi / 180) + y)
p4=QPointF(r * cos(126 * pi / 180) + x, r * sin(126 * pi / 10) + y)
p5=QPointF(r * cos(198 * pi / 180) + x, r * sin(198 * pi / 180) + y)

painter.drawPolyline([p1, p3, p5, p2, p4, p1]) # 绘制五角星
painter.end()


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWidget()
win.show()
sys.exit(app.exec())

打印预览对话框QPrintPreviewDialog

在开始打印之前,一般需要预览打印的效果。预览打印效果可在打印预览对话框QPrintPreviewDialog 中进行。

用QPrintPreviewDialog 创建打印预览对话框的方法如下所示,一般需要提供一个已经定义的QPrinter 对象,如果没有提供则用系统默认的打印机。

1
2
3
4
from PySide6.QtPrintSupport import QPrintPreviewDialog

QPrintPreviewDialog(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None
QPrintPreviewDialog(printer: PySide6.QtPrintSupport.QPrinter, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

打印预览对话框 QPrintPreviewDialog的显示方法仍是exec()、setVisible(visible:bool)或 show()方法,

在显示对话框之前会发送 paintRequested(printer:QPrinter)信号,需要在 paintRequested(printer:QPrinter)对应的槽函数中编写要预览的内容,把内容输人到参数printer 上。

要获取打印对话框中关联的打印机,可以使用QPrintPreviewDialog 的printer()方法。

下面的程序是打印预览对话框和打印对话框的应用实例。运行该程序,在QTextEdit控件中输人内容,单击文件菜单中的”打印预览”命令,弹出打印预览对话框,可查看打印效果;在打印预览对话框中单击按钮,弹出打印对话框即可进行打印,或者关闭打印预览对话框,单击文件菜单中的”打印”命令,弹出打印对话框进行打印。

image-20230220000424757

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import sys
from PySide6.QtWidgets import QApplication, QWidget, QTextEdit, QMenuBar, QVBoxLayout
from PySide6.QtPrintSupport import QPrintPreviewDialog, QPrintDialog, QPrinter, QPrinterInfo
from PySide6.QtCore import Qt


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.showMaximized()
menuBar=QMenuBar()
fileMenu=menuBar.addMenu("文件(&F)")
openaction=fileMenu.addAction("打开")
openaction.triggered.connect(self.openaction_triggered) ##信号与槽连接

previewAction=fileMenu.addAction("打印预览")
previewAction.triggered.connect(self.previewhction_triggered) # 信号与槽连接

printAction=fileMenu.addAction("打印")
printAction.triggered.connect(self.printAction_triggered) # 信号与槽连接

fileMenu.addSeparator()
fileMenu.addAction("退出").triggered.connect(self.close) # 信号与槽连接

self.textEdit=QTextEdit()

V=QVBoxLayout(self)
V.addWidget(menuBar)
V.addWidget(self.textEdit)
self.printer=QPrinter(QPrinterInfo.defaultPrinter()) # 创建默认的打印机

def openaction_triggered(self): # 槽函数
# 在此添加打开文件代码,将内容读取到QTextEdit 中,这里以简单文本代替
font=self.textEdit.font()
font.setPointSize(30)
self.textEdit.setFont(font)
for i in range(100):
self.textEdit.append("北京诺思多维科技有限公司")

def previewhction_triggered(self): # 槽函数
# 打印预览对话框
previewDialog=QPrintPreviewDialog(self.printer, self, flags=Qt.WindowFlags.WindowMinimizeButtonHint | Qt.WindowFlags.WindowMaximizeButtonHint | Qt.WindowFlags.WindowCloseButtonHint)
previewDialog.paintRequested.connect(self.preview_paintRequested)
previewDialog.exec()

self.printer=previewDialog.printer()

def preview_paintRequested(self, printer): # 槽函数
self.textEdit.print_(printer) # 预览QTextEdit控件中的内容

def printAction_triggered(self): # 槽函数
printDialog=QPrintDialog(self.printer)
printDialog.accepted.connect(self.printDialog_accepted) # 信号与槽连接
printDialog.exec()

def printDialog_accepted(self, printer): # 槽函数
self.textEdit.print_(printer) # 打印QTextEdit控件中的内容


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWidget()
win.show()
sys.exit(app.exec())

打印预览控件QprintPreviewWidget

打印预览对话框 QPrintPreviewDialog 实际上包含一个打印预览控件QPrintPreviewWidget,用户可以将打印预览控件QPrintPreviewWidget 嵌入到自己的应用程序中,从而不使用打印预览对话框进行打印预览,而是在自定义的界面中进行打印预览。

用QPrintPreviewWidget进行打印预览的过程与用打印预览对话框QPrintPreviewDialog进行预览的过程相同。

首先要创建QPrintPreviewWidget的应用实例,可以将其放入其他控件中,然后将QPrintPreviewWidget的信号 paintRequested(printer:QPrinter)与槽函数连接,最后在对应的槽函数中编写要打印的内容。

QPrintPreviewWidge 继承自QWidget,用QPrintPreviewWidge创建打印预览控件的方法如下所示,如果没有指定printer 参数,则使用系统默认的打印机。

1
2
3
4
5
6
7
8
from PySide6.QtPrintSupport import QPrintPreviewWidget

QPrintPreviewWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None,
flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

QPrintPreviewWidget(printer: PySide6.QtPrintSupport.QPrinter,
parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None,
flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None
打印预览控件QPrintPreviewWidget 的常用方法

打印预览控件QPrintPreviewWidget 的常用方法如表所示,主要方法介绍如下。

  • 用updatePreview()方法可以更新预览,发送 paintRequested(printer)信号;用print_)方法打印预览的内容。

  • 用setViewMode(viewMode:QPrintPreviewWidget.ViewMode)方法设置预览模式,参数 viewMode 可取:

    • PrintPreviewWidget.SinglePageView(单页模式,值是0)
    • QPrintPreviewWidget.FacingPagesView(左右两页模式,值是1)
    • QPrintPreviewWidget.AllPagesView(所有页模式,值是2)

    也可分别使用setSinglePageViewMode()方法、setFacingPagesViewMode()方法或 setAlIPagesViewMode()方法设置。

  • 可以对预览进行缩放,用setZoomMode(zoomMode:QPrintPreviewWidget,ZoomMode)方法设置缩放模式,参数 zoomMode 可取 :

    • QPrintPreviewWidget.CustomZoom(自定义缩放模式,值是0)
    • QPrintPreviewWidget.FitToWidth(以最大宽度方式显示,值是1)
    • QPrintPreviewWidget.PitInView(以最大适合方式显示,值是2)。

    后两种模式可以用{fitToWidth()方法和fitInView()方法代替;

    对于自定义缩放模式,可以先用setZoomFactor(zoomFactor:float)方法定义缩放系数,然后用zoomIn(zoom:float=1.1)方法和zoomOut(zoom:float=1.1)方法进行缩放。

QPrintPreviewWidget的方法及参数类型 返回值的类型 说 明
[slot]updatePreview() None 更新预览,发送 paintRequested(printer) 信号
pageCount() int 获取页数
[slot]print_() None 用关联的QPrinter进行打印
[slot]setCurrentPage(pageNumber:int) None 设置当前预览的页
currentPage() int 获取当前预览的页
[slot]setOrientation(orientation: QPageLayout.Orientation) None 设置预览方向
[slot]setLandscapeOrientation() None 横向预览
[slot]setPortraitOrientation() None 纵向预览
[slot]setViewMode(viewMode: QPrintPreviewWidget.ViewMode) None 设置预览模式
[slot]setSinglePageViewMode() None 以单页模式预览
[slot]setFacingPagesViewMode() None 以左右两页模式预览
[slot]setAllPagesViewMode() None 以所有页全部显示模式预览
[sIot]setZoomMode(zoomMode: QPrintPreviewWidget.ZoomMode) None 设置缩放模式
[sIot]fitToWidth() None 以最大宽度方式显示当前页
[slot]fitInView() None 以最大适合方式显示当前页
[slot]setZoomFactor(z00mFactor:float) None 设置缩放系数
zoomFactor() float 获取缩放系数
[slot]zoomIn(zoom:float=1.1) None 缩小显示
[slot]zoomOut(zoom: float=1.1) None 放大显示
打印预览控件QPrintPreviewWidget信号

打印预览控件 QPrintPreviewWidget 的信号有 paintRequested(printer: QPrinter)和previewChanged()

  • 当显示打印预览控件或更新预览控件时发送 paintRequested(printer:QPrinter)信号,需要在参数 printer 上写人需要预览的内容;
  • 当打印预览控件的内部状态发生改变时,例如预览方向发生改变,就会发送previewChanged()信号。

QDialogButtonBox

上面介绍的几个对话框都是QDialog的子类,QDialogButtonBox有些特殊,和QDialog一样,也是 QWidget 的子类。

严格来说,QDialogButtonBox并不是一个对话框,只是一个管理按钮的容器,可以根据不同的系统环境匹配相应的布局。

1
2
3
4
5
6
from PySide6.QtWidgets import QDialogButtonBox

QDialogButtonBox(buttons: PySide6.QtWidgets.QDialogButtonBox.StandardButton, orientation: PySide6.QtCore.Qt.Orientation, parent: Union[PySide6.QtWidgets.QWidget, NoneType] = None) -> None
QDialogButtonBox(buttons: PySide6.QtWidgets.QDialogButtonBox.StandardButton, parent: Union[PySide6.QtWidgets.QWidget, NoneType] = None) -> None
QDialogButtonBox(orientation: PySide6.QtCore.Qt.Orientation, parent: Union[PySide6.QtWidgets.QWidget, NoneType] = None) -> None
QDialogButtonBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType] = None) -> None

方法介绍

常见的使用场景是将QDialogButtonBox 嵌入 QDialog中,用它管理 QDialog 的按钮。

当然,也可以将QDialogButonBox 嵌入主窗口中管理主窗口按钮。

Qt会为不同的系统自动匹配相应的样式,QDialogButtonBox会根据系统自动改变 应布局,主要的系统布局如表所示。

系统布局 描 述
QDialogButtonBox.WinLayout O 适用于 Windows 中的应用程序的策略
QDialogButtonBox.MacLayout 1 适用于macOS中的应用程序的策略
QDialogButtonBox.KdeLayout 2 适用于 KDE 中的应用程序的策略
QDialogButtonBox.GnomeLayout 3 适用于GNOME中的应用程序的策略
QDialogButtonBox.AndroidLayout 4 适用于Android中的应用程序的策略 这个枚举值是在Qt5.10中添加的
  • 使用 QStyleFactory.keys0函数可以知道当前系统支持哪些样式

    • Windows 10 支持’windowsvista’、’Windows’和’Fusion’这3种样式:

      1
      2
      3
      from PySide6.QtWidgets import QStyleFactory

      print(QStyleFactory.keys())#['windowsvista', 'Windows', 'Fusion']
  • 使用QApplication.setStyle()函数可以设置样式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import sys
    from PySide6.QtWidgets import QApplication, QDialogButtonBox

    if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    demo = QDialogButtonBox()
    demo.show()
    sys.exit(app.exec())
  • QDialogButtonBox 和QMessageBox 类似

    • 它们共用一套标准化按钮(如 Ok、Cancel,Yes 和 No等)
    • 一套按钮角色(如 AcceptRole、RejectRole 等),
    • 及槽函数 accepted 和rejected 的实现方式。
    • 除此之外,QDialogButtonBox多了两个信号发射方式。
      • helpRequested():当基于 HelpRole 的按钮单击时触发。
      • clicked(button:QAbstractButton): 当单击任意按钮时触发,携带参数 QAbstractButton

QDialogButtonBox例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/14 23:49
# File_name: 01-QDialogButtonBox例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class DialogButtonBox(QWidget):
def __init__(self):
super(DialogButtonBox, self).__init__()
self.setWindowTitle("QDialogButtonBox 例子")
self.resize(300, 100)
layout = QVBoxLayout()
self.setLayout(layout)
self.label = QLabel('显示信息')
layout.addWidget(self.label)

buttonBox_dialog = self.create_buttonBox()
button1 = QPushButton("1、嵌入对话框中")
layout.addWidget(button1)
button1.clicked.connect(lambda: self.show_dialog(buttonBox_dialog))

layout.addWidget(QLabel('2、嵌入窗口中:'))
layout.addWidget(self.create_buttonBox())

def show_dialog(self, buttonBox):
dialog = QDialog(self)
dialog.setWindowTitle("Dialog + QDialogButtonBox demo")
layout = QVBoxLayout()
layout.addWidget(QLabel('QDialogButtonBox嵌入到对话框中实例'))
layout.addWidget(buttonBox)
dialog.setLayout(layout)
dialog.move(self.geometry().x(), self.geometry().y() + 180)
# 绑定相应信号与槽,用于退出对话框
buttonBox.accepted.connect(dialog.accept)
buttonBox.rejected.connect(dialog.reject)
buttonBox.setOrientation(Qt.Vertical) # 垂直排列
dialog.exec()

def create_buttonBox(self):
buttonBox = QDialogButtonBox()
buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.Reset | QDialogButtonBox.Help | QDialogButtonBox.Yes | QDialogButtonBox.No | QDialogButtonBox.Apply)
# 自定义按钮
buttonBox.addButton(QPushButton('MyOk-ApplyRole'), buttonBox.ButtonRole.ApplyRole)
buttonBox.addButton(QPushButton('MyOk-AcceptRole'), buttonBox.ButtonRole.AcceptRole)
buttonBox.addButton(QPushButton('MyNo-AcceptRole'), buttonBox.ButtonRole.RejectRole)
# 绑定信号与槽
buttonBox.accepted.connect(lambda: self.label.setText(self.label.text() + '\n触发了accepted'))
buttonBox.rejected.connect(lambda: self.label.setText(self.label.text() + '\n触发了rejected'))
buttonBox.helpRequested.connect(lambda: self.label.setText(self.label.text() + '\n触发了helpRequested'))
buttonBox.clicked.connect(lambda button: self.label.setText('点击了按钮:' + button.text()))
return buttonBox


if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion')
demo = DialogButtonBox()
demo.show()
sys.exit(app.exec())

停靠控件QDockWidget

QDockWidget

停靠控件QDockWidget主要应用在主窗口中,用鼠标可以将其拖拽到不同的停靠区域中。停靠控件通常作为容器来使用,需要在其内部添加一些常用控件。

停靠控件由标题栏和内容区构成,标题栏上显示窗口标题,还有浮动按钮和关闭按钮。

停靠控件QDockWidget继承自QWidget。用QDockWidget类创建停靠控件实例的方法如下所示,其中title是停靠控件的窗口标题,parent是停靠控件所在的窗口。

1
2
3
4
from PySide6.QtWidgets import QDockWidget

QDockWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None
QDockWidget(title: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, flags: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

停靠控件 QDockWidget的常用方法

停靠控件 QDockWidget主要方法介绍如下。

  • setWidget(QWidget)方法设置停靠控件工作区中的控件,通常选择容器类控件和表格类控件作为工作区的控件,用widget()方法获取工作区中的控件。
  • setTitleBarWidget(QWidget)方法设置标题栏中的控件,用titleBarWidget()方法获取标题栏中的控件。
  • setAllowedAreas(Qt.DockWidgetArea)方法设置停靠控件可以停靠的区域,用allowedAreas()方法获取可以停靠的区域,用isAreaAllowed(Qt.DockWidgetArea)方法获取指定的区域是否允许停靠。
  • setFeatures(QDock Widget.DockWidgetFeatures)方法设置停靠控件的特征,其中参数QDock Widget.Dock WidgetFeature 可以取以下值,用features()方法获取特征。
    • QDockWidget.DockWidgetClosable(可关闭)
    • QDock Widget.DockWidgetMovable(可移动)
    • QDockWidget.DockWidgetFloatable(可悬停)
    • QDockWidget.DockWidgetVerticalTitleBar(有竖向标题)
    • QDockWidget.AllDockWidgetFeatures(有以上所有特征)
    • QDockWidget.NoDockWidgetFeatures(没有以上特征)
  • toggleViewAction()方法返回一个QAction动作对象,单击该动作对象可以切换停靠窗口的可见状态,即该动作是一个对停靠控件窗口进行显示或关闭的开关。如果将该动作加到菜单上,对应菜单栏的文字即为停靠窗口的title文字,这样就可以在菜单上单击对应菜单项进行停靠窗口的关闭和显示。

停靠控件 QDockWidget的常用方法如表所示:

QDock Widget的方法及参数类型 返回值的类型 说 明
setAllowedAreas(Qt.Dock WidgetArea) None 设置可停靠区域
isAreaAllowed(Qt.Dock WidgetArea) bool 获取区域是否允许停靠
allowedAreas() Qt.DockWidgetArea 获取可停靠的区域
setFeatures(QDockWidget.DockWidgetFeatures) None 设置特征
setFloating(bool) None 设置成浮动状态
isFloating() bool 获取是否处于浮动状态
setTitleBarWidget(QWidget) None 设置标题栏中的控件
titleBarWidget() QWidget 获取标题栏中的控件
setWidget(QWidget) None 添加控件
widget() QWidget 获取控件
toggleViewAction() QAction 获取隐藏或显示的动作

停靠控件 QDockWidget的信号

QDockWidget的信号及参数类型 说明
allowedAreasChanged(Qt.DockWidgetArea) 允许停靠的区域发生改变时发送信号
dockLocationChanged(Qt.DockWidgetArea) 停靠的区域发生改变时发送信号
featuresChanged(QDockWidget.DockWidgetFeature) 特征改变时发送信号
topLevelChanged(bool) 悬浮和停靠状态转换时发送信号
visibilityChanged(bool) 可见性改变时发送信号

菜单栏QMenuBar、菜单QMenu、动作QAction

对于一个可视化程序界面,往往将各种操作命令集中到菜单栏或工具栏的按钮上,通过单击菜单或工具栏中的按钮来触发动作,每个菜单和按钮实现一定的功能。一般菜单栏由多个菜单构成,如图3-3所示,菜单下面又有动作、子菜单和分隔条,子菜单下面又有动作,还可以有子菜单,动作上有图标和快捷键。

菜单的构成

建立一个菜单分为3步,如图所示。

  • 第1步需要建立放置菜单的容器,即菜单栏;
  • 第2步,在菜单栏上添加菜单,或者在菜单上添加子菜单;
  • 第3步,在菜单栏、菜单或子菜单下面添加动作,并为动作编写槽函数。菜单一般不执行命令,其作用类似于标签,只有动作才可以发送信号,执行关联的槽函数。

image-20230216002511945

菜单栏QMenuBar

菜单栏QMenuBar 用于放置菜单和动作,它继承自QWidget。用QMenuBar创建菜单栏实例的方法如下,其中parent 是放置菜单栏的父窗口。

1
2
3
from PySide6.QtWidgets import QMenuBar

QMenuBar(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

菜单栏QMenuBar的方法与信号

菜单栏QMenuBar 的常用方法如表所示。

菜单栏上可以添加菜单、动作和分隔条,用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的方法及参数类型 返回值的类型 说明
addMenu(QMenu) QAction 添加已经存在的菜单
addMenu(title: str) QMenu 用字符串添加菜单,并返回菜单
addMenu(QIcon,title: str) QMenu 用字符串和图标添加菜单,并返回菜单
addAction(QAction) None 添加已经存在的动作
addAction(text:str) QAction 用字符串添加动作,并返回添加的动作
insertMenu(before:QAction,QMenu) QAction 在动作之前插入菜单
addSeparator() QAction 添加分隔条
insertSeparator(before:QAction) QAction 在动作之前插入分隔条
clear() None 清空所有的菜单和动作
setConerWidget(QWidget, Qt.Comer=Qt.TopRightCorner) None 在菜单栏的角落位置添加控件
cornerWidget(Qt.Coner=Qt.TopRightCorner) QWidget 获取角落位置的控件
Cslot]setVisible(visible: bool) None 设置菜单栏是否可见
setActiveAction(QAction) None 设置高亮显示的动作
actionAt(QPoint) QAction 获取指定位置处的动作
actionGeometry(QAction) QRect 获取动作所处的区域

菜单栏QMenuBar有两个信号,当单击莱单栏上的菜单或动作时,会发送riggered(QAction)信号;当光标滑过动作时,会发送 hovered(QAction)信号。

菜单栏QMenuBar 的应用实例

下面的程序创建一个菜单栏和一个多行纯文本控件,采用竖直布局。在菜单栏中添加两个菜单和两个动作,一个动作可以打开文件,另一个动作退出程序。单击动作,通过菜单栏的信号triggered(QAction)识别单击的是哪个动作,从而采取不同的对应方法。

image-20230216005418270

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/19 1:38
# File_name: 01-菜单栏QMenuBar 的应用实例.py


import sys
from PySide6.QtWidgets import(QApplication, QMenuBar, QPlainTextEdit, QVBoxLayout, QWidget, QFileDialog, QMessageBox)


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("OMenuBar 应用实例")
self.setupUi()

def setupUi(self):
self.menuBar = QMenuBar() # 创建菜单栏
self.plainText = QPlainTextEdit() # 创建文本编辑器
vlayout = QVBoxLayout(self) # 创建竖直布局
vlayout.addWidget(self.menuBar)
vlayout.addWidget(self.plainText)
vlayout.addWidget(self.menuBar)
vlayout.addWidget(self.plainText)

self.fileMenu = self.menuBar.addMenu("文件(&F)") # 菜单栏中添加菜单
self.editMenu = self.menuBar.addMenu("编辑(&E)") # 菜单栏中添加菜单
self.menuBar.addSeparator() # 菜单栏中添加分隔条
self.actNew = self.menuBar.addAction('新建(&N)') # 菜单栏中添加动作
self.actOpen = self.menuBar.addAction("打开(&O)") # 菜单栏中添加动作
self.actQuit = self.menuBar.addAction("退出(&Q)") # 菜单栏中添加动作
self.menuBar.triggered.connect(self.action_triggered) # 菜单栏信号与槽函数的连接

def action_triggered(self, action): # 菜单栏的槽函数
if action == self.actNew: # 新建动作
self.plainText.clear()
elif action == self.actOpen: # 打开动作
filename, filter = QFileDialog.getOpenFileName(self, "打开", ".", "文本文件(*.txt)")

try:
fp = open(filename, encoding="UTF-8")
string = fp.readlines()
self.plainText.clear()
for i in string:
self.plainText.appendPlainText(i)
fp.close()

except:
QMessageBox.critical(self, "打开文件失败", "请选择适合的文件!")

elif action == self.actQuit: # 退出动作
self.close()


if __name__ == '__main__':
app = QApplication(sys.argv)
windows = MyWindow()
windows.show()
sys.exit(app.exec())

菜单QMenu

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

1
2
3
4
from PySide6.QtWidgets import QMenu

QMenu(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QMenu(title: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

菜单QMenu的常用方法

菜单QMenu的常用方法如表3-8所示。菜单的主要方法是在菜单列表中添加动作、子菜单和分隔条、主要方法介绍如下。

  • 用addAction(QAction)方法可以添加一个已经定义好的动作;用addAction(text;str)或addAction(icon:QIcon,text:str)方法可以添加一个新创建的动作,并返回动作,其中text是动作在菜单中的名称,icon是图标。
  • 用addMenu(QMenu)方法可以将已定义好的菜单作为子菜单加入到菜单中;用addMenu(title:str)方法或addMenu(icon:QIcon,title:str)方法可以添加新的子菜单,并返回子菜单
  • 用addSection(text: str)、addSection(icon: QIcon,text: str)或addSeparator()方法可以添加分隔条,并返回对应的动作。分隔条的显示样式与操作系统有关,例如忽略动作的名称、图标或子菜单,或者显示成横线或名称。利用分隔条返回的动作,用动作的setSeparator(bool)方法可以将分隔条切换成动作,或者将动作切换成分隔条。
  • 用setTearOffEnabled(bool)方法可以将菜单定义成可撕扯菜单,可撕扯菜单在其动作列表中显示一条虚线,单击该虚线可以把菜单及动作列表弹出;用showTearOffMenu()方法或 showTearOf[Menu(QPoint)方法可以将可撕扯菜单在指定位置显示。
  • 用popup(pos: QPoint, at: QAction=None)方法或 exec(pos; QPoint, at: QAction=None)方法可以在指定位置(全局坐标系)弹出菜单,如果指定了 at参数,则指定的动作显示在指定位置。
QMenu的方法及参数类型 返回值的类型 说 明
addAction(QAction) None 在菜单中添加已存在的动作
addAction(text: str) QAction 在菜单中添加新动作
addAction(icon: QIcon,text, str) QAction 在菜单中添加新动作
addMenu(QMenu) QAction 在菜单中添加子菜单
addMenu(title: str) QMenu 在菜单中添加新子菜单
addMenu(icon: Qlcon,title: str) QMenu 在菜单中添加新子菜单
addSection(text: str) QAction 添加分隔条
addSection(icon: Qlcon,text, s1r) QAction 添加分隔条
addSeparator() QAction 添加分隔条
insertMenu(before: QAction, menu: QMenu) QAction 在动作前插入子菜单
insertSection(before: QAction, text: str) QAction 在动作前插人分隔条
insertSection(before: QAction, Qlcon, text:str) QAction 在动作前插人分隔条
insertSection(before:QAction) QAction 在动作前插人分隔条
insertSeparator(before: QAction) QAction 在动作前插人分隔条
removeAction(action:QAction) None 从菜单中移除动作
clear() None 清空菜单
actions() List[QAction] 获取菜单中的动作
isEmpty() int 获取菜单是否为空
actionAt(QPoint) QAction 获取指定位置处的动作
columnCount() int 获取列的数量
menuAction() QAction 获取菜单对应的动作
setSeparatorsCollapsible(bool) None 合并相邻的分隔条,开始和结尾的分隔条 不可见
setTearOffEnabled(bool) None 设置成可撕扯菜单
showTearOffMenu() None 以可撕扯菜单形式弹出菜单
showTearOffMenu(pos:QPoint) None 以可撕扯菜单形式在指定位置弹出菜单
hideTearOffMenu() None 隐藏可撕扯菜单
isTearOffEnabled() bool 获取是否是可撕扯菜单
isTearOffMenuVisible() None 获取可撕扯菜单是否可见
setTitle(title: str) None 设置菜单的标题
title() str 获取菜单的标题
setActiveAction(act: QAction) None 设置活跃的动作高亮显示
activeAction() QAction 获取活跃的动作
setDefaultAction(QAction) None 设置默认动作,以粗体字显示
defaultAction() QAction 获取默认的动作
setIcon(icon:Union[QIcon,QPixmap]) None 设置菜单的图标
setToolTipsVisible(visible: bool) None 设置提示信息是否可见
POPup(pos: QPoint, at: QAction=None) None 在指定位置显示菜单,并可使菜单中的动 作显示在指定位置
[static]exec() QAction 显示菜单,返回被触发的动作,如果没有则 返回 None
[static]exec(pos;QPoint,at: QAction=None) QAction 在指定位置显示菜单
[static]exec(Sequence[QAction], pos: QPoint, at: QAction=None, parent: QWidget=None) QAction 在指定位置显示菜单,当用pos无法确定 位置时,用父控件 parent辅助确定位置

菜单QMenu的信号

菜单QMenu的信号如表所示,最常用的是triggered(QAction)信号,其发送的是被激发的动作。

QMenu的信号及参数类型 说 明
aboutToShow() 菜单将要显示时发送信号
aboutToHide() 菜单将要隐藏时发送信号
hovered(QAction) 鼠标滑过菜单时发送信号
triggered(QAction) 动作被激发时发送信号

Qmenu 例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import os

os.chdir(os.path.dirname(__file__))


class MenuDemo(QMainWindow):
def __init__(self, parent=None):
super(MenuDemo, self).__init__(parent)

widget = QWidget(self)
self.setCentralWidget(widget)

topFiller = QWidget()
topFiller.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

self.infoLabel = QLabel("<i>Choose a menu option, or right-click to invoke a context menu</i>")
self.infoLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
self.infoLabel.setAlignment(Qt.AlignCenter)

bottomFiller = QWidget()
bottomFiller.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

layout = QVBoxLayout()
layout.setContentsMargins(5, 5, 5, 5)
layout.addWidget(topFiller)
layout.addWidget(self.infoLabel)
layout.addWidget(bottomFiller)
widget.setLayout(layout)

self.createActions()
self.createMenus()

message = "A context menu is available by right-clicking"
self.statusBar().showMessage(message)

self.setWindowTitle("Menus")
self.setMinimumSize(160, 160)
self.resize(480, 320)

def contextMenuEvent(self, event):
menu = QMenu(self)
menu.addAction(self.cutAct)
menu.addAction(self.copyAct)
menu.addAction(self.pasteAct)
menu.exec(event.globalPos())

def newFile(self):
self.infoLabel.setText("Invoked <b>File|New</b>")

def open(self):
self.infoLabel.setText("Invoked <b>File|Open</b>")

def save(self):
self.infoLabel.setText("Invoked <b>File|Save</b>")

def print(self):
self.infoLabel.setText("Invoked <b>File|Print</b>")

def undo(self):
self.infoLabel.setText("Invoked <b>Edit|Undo</b>")

def redo(self):
self.infoLabel.setText("Invoked <b>Edit|Redo</b>")

def cut(self):
self.infoLabel.setText("Invoked <b>Edit|Cut</b>")

def copy(self):
self.infoLabel.setText("Invoked <b>Edit|Copy</b>")

def paste(self):
self.infoLabel.setText("Invoked <b>Edit|Paste</b>")

def bold(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Bold</b>")

def italic(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Italic</b>")

def leftAlign(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Left Align</b>")

def rightAlign(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Right Align</b>")

def justify(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Justify</b>")

def center(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Center</b>")

def setLineSpacing(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Set Line Spacing</b>")

def setParagraphSpacing(self):
self.infoLabel.setText("Invoked <b>Edit|Format|Set Paragraph Spacing</b>")

def about(self):
self.infoLabel.setText("Invoked <b>Help|About</b>")
QMessageBox.about(self, "About Menu",
"The <b>Menu</b> example shows how to create menu-bar menus and context menus.")

def aboutQt(self):
self.infoLabel.setText("Invoked <b>Help|About Qt</b>")

def createActions(self):
self.newAct = QAction(QIcon("./images/new.png"), "&New")
self.newAct.setShortcuts(QKeySequence.New)
self.newAct.setStatusTip("Create a new file")
self.newAct.triggered.connect(self.newFile)

self.openAct = QAction(QIcon("./images/open.png"), "&Open...")
self.openAct.setShortcuts(QKeySequence.Open)
self.openAct.setStatusTip("Open an existing file")
self.openAct.triggered.connect(self.open)

self.saveAct = QAction(QIcon("./images/save.png"), "&Save")
self.saveAct.setShortcuts(QKeySequence.Save)
self.saveAct.setStatusTip("Save the document to disk")
self.saveAct.triggered.connect(self.save)

self.printAct = QAction("&Print...")
self.printAct.setShortcuts(QKeySequence.Print)
self.printAct.setStatusTip("Print the document")
self.printAct.triggered.connect(self.print)

self.exitAct = QAction("E&xit")
self.exitAct.setShortcuts(QKeySequence.Quit)
self.exitAct.setStatusTip("Exit the application")
self.exitAct.triggered.connect(self.close)

self.undoAct = QAction("&Undo")
self.undoAct.setShortcuts(QKeySequence.Undo)
self.undoAct.setStatusTip("Undo the last operation")
self.undoAct.triggered.connect(self.undo)

self.redoAct = QAction("&Redo")
self.redoAct.setShortcuts(QKeySequence.Redo)
self.redoAct.setStatusTip("Redo the last operation")
self.redoAct.triggered.connect(self.redo)

self.cutAct = QAction("Cu&t")
self.cutAct.setShortcuts(QKeySequence.Cut)
self.cutAct.setStatusTip("Cut the current selection's contents to the clipboard")
self.cutAct.triggered.connect(self.cut)

self.copyAct = QAction("&Copy")
self.copyAct.setShortcuts(QKeySequence.Copy)
self.copyAct.setStatusTip("Copy the current selection's contents to the clipboard")
self.copyAct.triggered.connect(self.copy)

self.pasteAct = QAction("&Paste")
self.pasteAct.setShortcuts(QKeySequence.Paste)
self.pasteAct.setStatusTip("Paste the clipboard's contents into the current selection")
self.pasteAct.triggered.connect(self.paste)

self.boldAct = QAction("&Bold")
self.boldAct.setCheckable(True)
self.boldAct.setShortcut(QKeySequence.Bold)
self.boldAct.setStatusTip("Make the text bold")
self.boldAct.triggered.connect(self.bold)

boldFont = self.boldAct.font()
boldFont.setBold(True)
self.boldAct.setFont(boldFont)

self.italicAct = QAction("&Italic")
self.italicAct.setCheckable(True)
self.italicAct.setShortcut(QKeySequence.Italic)
self.italicAct.setStatusTip("Make the text italic")
self.italicAct.triggered.connect(self.italic)

italicFont = self.italicAct.font()
italicFont.setItalic(True)
self.italicAct.setFont(italicFont)

self.setLineSpacingAct = QAction("Set &Line Spacing...")
self.setLineSpacingAct.setStatusTip("Change the gap between the lines of a paragraph")
self.setLineSpacingAct.triggered.connect(self.setLineSpacing)

self.setParagraphSpacingAct = QAction("Set &Paragraph Spacing...")
self.setParagraphSpacingAct.setStatusTip("Change the gap between paragraphs")
self.setParagraphSpacingAct.triggered.connect(self.setParagraphSpacing)

self.aboutAct = QAction("&About")
self.aboutAct.setStatusTip("Show the application's About box")
self.aboutAct.triggered.connect(self.about)

self.aboutQtAct = QAction("About &Qt")
self.aboutQtAct.setStatusTip("Show the Qt library's About box")
self.aboutQtAct.triggered.connect(QApplication.aboutQt)
self.aboutQtAct.triggered.connect(self.aboutQt)

self.leftAlignAct = QAction("&Left Align")
self.leftAlignAct.setCheckable(True)
self.leftAlignAct.setShortcut("Ctrl+L")
self.leftAlignAct.setStatusTip("Left align the selected text")
self.leftAlignAct.triggered.connect(self.leftAlign)

self.rightAlignAct = QAction("&Right Align")
self.rightAlignAct.setCheckable(True)
self.rightAlignAct.setShortcut("Ctrl+R")
self.rightAlignAct.setStatusTip("Right align the selected text")
self.rightAlignAct.triggered.connect(self.rightAlign)

self.justifyAct = QAction("&Justify")
self.justifyAct.setCheckable(True)
self.justifyAct.setShortcut("Ctrl+J")
self.justifyAct.setStatusTip("Justify the selected text")
self.justifyAct.triggered.connect(self.justify)

self.centerAct = QAction("&Center")
self.centerAct.setCheckable(True)
self.centerAct.setShortcut("Ctrl+E")
self.centerAct.setStatusTip("Center the selected text")
self.centerAct.triggered.connect(self.center)

alignmentGroup = QActionGroup(self)
alignmentGroup.addAction(self.leftAlignAct)
alignmentGroup.addAction(self.rightAlignAct)
alignmentGroup.addAction(self.justifyAct)
alignmentGroup.addAction(self.centerAct)
self.leftAlignAct.setChecked(True)

def createMenus(self):
fileMenu = self.menuBar().addMenu("&File")
fileMenu.addAction(self.newAct)

fileMenu.addAction(self.openAct)

fileMenu.addAction(self.saveAct)
fileMenu.addAction(self.printAct)

fileMenu.addSeparator()

fileMenu.addAction(self.exitAct)

editMenu = self.menuBar().addMenu("&Edit")
editMenu.addAction(self.undoAct)
editMenu.addAction(self.redoAct)
editMenu.addSeparator()
editMenu.addAction(self.cutAct)
editMenu.addAction(self.copyAct)
editMenu.addAction(self.pasteAct)
editMenu.addSeparator()

helpMenu = self.menuBar().addMenu("&Help")
helpMenu.addAction(self.aboutAct)
helpMenu.addAction(self.aboutQtAct)

formatMenu = editMenu.addMenu("&Format")
formatMenu.addAction(self.boldAct)
formatMenu.addAction(self.italicAct)
formatMenu.addSeparator().setText("Alignment")
formatMenu.addAction(self.leftAlignAct)
formatMenu.addAction(self.rightAlignAct)
formatMenu.addAction(self.justifyAct)
formatMenu.addAction(self.centerAct)
formatMenu.addSeparator()
formatMenu.addAction(self.setLineSpacingAct)
formatMenu.addAction(self.setParagraphSpacingAct)


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = MenuDemo()
demo.show()
sys.exit(app.exec())

动作QAction

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

动作 QAction 继承自QObject,位于 QtGui 模块中。用QAction创建动作对象的方法如下所示,其中 parent通常是窗口、工具栏、菜单栏或菜单;text是显示的文字,如果将动作放到菜单或工具栏上,text将成为菜单或工具栏中按钮的文字;icon 是图标,将成为菜单或工具栏中按钮的图标。

1
2
3
4
5
from PySide6.QtGui import QAction

QAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None
QAction(parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None
QAction(text: str, parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None

动作QAction的常用方法

动作 QAction 的常用方法如表所示,主要方法介绍如下。

  • 用setMenu(QMenu)方法把动作添加到菜单中,用菜单的addAction(QAction)方法也可以把动作添加到菜单中,作为菜单下拉列表中的一项。
  • 用setCheckable(bool)方法设置动作是否可以勾选,用setChecked(bool)方法设置是否处于勾选状态。
  • 对于互斥的一些动作,如同QRadioButton一样,需要将其放到一个组中,可以先用Broup=QActionGroup(self)创建一个对象,然后用group.addAction(QAction)方
  • 法把动作放到一个组中,并将 setExclusive(bool)设置成 True,这样就可以保证组内的动作是互斥的。
  • 用setShortcut(str)方法可以给动作设置快捷键,例如setShortcut(“Ctrl+A”);用setShortcut(QKeySequence)方法或 setShortcut(QKeySequence.StandardKey)方法也可设置快捷键,其中 QKeySequence定义按键顺序类,QKeySequence,StandardKey 是一些标准的快捷键。
  • 用setIconVisiblelnMenu(bool)方法设置菜单中是否显示动作的图标,而在工具档中不受影响;用setShortcutVisibleInContextMenu(bool)方法设置在右键快捷菜单中是否显示动作的快捷键(如果动作出现在快捷菜单中)。
  • 用setPriority(QAction.Priority)方法设置动作在界面上的优先级,参数是QAction.Priority 的枚举值,可取 QAction.LowPriority、QAction.NormalPriority或QAction.HighPriority,例如工具栏设置了 Qt.ToolButtonTextBesideIcon 模式,具有QAction.LowPriority 的动作将不显示文本。
QAction的方法及参数类型 返回值类型 说 明
setText(str) None 设置名称
text() str 获取名称
setIcon(QIcon) None 设置图标
icon() QIcon 获取图标
setCheckable(bool) None 设置是否可以勾选
isCheckable() bool 获取是否可以勾选
[slot]setChecked(bool) None 设置是否处于勾选状态
isChecked() bool 获取是否处于勾选状态
setIconVisibleInMenu(bool) None 设置在菜单中图标是否可见
isIconVisibleInMenu() bool 获取在菜单中图标是否可见
setShortcutVisibleInContextMenu(bool) None 设置动作的快捷键在右键快捷菜单中是否 显示
setFont(QFont) None 设置字体
font() QFont 获取字体
setMenu(QMenu) None 将动作添加到菜单中
menu() QMenu 获取动作所在的菜单
setShortcut(str) None 设置快捷键
setShortcut(QKeySequence) None 设置快捷键
setShortcut(QKeySequence.StandardKey) None 设置快捷键
[slot]setDisabled(bool) None 设置是否失效
[slot]setEnabled(bool) None 设置是否激活
isEnabled() Bool 获取是否处于激活状态
[slot]resetEnabled() None 恢复激活状态
setActionGroup(QActionGroup) None 设置动作所在的组
[slot]setVisible(bool) None 设置是否可见
isVisible() bool 获取是否可见
setSeparator(bool) None 将动作当作分割线来使用
setAutoRepeat(bool) None 设置长按快捷键时是否可以重复执行动 作,默认是True
autoRepeat() bool 获取是否可以重复执行动作
setData(var:Any) None 给动作设置任意类型的数据
data() Any 获取动作的数据
setPriority(QAction.Priority) None 设置动作的优先级
setToolTip(str) None 设置提示信息
setStatusTip(str) None 设置状态提示信息
setWhatsThis(str) None 设置按Shift+F1键时的提示信息
[slot]trigger() None 发送 triggered()或 triggered(bool)信号
[slot]hover() None 发送hovered()信号
[slot]toggle() None 发送 toggled(bool)信号

动作QAction的信号

如表所示,主要信号是toggled()和toggled(bool)信号

QMenu的信号及参数类型 说 明
hovered() 光标滑过动作时发送信号
triggered() 单击动作或按快捷键时发送信号
triggered(bool) 单击动作或按快捷键时发送信号
toggled(bool) 动作的切换状态发生改变时发送信号
changed() 当动作的属性(如文本、图标、可见性、优先级、快捷键、提示信息等)发生改 变时发送信号
checkableChanged(bool) 动作勾选状态发生改变时发送信号
enabledChanged(bool) 动作使能状态发生改变时发送信号
visibleChanged() 动作的可见性发生改变时发送信号

自定义动作QWidgetAction的实例

创建动作的方式是用QAction类来创建,这样创建的动作用户无法定制自己需要的功能或外观。若要自己定义动作,可继承QWidgetAction创建自定义动作类,QWidgetAction 继承自 QAction。

在自定义类中重写 createWidget(parent; QWidget)函数,其中 parent 是自定义动作所在的容器,如菜单或工具栏。在将自定义动作添加到菜单或工具栏中时,会自动调用createWidget(parent:QWidget)函数;当从菜单或工具栏中移除自定义的动作时,会调用deleteWidget(widget:QWidget)函数,重写该函数可以删除控件。

下面的代码是自定义动作的应用实例,该程序创建了继承自 QWidgetAction 的MyAction,在 MyAction类中重写了 createWidget()函数,在 createWidget()函数中创建了一个QPushButton 控件和一个 QSlider 控件,单击 QPushButton 控件,可以切换喇叭图像的显示。程序运行结果如图所示。

image-20230216015348466

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:38
# File_name: 03-自定义动作QWidgetAction的实例.py
import sys
from PySide6.QtWidgets import(QApplication, QMenuBar, QWidgetAction, QPushButton, QSlider, QHBoxLayout, QWidget)
from PySide6.QtGui import QPixmap
from PySide6.QtCore import Qt.QSize


class MyAction(QWidgetAction): # 创建继承自 oidgetAction 的类
def createWidget(self, parent): # 重写createWidget函数
self.widget = QWidget(parent)
self.setDefaultWidget(self.widget)
self.button = QPushButton()
self.button.setFlat(True)
self.button.setIcon(QPixmap("../../Resources/animal/m2.png"))
self.button.setIconSize(QSize(30, 30))
self.slide = QSlider(Qt.Orientation.Horizontal)
self.slide.setFixedWidth(200)

H = QHBoxLayout(self.widget)
H.addWidget(self.button)
H.addWidget(self.slide)

self.mute = False

self.button.clicked.connect(self.mute_requested) # 信号与槽函数的连接

def mute_requested(self): # 槽函数
self.mute = not self.mute
if self.mute:
self.button.setIcon(QPixmap("../../Resources/animal/m3.png"))
self.slide.setEnabled(False)
else:
self.button.setIcon(QPixmap("../../Resources/animal/m4.png"))
self.slide.setEnabled(True)


class Mywindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("WidgetAction 应用实例")
self.setupUi()

def setupUi(self):
menuBar = QMenuBar(self)
self.menuVolume = menuBar.addMenu("音量控制")
self.actVolume = MyAction(self.menuVolume) # 自定义动作的实例
self.menuVolume.addAction(self.actVolume) # 将自定义动作加人到菜单中


if __name__ == '__main__':
app = QApplication(sys.argv)
win = Mywindow()

win.show()
sys.exit(app.exec())

右键菜单(上下文菜单)

右键菜单有两种实现方式。

  • 重写父类(QWidget)的默认右键调用对象方法 contextMenuEvent(event: PySide6.QtGui.QContextMenuEvent)

  • 通过设置上下文菜单策略 setContextMenuPolicy(policy: PySide6.QtCore.Qt.ContextMenuPolicy)后自定义上下文菜单

    policy设置策略可设置:

    • Qt.ContextMenuPolicy.DefaultContextMenu # 默认上下文菜单,默认策略,右键调用对象方法contextMenuEvent()即第一种方法
    • Qt.ContextMenuPolicy.CustomContextMenu # 自定义上下文菜单,点击发送信号customContextMenuRequested(QPoint)在信号连接方法实现相关功能
    • Qt.ContextMenuPolicy.NoContextMenu # 无上下文菜单
    • Qt.ContextMenuPolicy.PreventContextMenu # 阻止上下文菜单
    • Qt.ContextMenuPolicy.ActionsContextMenu # 操作上下文菜单

重写contextMenuEvent法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:45
# File_name: 01- 重写contextMenuEvent法.py
import sys
import PySide6
from PySide6.QtCore import Qt
from PySide6.QtGui import QAction, QIcon
from PySide6.QtWidgets import *


class win_demo(QWidget):
def __init__(self):
app = QApplication(sys.argv) # 初始化界面
super().__init__()

self.resize(500, 500)
self.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

self.show() # 显示窗口以及其子控件
sys.exit(app.exec()) # 主循环和退出

@staticmethod
def get_menu(parent):
menu = QMenu(parent)
new_action = menu.addAction(QIcon(r"../../Resources/animal/m1.png"), "菜单动作")
new_action.triggered.connect(lambda: print("点击菜单动作"))

menu.addSection("")

submenu = QMenu("更多", menu)
sub_action = submenu.addAction(QIcon(r"../../Resources/animal/m1.png"), "子菜单动作")
sub_action.triggered.connect(lambda: print("点击子菜单动作"))
menu.addMenu(submenu)

return menu

def contextMenuEvent(self, event: PySide6.QtGui.QContextMenuEvent):
"""重写contextMenuEvent设置右键菜单"""
print("展示默认菜单")
default_menu = self.get_menu(self)

default_menu.exec(event.globalPos())


if __name__ == '__main__':
win_demo()

自定义上下文策略方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:47
# File_name: 02-自定义上下文策略方法.py
import sys
import PySide6
from PySide6.QtCore import Qt.QPoint
from PySide6.QtGui import QAction, QIcon
from PySide6.QtWidgets import *


class win_demo(QWidget):
def __init__(self):
app = QApplication(sys.argv) # 初始化界面
super().__init__()

self.resize(500, 500)
self.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

self.custom_menu()

self.show() # 显示窗口以及其子控件
sys.exit(app.exec()) # 主循环和退出

@staticmethod
def get_menu(parent):
menu = QMenu(parent)
new_action = menu.addAction(QIcon(r"../../Resources/animal/m1.png"), "菜单动作")
new_action.triggered.connect(lambda: print("点击菜单动作"))

menu.addSection("")

submenu = QMenu("更多", menu)
sub_action = submenu.addAction(QIcon(r"../../Resources/animal/m1.png"), "子菜单动作")
sub_action.triggered.connect(lambda: print("点击子菜单动作"))
menu.addMenu(submenu)

return menu

def show_menu(self, point: QPoint):
"""point默认是,相对位置即相对窗口的位置"""
print("展示自定义菜单策略")
default_menu = self.get_menu(self)
point = self.mapToGlobal(point) # 把局部位置映射到全局
default_menu.exec(point) # 按钮展示位置

def custom_menu(self):
"""修改上下文策略自定义菜单
Qt.ContextMenuPolicy.CustomContextMenu # 自定义上下文菜单
Qt.ContextMenuPolicy.DefaultContextMenu # 默认上下文菜单
Qt.ContextMenuPolicy.NoContextMenu # 无上下文菜单
Qt.ContextMenuPolicy.PreventContextMenu # 阻止上下文菜单
Qt.ContextMenuPolicy.ActionsContextMenu # 操作上下文菜单
"""

self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) # 自定义上下文菜单
self.customContextMenuRequested.connect(self.show_menu) # 自定义上下文菜单信号连接


if __name__ == '__main__':
win_demo()

工具栏和工具栏按钮

与菜单类似,工具栏也是一组命令的集合地。菜单上放置的动作也可放到工具栏上,实现工具栏和菜单的同步。

工具栏上除了放置动作外,还可以放置其他控件,例如 QLineEdit、QSpinBox,QComboBox、QToolButton 和 FontComboBox 等。在 QMainWindow 窗口中,工具栏还可以拖动和悬浮。

工具栏QToolBar 用于存放动作,动作在工具栏中一般呈现按钮状态。QToolBar继承自QWidget。用QToolBar类创建工具栏实例的方法如下,其中 title 是工具栏控件的标题名称,可通过 setWindowTitle(str)方法修改; parent 是工具栏所在的窗口。

1
2
3
4
from PySide6.QtWidgets import QToolBar

QToolBar(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QToolBar(title: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

工具栏QToolBar的常用方法

主要方介绍如下。

  • 用addAction(QAction)方法可以将已经存在的动作添加到工具栏申,用a66kcics(text: str)方法、addAction(icon:QIcon,text;str)方法可以同时创建和参加动作,并返回动作;用addSeparator()方法可以添加分隔条;用addWidget(Qwidges)方法可以把一个控件添加到工具栏上。
  • 用setOrientation(Qt.Orientation)方法可以设置工具栏的方向,其中QtOrientation 可以取 Qt.Horizontal(水平)或 Qt.Vertical(竖直)。
  • 用setToolButtonStyle(Qt.ToolButtonStyle)方法可以设置工具栏上按钮约风格Qt.ToolButtonStyle 可以取以下值
    • Qt.ToolButtonIconOnly(只显示图标)
    • Qr.ToolButtonTextOnly(只显示文字)
    • Qt.ToolButtonTextBesidelcon(文字在图标的旁边)
    • Qt.ToolButtonTextUnderIcon(文字在图标的下面)
    • Qt.ToolButtonFollowStyle(遵循风格设置)。
  • 在 QMainWindow 窗口中,可以用setMovable(bool)方法可以设置工具栏是否可以移动,用setFloatable(bool)方法设置工具栏是否可以浮动。
  • 在QMainWindow 窗口中,用setAllowedAreas(Qt.ToolBarArea)方法可以设置工具栏的停靠区域,其中Qt.ToolBarArea 参数指定可以停靠的区域,可以取值如下。如果工具栏是可移动的,则无论allowedAreas 设置何值都可以移动,但只有在进入toolBar 的allowedAreas 范围内时才会自动显示toolBar停靠区域范围,并在鼠标释放后自动在该范围内缩放,否则将保持最适合的大小浮动在窗口之上。
    • Qt.LeftToolBarArea(左侧)
    • Qt.RightToolBarArea(右侧)
    • Qt.TopToolBarArea(顶部,菜单栏下部)
    • Qt.BottomToolBarArea(底 部,状态栏上部)
    • Qt.AllToolBarAreas(所有区域都可以停靠)
    • Qt.NoToolBarArea(不可停靠)。
  • 用toggleViewAction()方法返回一个动作对象,通过单击该动作对象可以切换停靠窗口的可见状态,即该动作是一个对停靠控件窗口进行显示或关闭的开关,如果将该动作加到菜单上,对应菜单栏的文字即为停靠窗口的标题名称,这样就可以在菜单上单击对应菜单项进行停靠窗口的关闭和显示。

工具栏QToolBar的常用方法如表所示:

QToolBar的方法及参数类型 返回值的类型 说明
addAction(QAction) None 添加已定义的动作到工具栏上
addAction(text: str) QAction 创建并添加动作,返回新建立的动作
addAction(icon: QIcon,text; str) QAction 创建并添加动作,返回新建立的动作
addSeparator() QAction 添加分隔条
addWidget(QWidget) QAction 添加控件,返回与控件关联的动作
insertSeparator(before: QAction) QAction 在动作的前面插入分隔条
insertWidget(QAction,QWidget) QAction 在动作的前面插入控件
clear() None 清空工具栏中的动作和控件
widgetForAction(QAction) QWidget 获取与动作关联的控件
actionAt(QPoint) QAction 获取指定位置的动作
setionAt(x: int,y: int) QAction 获取指定位置的动作
ationGeometry(QAction) QRect 获取动作按钮的几何尺寸
setFlontable(booL) None 在QMinWindow中设置是否可以浮动
isFloatable() bool 获取是否可以浮动
isFloating() bool 获取是否正处于浮动状态
setMovable(bool) None 在QMainWindow中设置是否可以推动
isMcvable() bool 获取是否可以移动
[slot]setlconSize(QSize) None 设置图标允许的最大尺寸
iconSize() QSize 获取图标尺寸
setOrientation(Qt.Orientation) None 设置工具栏的方向
orientation() Qt.Orientation 获取工具栏的方向
[slot]setToolButtonStyle(Qt.ToolButtonStyle) None 设置工具栏上按钮的风格
toolButtonStyle() Qt.ToolButtonStyle 获取按钮风格
setAllowedAreas(Qt.ToolBarArea) None 设置QMainWindow中可停靠的区域
allowedAreas() Qt.ToolBarArea 获取可以停靠的区域
isAreaAllowed(Qt.ToolBarArea) bo0l 获取指定的区域是否可以停靠
toggleViewAction() QAction 切换停靠窗口的可见状态

工具栏QToolBar的信号和槽函数

工具栏的槽函数只有:

  • setToolButtonStyle(Qt.ToolButtonStyle)
  • setIconSize(QSize)。

信号见下表:

QToolBar的信号及参数类型 说明
actionTriggered(QAction) 动作被触发时发送信号
allowedAreasChanged(Qt.ToolBarArea) 允许的停靠区域发生改变时发送信号
iconSizeChanged(QSize) 按钮的尺寸发生改变时发送信号
movableChanged(bool) 可移动状态发生改变时发送信号
orientationChanged(Qt.Orientation) 工具栏的方向发生改变时发送信号
toolButtonStyleChanged(Qt.ToolButtonStyle) 工具栏的风格发生改变时发送信号
topLevelChanged(bool) 悬浮状态发生改变时发送信号
visibilityChanged(bool) 可见性发生改变时发送信号

工具按钮控件QToolButton

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

1
2
3
from PySide6.QtWidgets import QToolButton

QToolButton(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

工具按钮QToolButton的常用方法

工具按钮QToolButton的主要方法介绍如下。

  • 用工具栏的 addWidget()方法可以将工具按钮加人到工具栏中。
    • setMenu(QMenu)方法可以为工具按钮设置一个菜单。
    • setPopupMode(QToolButton.ToolButtonPopupMode)方法可以设置菜单的弹出方式。其中参数 QToolButton.ToolButtonPopupMode 可取值如下:
      • QToolButton.DelayedPopup,表示用鼠标按下按钮并保持一会儿后弹出菜单
      • QToolButton.MenuButtonPopup,表示在工具按钮的右下角上出现一个向下的黑三角,单击这个黑三角,弹出菜单
      • QToolButton.InstantPopup,表示立即弹出菜单
    • showMenu()方法可以让菜单弹出。
  • 用setAutoRaise(bool)方法可以设置工具按钮的自动弹起特征,当光标放到按钮上面时会有三维立体感。
  • 按钮的外观和尺寸可通过 setToolButtonStyle(Qt.ToolButtonStyle)方法和setIconSize(QSize)方法来设置,其中参数Qt.ToolButtonStyle 可以取值 Qt.ToolButtonIconOnlyQt.ToolButtonTextOnlyQt.ToolButtonTextBesidelconQt.ToolButtonTextUnderIconQt.ToolButtonFollowStyle。在 QMainWindow的QToolBar 中使用工具按钮时,按钮会自动调节尺寸来适应QMainWindow 的设置。
  • 用setArrowType(Qt.ArrowType)方法可以设置工具按钮上的箭头形状,其中Qt.ArrowType 可以取 Qt.NoArrow, Qt.UpArrow, Qt.DownArrowQt.LeftArrowQt.RightArrow

工具按钮QToolButton的常用方法如表所示:

QToolButton的方法及参数类型 说 明
setMenu(QMenu) 设置菜单
[slot]showMenu() 弹出菜单
setText(str) 设置文本
setIcon(QIcon) 设置图标
setPopupMode(QToolButton.ToolButtonPopupMode 设置菜单的弹出 方式
[slot]setDefaultAction(QAction) 设置默认动作
setArrowType(Qt.ArrowIype) 设置箭头形状
[slot]setToolButtonStyle(Qt.ToolButtonStyle) 设置按钮外观
setAutoExclusive(bool) 设置是否互斥
setShortcut(str) 设置快捷键
[slot]setlconSize(QSize) 设置图标尺寸
setCheckable(bool) 设置是否可勾选
[slot]setChecked(bool) 设置勾选状态
setAutoRaise(bool) 设置自动弹起
showMenu() 弹出菜单
[sIot]click() 鼠标单击事件

工具按钮QToolButton的信号

QToolButton的信号 说 明
triggered(QAction) 激发动作时发送信号
clicked() 单击时发送信号
pressed() 按钮被按下时发送信号
released() 按钮被按下又弹起时发送信号

实例

下面的程序是在上节程序的基础之上添加了工具栏,在工具栏上添加动作、字体下拉列表、字体尺寸下拉列表和工具按钮,用下拉列表控制字体和字体尺寸。程序运行界面如图所示。程序只能打开 UTF-8 格式的文本文件

image-20230216180425436

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:48
# File_name: 工具按钮QToolButton的信号.py
import sys, os
from PySide6.QtCore import Qt
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import(QApplication, QMenuBar, QPlainTextEdit, QComboBox, QFontComboBox, QToolBar, QVBoxLayout, QWidget, QFileDialog, QToolButton)


class MyWindow(QWidget):
def __init__(self, paprent=None):
super().__init__()
self.setWindowTitle("OMenu and OToolBar")
self.setupUi()

def setupUi(self):
menuBar = QMenuBar() # 创建菜单栏
toolBar = QToolBar() # 创建工具栏
toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) # 设置工具栏上按钮的样式

self.plainText = QPlainTextEdit() # 创建文本编辑器
vlayout = QVBoxLayout(self) # 创建竖直布局
vlayout.addWidget(menuBar)
vlayout.addWidget(toolBar)
vlayout.addWidget(self.plainText) # 工具栏上添加动作

act_new = toolBar.addAction(QIcon("../../../Resources/animal/m4.png"), "新建(&N)") # 添加动作
act_open = toolBar.addAction(QIcon("../../../Resources/animal/m5.png"), "打开(&O)") # 添加动作
act_save = toolBar.addAction(QIcon("../../../Resources/animal/m6.png"), "保存(&S)") # 添加动作

toolBar.addSeparator() # 分割线

act_copy = toolBar.addAction(QIcon("../../../Resources/animal/m7.png"), "复制(&C)") # 添加动作
act_paste = toolBar.addAction(QIcon("../../../Resources/animal/m8.png"), "粘贴(&V)") # 添加动作
act_cut = toolBar.addAction(QIcon("../../../Resources/animal/m9"), "剪贴(&X)") # 添加动作

toolBar.addSeparator() # 分割线

self.fontComboBox = QFontComboBox(self) # 字体下拉列表
self.fontComboBox.setFixedWidth(100)
toolBar.addWidget(self.fontComboBox) # 工具栏上添加字体下拉列表
self.plainText.setFont(self.fontComboBox.currentFont()) # 设置字体
self.fontComboBox.currentFontChanged.connect(self.plainText.setFont) # 信号与槽连接

self.comboBox = QComboBox(self) # 下拉列表
for i in range(5, 50):
self.comboBox.addItem(str(i))

self.comboBox.setCurrentText("15") # 工具栏上添加下拉列表
toolBar.addWidget(self.comboBox)
self.comboBox.currentTextChanged.connect(self.comboBox_text_changed) # 信号与槽连接
menu_file = menuBar.addMenu("文件(&F)") # 菜单栏中添加菜单
menu_file.addAction(act_new) # 菜单栏中添加动作
menu_file.addAction(act_open) # 菜单栏中添加动作
menu_file.addAction(act_save) # 菜单栏中添加动作
menu_file.addSeparator()

act_exit = menu_file.addAction(QIcon("../../../Resources/animal/m10.png"), "退出(&E)") # 添加动作

menu_edit = menuBar.addMenu("编辑(&E)")
menu_edit.addAction(act_copy)
menu_edit.addAction(act_paste)
menu_edit.addAction(act_cut)

act_new.triggered.connect(self.act_new_triggered)
act_open.triggered.connect(self.act_open_triggered)
act_save.triggered.connect(self.act_save_triggered)
act_copy.triggered.connect(self.plainText.copy)

act_cut.triggered.connect(self.plainText.cut)
act_paste.triggered.connect(self.plainText.paste)
act_exit.triggered.connect(self.close)

toolButton = QToolButton(self) # 工具按钮
toolButton.move(200, 0)
toolButton.setMenu(menu_file) # 为工具按钮添加菜单
toolButton.setArrowType(Qt.DownArrow)
toolButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) # 设置工具按钮样式

def comboBox_text_changed(self, text): # 下拉列表的槽函数
font = self.plainText.font()
font.setPointSize(int(text))
self.plainText.setFont(font)

def act_new_triggered(self):
self.plainText.clear()

def act_open_triggered(self):
filename, filter = QFileDialog.getOpenFileName(self, "打开", ".", "文本文件(*.txt)")
if os.path.exists(filename):
self.plainText.clear()
fp = open(filename, mode="r", encoding="utf-8")
string = fp.readlines()
for i in string:
i = i.strip()
self.plainText.appendPlainText(i)
fp.close()
self.comboBox_text.changed(self.comboBox.currentText())

def act_save_triggered(self):
filename, filter = QFileDialog.getSaveFileName(self, "打开文件", ".", "文本文件(*.txt)")
string = self.plainText.toPlainText()
if filename != "":
if os.path.exists(filename):
fp = open(filename, mode="r", encoding="utf-8")
fp.writelines(string)
fp.close()
else:
fp = open(filename, "w", encoding="UTE-8")
fp.writelines(string)
fp.close()


if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec())

状态栏QStatusBar

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

状态栏 QStatusBar 继承自 QWidget。用QStatusBar 类创建状态栏实例的方法如下,其中parent是状态的父窗口,一般是独立窗口。

1
2
3
from PySide6.QtWidgets import QStatusBar

QStatusBar(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

状态栏QStatusBar的常用方法

状态栏QStatusBar的主要方法介绍如下。

  • 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)方法可以把其他控件(如 QLabel)添加到状态栏的右侧,用于显示一些永久的信息,例如软件版本号、公司名称、键盘大小写状态等,这些信息不会被状态栏的信息遮挡住,其中参数stretch用于指定控件的相对缩放系数,index是控件的索引号。
  • addtWidget(widget:QWidget,stretch: int=0)方法或insertWidget(index: int,QWidget,stretch:int=0)方法可以把其他控件添加到状态栏的左侧,用于显示正常的信息,这些信息会被状态栏的信息遮挡住。
  • removeWidget(QWidget)方法可以把控件从状态栏上移除,但控件并没有被真状态栏真正删除,可以用addWidget()方法和show()方法将控件重新添加到状态栏中。
  • setSizeGripEnabled(bool)方法可以设置状态栏的右侧是否有一个小三角形标识。

QStatusBar的常用方法如表所示,主要方法介绍如下:

QStatusBar的方法及参数类型 返回值的类型 说 明
[slod]showMessage(rext: str, timeout:int=0) None 显示信息,timeout 是显示时间
currentMessage() Str 获取当前显示的信息
[slot]clearMessage() None 删除信息
aadPermanentWidget(Qwidget,stretch: int=0) None 在状态栏的右边添加永久控件
addWidget(widget: QWidget,stretch: int=0) None 在状态栏的左边添加控件
insertPermanentWidget(index: int, widget: QWidget,stretch:int=0) int 根据索引值,在右边插入永久控件
insertWidget(index: int,QWidget,stretch: int=0) int 根据索引值,在左边插入控件
removeWidget(widget: QWidget) None 从状态栏中移除控件
setSizeGripEnabled(bool) None 设置在右下角是否有三角形
isSizeGripEnabled() bool 获取右下角是否有三角形
hideOrShow() None 确保右边的控件可见

状态栏QStatusBar的信号

状态栏QStatusBar 只有1个信号 messageChanged(text: str),当显示的信息发生改变时发送该信号。

QStatusBar 例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 22:59
# File_name: QStatusBar 例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import time
import os

os.chdir(os.path.dirname(__file__))


class StatusDemo(QMainWindow):
def __init__(self, parent=None):
super(StatusDemo, self).__init__(parent)
self.resize(300, 200)

bar = self.menuBar()
file = bar.addMenu("File")
new = QAction(QIcon("./images/new.png"), "new", self)
new.setStatusTip('select menu: new')
open_ = QAction(QIcon("./images/open.png"), "open", self)
open_.setStatusTip('select menu: open')
save = QAction(QIcon("./images/save.png"), "save", self)
save.setStatusTip('select menu: save')
file.addActions([new, open_, save])
file.triggered[QAction].connect(self.processTrigger)
self.init_statusBar()

self.timer = QTimer(self)
self.timer.timeout.connect(lambda: self.label.setText(time.strftime("%Y-%m-%d %a %H:%M:%S")))
self.timer.start(1000)

def init_statusBar(self):
self.status_bar = QStatusBar()
self.status_bar2 = QStatusBar()
self.status_bar2.setMinimumWidth(150)
self.label = QLabel('显示永久信息:时间')
self.button = QPushButton('清除时间')

self.status_bar.addWidget(self.status_bar2)
self.status_bar.addWidget(self.label)
self.status_bar.addWidget(self.button)

self.setWindowTitle("QStatusBar 例子")
self.setStatusBar(self.status_bar)
self.button.clicked.connect(lambda: self.status_bar.removeWidget(self.label))

def processTrigger(self, q):
self.status_bar2.showMessage('点击了menu: ' + q.text(), 5000)


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = StatusDemo()
demo.show()
sys.exit(app.exec())

容器和容器控件

容器类控件不能输人输出数据,通常作为常用控件的载体,将常用控件”放置”到其内部。

容器控件对放到其内部的控件进行管理,并成为控件的父控件。

常用的容器控件如表所示:

容器控件类 中文名
QGroupBox 分组框控件
QFrame 框架控件
QScrollArea 滚动区控件
QTabWidget 切换卡控件
QStackedWidget 控件栈控件
QToolBox 工具箱控件
QWidget 容器窗口控件
QMdiArea 多文档区
QDockWidget 停靠窗口控件
QAxWidget 插件窗口控件

框架控件(帧窗口)QFrame

框架控件 QFrame作为容器可以在其内部放置各种可视控件。

QFrame没有属于自己特有的信号和槽函数,一般不接受用户的输人,它只能提供一个外形.可以设置外形的样式线宽等。

QFrame作为父类被其他一些控件所继承,这些控件如QAbstractScrollArea、QLabel、QLCDNumber,QSplitter、QStackedWidget 和 QToolBox 等

框架控件QFrame的常用方法

框架控件QFrame是从QWidget类继承而来的用QFrame创建实例对象的常用方法如下所示,其中parent是窗口或者容器类控件,f用于设置控件的窗口类型可参考窗口flags的内容,默认值是QtWidget。

1
2
3
4
from PySide6.QtWidgets import QFrame

QFrame(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None,
f: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags))
QFrame的方法及参数类型 返回值的类型 说明
setFrameShadow(QFrame.Shadow) None 设置QFrame窗口的阴影形式
frameShadow() QFrame.Shadow 获取窗口的阴影形式
setFrameShape(QFrame.Shape) None 设置QFrame窗口的边框形状
frameShape() QFrame, Shape 获取窗口的边框形状
setFrameStyle(int) None 设置边框的样式
frameStyle() int 获取边框的样式
setLineWidth(int) None 设置边框线的宽度
lineWidth() int 获取边框的宽度
setMidLineWidth(int) None 设置边框线的中间线的宽度
midLineWidth() int 获取边框线的中间线的宽度
frameWidth() int 获取边框的宽度
setFrameRect(QRect) None 设置边框线所在的范围
frameRect() QRect 获取边框线所在的范围
drawFrame(QPainter) None 绘制边框线
setLayout(QLayout) None 设置框架中的布局
setGeometry(QRect) None 设置QFrame控件左上角的位置和长 度、宽度
setGeometry(x:int,y: int,w; int,h; int)
resize(QSize)、resize(w:int,h;int) None 设置QFrame控件的长度和宽度
  • 框架主要由边框线构成,边框线由外线、内线和中间线构成。

    • 外线和内线的宽度可以通过setLineWidth(int)方法设置,
    • 中间线宽度可以通过 setMidLineWidth(int)方法设置,
    • 外线和内线的宽度通过 lineWidth()方法获取,
    • 中间线的宽度通过midLineWidth()方法获取,
    • 外线内线和中间线宽度通过 frameWidth()方法获取
  • 通过给边框的内线、外线设置不同的颜色,可以让外框有凸起和凹陷的立体感觉

    • 用setFrameShadow(QFrameShadow)方法设置边框线的立体感觉,参数QFrameShadow可以取:
      • QFrame.Plain(平面)
      • QFrame.Raised(凸起)
      • QFrame.Sunken(凹陷)
  • 外框线的形状

    • 通过 setFrameShape(QFrameShape)方法设置,其中参数QFrame.Shape是枚举类型可取值如表所示。

      QFrame.Shape的取值 说明lacm
      QFrame.NoFrame 0 无边框,默认值
      QFrame.Box 1 矩形框,边框线内部不填充
      QFrame.Panel 2 面板,边框线内部填充
      QFrame.WinPanel 3 Windows 2000风格的面板,边框线的宽度是2像素
      QFrame.HLine 4 边框线只在中间有一条水平线(用作分隔线)
      QFrame.VLine 5 边框线只在中间有一条竖直线(用作分隔线)
      QFrame.StyledPanel 6 依据当前GUI类型,画一个矩形面板
    • QFrame的frameStyle属性由frameShadow属性和frameShape属性决定,因此设置frameShadow和frameShape的值,就不需要再设置 frameStyle 的值了。将以上参数进行组合可以得到不同感觉的边框线。

QFreme样式图:

帧.png

  • 在界面上,经常在不同类型的控件之间划分一条横线或竖线。横线和竖线可以用QFrame来创建,方法是设置setFrameShape(QFrameHLine)或 setFrameShape(QFrameVLine)并结合 setGeometry()或resize()方法确定线的位置和尺寸

框架控件QFrame的应用实例

下面的程序将两组互斥的QRadioButton 分别放到两个 QFrame中,这两个QFrame又放到QGroupBox控件中。由于 QFrame 的边框线不可见,所以从外观上看,所有互斥的QRadioButton都放到了 QGroupBox控件中,但是选择时两组是可以分别选择的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import sys
from PySide6.QtWidgets import QApplication, QWidget, QGroupBox, QFrame, QRadioButton, QHBoxLayout, QRadioButton, QHBoxLayout


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("QFrame 的应用")
self.resize(300, 100)
self.setupUi()

def setupUi(self): # 创建界面上的控件
self.r_1=QRadioButton("男")
self.r_2=QRadioButton("女")
self.r_3=QRadioButton("党员")
self.r_4=QRadioButton("团员")
self.r_5=QRadioButton("群众")
self.frame_1=QFrame()
self.frame_2=QFrame()

self.h_layout_1=QHBoxLayout(self.frame_1)
self.h_layout_1.addWidget(self.r_1)
self.h_layout_1.addWidget(self.r_2)

self.h_layout_2=QHBoxLayout(self.frame_2)
self.h_layout_2.addWidget(self.r_3)
self.h_layout_2.addWidget(self.r_4)
self.h_layout_2.addWidget(self.r_5)

self.groupBox=QGroupBox("选择基本信息", self)
self.h_layout_3=QHBoxLayout(self.groupBox)
self.h_layout_3.addWidget(self.frame_1)
self.h_layout_3.addWidget(self.frame_2)

self.r_1.setChecked(True)
self.r_3.setChecked(True)


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWidget()

win.show()
sys.exit(app.exec())

滚动区域容器QScollArea

滚动区控件 QScrollArea 作为其他控件的容器当其内部的控件超过滚动区的尺寸时滚动区自动提供水平或竖直滚动条,通过拖动滚动条的位置,用户可以看到内部所有控件的内容。例如在滚动区中放置 QLabel控件,用QLabel控件显示图片,当QLabel显示的图片超过 QScrollArea 的范围时,通过拖动滚动条可以看到被挡住的图片。

用QScrollArea类创建实例对象的方法如下所示,其中 parent 是窗口或者容器类控件,它是从抽象类QAbstractScrollArea 继承而来的。

1
2
3
from PySide6.QtWidgets import QScrollArea

QScrollArea(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

滚动区控件QScrollArea 的常用方法

滚动区控件QScrollArea 的常用方法

主要方法介绍如下:

  • 必须用setWidget(QWidget)方法将某个控件设置成可滚动显示的控件,只有当该控件移出了滚动区控件的窗口,才能用滚动条移动控件。
  • 用setAlignment(Qt.Alignment)方法设置QScrollArea 内部控件的对齐位置,其中参数 Qt.Alignment 可以取:
    • Qt.AlignCenter
    • Qt.AlignLeft
    • Qt.AlignHCenter
    • Qt.AlignRight
    • Qt.AlignTop
    • Qt.AlignVCenter
    • Qt.AlignBottom。
  • 用setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy)方法和 setVerticalScrollBarPolicy(QtScrollBarPolicy)方法设置竖直滚动条和水平滚动条出现的策略,其中参数 QScrollBarPolicy可以取:
    • QtScrollBarAsNeeded(根据情况自动决定何时出现滚动条)
    • Qt.ScrollBarAlwaysOf[(从不出现滚动条)
    • Qt.ScrollBarAlwaysOn(一直出现滚动条)。
  • ensureVisible(x,y[,xmargin=50[,ymargin=50]])方法和ensureWidgetVisible(childWidget[,xmargin=50[;ymargin=50]])方法可以确保某个点或某个控件是可见的,如果无法使其可见,将会使距其最近的有效点可见。当点或控件可见时,点或控件距离边界的位置是xmargin和ymargin。

滚动区控件 QScrollArea 的常用方法如表所示,

QScrollArea的方法及参数类型 说明
setWidget(QWidget) 将某个控件设置成可滚动显示的控件
widget() 获取可滚动显示的控件
setWidgetResizable(bool) 设置内部控件是否可调节尺寸,尽量不显示滚动条
widgetResizable() 获取内部控件是否可以调节尺寸
setAlignment(Qt.Alignment) 设置内部控件在滚动区的对齐位置
aligament() 返回内部控件在滚动区的对齐位置
ensureVisible(x:int,y:int,xmargin:int=50, ymargin:int=50) 自动移动滚动条的位置,确保(x,y)像素点是可见 的。可见时,点到边框的距离是xmargin 和 ymargin,默认距离是50个像素
ensureWidgetVisible(childWidget: QWidget, xmargin: int=50,ymargin: int=50) 自动移动滚动条的位置,确保控件childWidget是可 见的
setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy) 设置竖直滚动条的显示策略
setVerticalScrollBarPolicy(Qt.ScrollBarPolicy) 设置水平滚动条的显示策略

滚动区控件QScrollArea的应用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:52
# File_name: 04-滚动区控件QScrollArea的应用实例.py
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QScrollArea
from PySide6.QtGui import QPixmap

from PySide6.QtCore import Qt


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi()

def setupUi(self): # 建立界面上的控件
self.resize(300, 300)
self.scroArea = QScrollArea(self)

label = QLabel(self.scroArea)
pix = QPixmap("../../Resources/animal/m1.png")
pix = pix.scaled(666, 666, Qt.AspectRatioMode.IgnoreAspectRatio) # 调整图像大小

label.resize(pix.width(), pix.height()) # 设置标签的宽度和高度
label.setPixmap(pix)

self.scroArea.ensureVisible(150, 100) # 设置可滚动显示的控件
self.scroArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) # 设置对齐方式
self.scroArea.setWidget(label) # 设置可见点
self.scroArea.setAlignment(Qt.AlignCenter) # 设置显示策略
self.scroArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # 设置显示策略
self.h = QHBoxLayout(self) # 布局
self.h.addWidget(self.scroArea)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

多文档区QMdiArea

用QMainWindow 建立的主界面,通常会同时建立或打开多个相互独立的文档,这些文档共享主界面的菜单、工具栏和停靠控件,多文档中只有一个文档是活跃的文档,菜单和工具栏的操作只针对当前活跃的文档。

主界面要实现多文档操作需要用QMdiArea控件,通常把QMdiArea 定义成中心控件。

可以在QMdiArea 控件中添加多个子窗口QMdiSubWindow,通常每个子窗口都有相同的控件,当然控件也可以不相同,这时代码会比较复杂。

QMdiArea 是从抽象类QAbastractScrollArea 继承而来的

1
2
3
from PySide6.QtWidgets import QMdiArea

QMdiArea(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

多文档区QMdiArea的常用方法

多文档区QMdiArea常用方法方法介绍如下:

  • 用QMdiArea 的addSubWindow(QWidget,Qt.WindowFlags)方法可以往多文档区中添加子窗口,并返回子窗口,参数QWidget 可以是子窗口,也可以是其他控件,如果是其他控件,则先创建其他控件,然后在子窗口上添加该控件;

    • QMdiArea中的子窗口类型是QMdiSubWindow的实例,但可以使用addSubWindow()方法将任何QWidget或其派生类的实例添加到MDI区域作为子窗口,此时QMdiArea会自动创建子窗口的QMdiSubWindow实例,并作为addSubWindow()方法的结果返回。
  • 用removeSubWindow(QWidget)方法可以从多文档中移除子窗口或子窗口上的控件,使用该方法子窗口或控件并没有真正删除,其父窗口变成 None。如果移除的是控件,则控件所在的子窗口并没有被移除。

  • 用QMdiArea 的setViewMode(QMdiArea.ViewMode)方法可以设置多文档区中子窗口的显示模式,其中参数 QMdiArea.ViewMode 可 以取:

    • QMdiArea.SubWindowView(子窗口视图)
    • QMdiArea.TabbedView(Tab标签视图),这两种视图的样式如图所示。
  • 在子窗口视图模式下,可以随意缩放和拖动窗口,还可以设置子窗口的排列形式。用cascadeSubWindows()方法可以设置子窗口为层叠排列显示,用tileSubWindows()方法可以设置子窗口为平铺排列显示,这两种排列形式如图所示。

  • 用QMdiArea 的currentSubWindow()方法可以获得当前子窗口,如果没有子窗口或活跃窗口,则返回值是 None;用setActiveSubWindow(QMdiSubWindow)方法可以使某个子窗口变成活跃窗口。

  • 如果用户在界面上单击某个子窗口,则单击的子窗口变成活跃窗口。如果用代码使某个窗口活跃,则要考虑子窗口的顺序。

    • setActivationOrder(QMdiArea.WindowOrder)方法可以设置子窗口的活跃顺序的规则,其中参数QMdiArea.WindowOrder 可以取:
      • QMdiArea.CreationOrder(创建 顺序)
      • QMdiArea.StackingOrder(堆放顺序)
      • QMdiArea.ActivationHistoryOrder(历史活跃顺序);
    • 用activateNextSubWindow()方法和activatePreviousSubWindow()方法可以按照活跃顺序分别激活下一个子窗口和前一个子窗口
    • subWindowList(QMdiArea.WindowOrder)方法可以按照指定的顺序获取子窗口的列表List[QMdiSubWindowJ。
  • 用QMdiArea 的setOption(QMdiArea.AreaOption,bool)方法可以设置子窗口在活跃时的状态,其中参数QMdiArea.AreaOption 只有一个取值 QMdiArea.DontMaximizeSubWindowOnActivation,在子窗口变成活跃窗口时不进行最大化显示。

  • 子窗口数量

    • QMdiArea中的子窗口数量无法直接通过QMdiArea方法获取,必须先通过方法subWindowList()返回所有子窗口的列表,再通过Python的len函数获取子窗口的数量。

多文档区QMdiArea常用方法:

QMdiArea的方法及参数类型 返回值的类型 说明
addSubWindow(QWidget.Qt.WindowFlags) QMdiSubWindow 用控件创建一个子窗口,并返回子窗口
removeSubWindow(QWidget) None 移除控件所在的子窗口
setViewMode(QMdiArea.ViewMode) None 设置子窗口在QMdiArea中的显示样式
viewMode() QMdiArea.ViewMode 获取子窗口的显示样式
[slot]cascadeSubWindows() None 层叠显示子窗口
[slot]tileSubWindows() None 平铺显示子窗口
[slot]closeActiveSubWindow() None 关闭活跃的子窗口
[slot]closeAllSubWindows() None 关闭所有的子窗口
currentSubWindow() QMdiSubWindow 获取当前的子窗口
scrollContentsBy(dx: int,dy:int) None 移动子窗口中的控件
setActivationOrder(QMdiArea.WindowOrder) None 设置子窗口的活跃顺序
activationOrder() QMdiArea.WindowOrder 获取活跃顺序
subWindowList(QMdiArea.WindowOrder=QMdiArea. List[QMdiSubWindowJ 按照指定的顺序获取子窗口列表
CreationOrder)[slot]activateNextSubWindow() None 激活下一个子窗口
[slot]activatePreviousSubWindow() None 激活前一个子窗口
[slot]setActiveSubWindow None 设置活跃的子窗口
(QMdiSubWindow) activeSubWindow() QMdiSubWindow 获取活跃的子窗口
setBackground(Union[QBrush, QColor,Qt.GlobalColor,QGradient]) None 设置背景颜色,默认是灰色
background() QBrush 获取背景色画刷
setOption(QMdiArea.AreaOption, bool) None 设置子窗口的模式
testOption(QMdiArea.AreaOption) bool 获取是否设置了选项
setTabPosition(QTabWidget.TabPosition) None 设置Tab 标签的位置
setTabShape(QTabWidget.TabShape) None 设置Tab标签的形状
setTabsClosable(bool) None Tab 模式时设置Tab 标签是否有关闭按钮
setTabsMovable(bool) None Tab 模式时设置Tab 标签是否可移动
setDocumentMode(bool) None Tab 模式时设置Tab 标签是否文档模式
documentMode() bool Tab 模式时获取Tab 标签是否文档模式
tabPosition() QTabWidget.TabPosition 获取 Tab标签的位置
tabShape() QTabWidget.TabShape 获取 Tab标签的形状
tabsClosable() bool 获取 Tab标签上是否有关闭按钮
tabsMovable() bool 获取 Tab标签是否可移动

多文档区 QMdiArea 的信号

多文档区QMdiArea只有一个信号 subWindowActivated(QMdiSubWindow),当子窗口活跃时发送该信号。

实例

image-20230319020111077

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 22:59
# File_name: demo.py

import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class MainWindow(QMainWindow):
count = 0

def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
# 添加菜单栏
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
file.addAction("cascade")
file.addAction("Tiled")
file.triggered[QAction].connect(self.windowaction)
self.setWindowTitle("MDI 示例")

def windowaction(self, q):
# 通过点击不同的按钮实现不同布局的显示方式
if q.text() == "New":
MainWindow.count = MainWindow.count + 1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow" + str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()
if q.text() == "cascade":
self.mdi.cascadeSubWindows()
if q.text() == "Tiled":
self.mdi.tileSubWindows()


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = MainWindow()
demo.show()
sys.exit(app.exec())

分割容器QSplitter

image-20230212204141285

分割器控件QSplitter 中可以加人多个控件,在两个相邻的控件之间自动用一个分隔条把这两个控件分开,可以拖拽分割条改变它的位置。

分割器可以分为水平分割和竖直分割两种,分割器中还可以加入其他分割器,这样形成多级分割。只能往分割器中加控件,不能直接加布局。分割器的外观如图所示。

在往窗体或布局中添加分割器控件时,应以控件形式而不能以布局形式加入,因此应该将分割器当成控件而不是布局。

QSplitter 继承自QFrame。用QSplitter 类创建实例对象的方法如下所示其中 parent是窗口或容器控件;Qt.Orientation 是分方向,可以取 Qt.Vertical或 Qt.Horizontal。

1
2
3
4
from PySide6.QtWidgets import QSplitter

QSplitter(arg__1: PySide6.QtCore.Qt.Orientation, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QSplitter(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

分割器控件QSplitter 的常用方法

分割器控件 QSplitter 的常用方法如表所示,主要方法介绍如下。

  • 控件添加

    • 用addWidget(QWidget)方法在末尾添加控件;

    • 用insertWidget(index:int, QWidget)方法插人控件,不能添加布局;

    • 用replaceWidget(index:int,QWidget)方法替换指定索引的控件;

    • 用widget(index:int)方法获取索引值是index的控件;

    • 用indexOf(QWidget)方法获取指定控件的索引值

    • 用count()方法获取控件的数量。

  • 分割方向

    • 用setOrientation(Qt.Orientation)方法设置分制方向;
    • 用setOpaqueResize(bool)方法设置移动分割条时,是否是动态显示的,动态显示时控件随鼠标的移动进行缩放,非动态显示时释放鼠标后才缩放控件。
  • 用setChildrenCollapsible(bool)和 setCollapsible(int,bool)方法设置控件是否是可以折叠的,在折叠情况下,两个分隔条可以合并在一起。

QSplitter的方法及参数类型 说 明
addWidget(QWidget) 在末尾添加控件
insertWidget(index:int,QWidget) 在指定索引位置插人控件
widget(index: int) 获取指定索引的控件
replaceWidget(index:int,QWidget) 替换指定索引的控件
count() 获取控件的数量
indexOf(QWidget) 获取控件的索引值
setOrientation(Qt.Orientation) 设置分割方向
orientation() 获取分割方向
setOpaqueResize(bool) 设置拖动分隔条时,是否是动态的
setStretchFactor(index:int,stretch) 设置分割区在窗口缩放时的缩放系数
setHandJeWidth(int) 设置分隔条的宽度
setChildrenCollapsible(bool) 设置内部控件是否可以折叠,默认为True
setCollapsible(index:int, bool) 设置索引号为int的控件是否可以折叠
setSizes(list: Sequence[int]) 使用可迭代序列(列表、元组等)设置内部控件的宽度(水平分 割)或高度(竖直分割)
sizes() 获取分割器中控件的宽度(水平分割)列表或高度(竖直分割) 列表
setRubberBand(position:int) 设置橡皮筋到指定位置,如果分割条不是动态的,则会看到橡 皮筋
moveSplitter(pos:int,index; int) 将索引为index的分割线移到pos处
getRange(index;int) 获取索引为int的分割线的可调节范围,返回元组
saveState() 保存状态到QByteArray
restoreState(QByteArray) 恢复保存的状态

分割器控件QSplitter 的信号

分割器控件QSplitter 只有一个信号 splitterMoved(pos:int,index;int),当分隔条移动时发送信号,信号的参数是分割条的位置和索引值。

分割器控件QSplitter 的应用实例

下面的程序用两个 QSplitter 分割器将窗日分成三部分,每部分显示一个图片。

image-20230225012434495

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:53
# File_name: 01-分割器控件QSplitter 的应用实例.py
from PySide6.QtWidgets import QApplication, QWidget, QSplitter, QLabel, QHBoxLayout
from PySide6.QtCore import Qt
import sys
from PySide6.QtGui import QPixmap


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.widget_setupUi()

def widget_setupUi(self): # 建立主程序界面
label_1 = QLabel()
label_2 = QLabel()
label_3 = QLabel()

label_1.setPixmap(QPixmap('../../Resources/animal/m1.png'))
label_2.setPixmap(QPixmap('../../Resources/animal/m2.png'))
label_3.setPixmap(QPixmap('../../Resources/animal/m3.png'))

splitter_H = QSplitter(Qt.Orientation.Horizontal)
splitter_V = QSplitter(Qt.Orientation.Vertical)
h = QHBoxLayout(self)
h.addWidget(splitter_H)
splitter_H.addWidget(label_1)
splitter_H.addWidget(splitter_V)
splitter_V.addWidget(label_2)
splitter_V.addWidget(label_3)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

切换卡控件QTabWidget

QTabBar

切换卡控件QTabWidget 由多页卡片构成,每页卡片就是一个窗口(QWidget)。

可以将不同的控件放到不同的卡片上,这样可以节省界面资源。切换卡控件的外观如图所示,当无法显示全部卡片时,可单击右上角显示滚动按钮。

切换卡控件继承自QWidget。用QTabWidget类创建实例对象的方法如下所示,其中parent 是窗口或者容器类控件。

1
2
3
from PySide6.QtWidgets import QTabWidget

QTabWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

切换卡控件QTabWidget 的常用方法

切换卡控件QTabWidget 的常用方法如表所示主要方法介绍如下。

切换卡的每页卡片都是一个窗口(QWidget)或者从QWidget继承的可视化子类因此添加卡片时,需要实例化的QWidget。

  • QTabWidget 添加卡片的方法是 addTab(QWidget,label:str)和 addTab(QWidget,QIcon,label:str)

    • QWidger 是继承自QWidget 的实例
    • label是卡片标题的名称,可以在名称中添加”&”和字母设置快捷键;
    • QIcon 是卡片的图标,
    • 卡片的索引从0开始。
  • 在某个位置插入卡片用insertTab(index; int,QWidget,label: str)和 insertTab(index: int,QWidget,QIcon,str)方法;

  • 删除所有卡片用clear()方法;

  • 删除索引号是int 的卡片用removeTab(index:int)方法;

  • 卡片标题可以用setTabText(index:int,str)方法设置,其中参数index是卡片的索引。

  • 卡片标题栏可以放到上、下左、右位置

    • 卡片标题的位置用setTabPosition(QTabWidget TabPosition)方法设置,其中参数 QTabWidget.TabPosition 可以取:
      • QTabWidget.North 上
      • QTabWidget.South 下
      • QTabWidget.East 右
      • QTabWidget.West 左。
  • 标题栏的位置如图所示

    • 可以用tabPosition()方法获取标题栏的位置。
  • 卡片标题栏的形状

    • 用setTabShape(QTabWidget,TabShape)方法定义,其中参数QTabWidget.TabShape可以取 :
      • QTabWidget.Rounded 圆角
      • QTabWidget.Triangular 三角形
    • 用tabShap()方法可以获取标题栏的形状。
  • 如果显示标题栏文字的空间不足,可以用省略号来表示。

    • 用setElideMode(Qt.TextElideMode)方法设置卡片标题栏文字在显示空间不足时的省略号显示方式,其中参数 Qt.TextElideMode 可以取:
      • Qt.ElideNone 没有省略号
      • Qt.ElideLeft 省略号在左边
      • Qt.ElideMiddle 省略号在中间
      • Qt.ElideRight 省略号在右边
  • 当卡片较多时,父窗口中无法显示出所有的卡片标题,这时可以用滚动条来显示出被隐藏的卡片。

    • 用setUsesScrollButtons(bool)方法设置是否有滚动按钮。每页卡片显示时,默认为有框架并呈立体形状显示在父窗口上。
    • 用setDocumentMode(bool)方法设置卡片是否有框架,如果没有框架,则卡片上内容与父窗口看起来是一个整体。
  • 当setTabsClosable(bool)为 True 时,卡片的标题栏上显示关闭标识,单击该关闭标识,可发送tabCloseRequested(int)信号。

  • 用setCornerWidget(QWidget,Qt.Corner)方法可以在 QTabWidget 的右上角下角、左上角和左下角处放置控件,例如放置标签、单击按钮等,其中参数 Qt.Corner 可以取:

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

    用cornerWidget(Qt.Corner)方法可以获取角上的控件

  • 用setTabBarAutoHide(bool)方法可以设置当只有1张卡片时,卡片标题是否自动隐藏。

QTabWidget的方法及参数类型 返回值的类型 说 明
addTab(QWidget,label:str) int 在末尾添加新卡片
addTab(QWidget,QIcon,label: str) int 在末尾添加新卡片
insertTab(index: int,QWidget,label; str) int 在索引int处插入卡片
insertTab(index: int,QWidget,QIcon,str) int 在索引int处插入卡片
widget(index:int) QWidget 根据索引获取卡片窗口
clear() None 清空所有卡片
count() int 获取卡片数量
indexOf(QWidget) int 获取窗口对应的卡片索引号
removeTab(index: int) None 根据索引移除卡片
setCornerWidget(QWidget,Qt.Corner) None 在角上设置控件
cornerWidget(Qt.Corner) QWidget 获取角位置处的控件
[slot]setCurrentIndex(index;int) None 根据索引设置当前卡片
currentIndex() int 获取当前卡片的索引号
[slot]setCurrentWidget(QWidget) None 将窗口控件是 QWidget的卡片设置成当前卡片
currentWidget() QWidget 获取当前卡片的窗口
setDocumentMode(bool) None 设置卡片是否为文档模式
documentMode() bool 获取卡片是否为文档模式
setElideMode(Qt.TextElideMode) None 设置卡片标题是否为省略模式
setlconSize(QSize) None 设置卡片图标的尺寸
iconSize() QSize 获取卡片图标的尺寸
setMovable(bool) None 设置卡片之间是否可以交换位置
isMovable() bool 获取卡片是否可以交换位置
setTabBarAutoHide(bool) None 设置卡片标题是否自动隐藏
tabBarAutoHide() bool 获取标题是否可以自动隐藏
setTabEnabled(index:int,bool) None 设置是否将索引为int的卡片激活
isTabEnabled(index:int) bool 获取索引为int的卡片是否激活
setTabIcon(index:int,QIcon) None 设置索引为int的卡片的图标
tabIcon(index:int) QIcon 获取索引为int的卡片的图标
setTabPosition(QTabWidget.TabPosition) None 设置标题栏的位置
setTabShape(QTabWidget.TabShape) None 设置标题栏的形状
setTabText(index:int,str) None 根据索引设置卡片的标题名称
tabText(index:int) str 获取卡片标题的名称
setTabToolTip(index:int,str) None 根据索引设置卡片的提示信息
tabToolTip(index:int) Str 获取卡片的提示信息
setVisible(bool) None 设置切换卡是否显示
setTabsClosable(bool) None 设置卡片标题上是否有关闭标识
tabsClosable() bool 获取卡片是否可以关闭
setUsesScrollButtons(bool) None 设置是否可以有滚动按钮
usesScrollButtons() bool 获取是否有滚动按钮

切换卡控件QTabWidget的信号

切换卡控件QTabWidget的信号如表所示

QTabWidget 的信号及参数类型 说明
currentChanged(index: int) 当前卡片改变时发送信号
tabBarClicked(index:int) 单击卡片的标题时发送信号
tabBarDoubleClicked(index: int) 双击卡片的标题时发送信号
tabCloseRequested(index: int) 单击卡片的关闭标识时发送信号

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import os

os.chdir(os.path.dirname(__file__))


class TabDemo(QWidget):
def __init__(self, parent=None):
super(TabDemo, self).__init__(parent)
self.tabWidget = QTabWidget(self)
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tab3 = QWidget()
self.tabWidget.addTab(self.tab1, "Page 0")
self.tabWidget.insertTab(1, self.tab2, "Page 1")
self.tabWidget.addTab(self.tab3, "Page 2")
self.tab1Init()
self.tab2Init()
self.tab3Init()

# 修改选项卡默认信息
self.tabWidget.setTabShape(self.tabWidget.TabShape.Triangular)
self.tabWidget.setTabPosition(self.tabWidget.TabPosition.South)

pageComboBox = QComboBox()
pageComboBox.addItem("Goto Page 0")
pageComboBox.addItem("Goto Page 1")
pageComboBox.addItem("Goto Page 2")
# 导航与页面链接
pageComboBox.activated.connect(self.tabWidget.setCurrentIndex)

vlayout = QVBoxLayout(self)
self.label = QLabel('用来显示信息')
vlayout.addWidget(pageComboBox)
vlayout.addWidget(self.label)
vlayout.addWidget(self.tabWidget)
self.setLayout(vlayout)

self.setWindowTitle("QTabWidget 例子")
self.resize(400, 200)

self.tabWidget.currentChanged.connect(self.tabChanged)

def tab1Init(self):
layout = QFormLayout()
line1 = QLineEdit()
line2 = QLineEdit()
layout.addRow("姓名", line1)
layout.addRow("电话", line2)
self.tab1.setLayout(layout)
self.tabWidget.setTabText(0, "联系方式")
line1.editingFinished.connect(lambda: self.label.setText(f'page0,更新了姓名:{line1.text()}'))
line2.editingFinished.connect(lambda: self.label.setText(f'page0,更新了电话:{line2.text()}'))

def tab2Init(self):
layout = QFormLayout()
sex = QHBoxLayout()
radio1 = QRadioButton("男")
radio2 = QRadioButton("女")
sex.addWidget(radio1)
sex.addWidget(radio2)
layout.addRow(QLabel("性别"), sex)
line = QLineEdit()
layout.addRow("教育程度", line)
self.tab2.setLayout(layout)
self.tabWidget.setTabText(1, "个人信息")
self.tabWidget.setTabToolTip(1, '更新:个人信息')
self.tabWidget.setTabIcon(1, QIcon(r'images/cartoon1.ico'))
self.tabWidget.tabBar().setTabTextColor(1, QColor(40, 120, 120))

radio1.clicked.connect(lambda: self.label.setText('page 1 更新了性别:男'))
radio2.clicked.connect(lambda: self.label.setText('page 1 更新了性别:女'))
line.editingFinished.connect(lambda: self.label.setText(f'page1,更新了教育程度:{line.text()}'))

def tab3Init(self):
layout = QHBoxLayout()
check1 = QCheckBox('一等奖')
check2 = QCheckBox('二等奖')
check3 = QCheckBox('三等奖')
layout.addWidget(check1)
layout.addWidget(check2)
layout.addWidget(check3)
self.tab3.setLayout(layout)
self.tabWidget.setTabText(2, "获奖情况")
self.tabWidget.setTabToolTip(2, '更新:获奖情况')
self.tabWidget.setTabIcon(2, QIcon(r'images/bao13.png'))
self.tabWidget.tabBar().setTabTextColor(2, 'red')

_dict = {0: False, 2: True, 1: True}
check1.stateChanged.connect(lambda x: self.label.setText(f'page2,更新了“1等奖”获取情况:{_dict[x]}'))
check2.stateChanged.connect(lambda x: self.label.setText(f'page2,更新了“2等奖”获取情况:{_dict[x]}'))
check3.stateChanged.connect(lambda x: self.label.setText(f'page2,更新了“3等奖”获取情况:{_dict[x]}'))

def tabChanged(self, index: int):
a = self.tabWidget.currentWidget()
text = self.tabWidget.tabBar().tabText(index)
self.label.setText(f'切换到页面{index},{text}')


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = TabDemo()
demo.show()
sys.exit(app.exec())

控件栈,层次容器QStackedWidget

QStackedWidget

控件栈控件QStackedWidget与QTabWidget 在功能上有些相似。

控件栈也是包含多个窗口的控件,但是与QTabWidget不同的是,控件栈不是通过卡片管理窗口控件,而是根据需要从多个控件中选择某个窗口作为当前窗口,当前窗口是要显示的窗口,而不是当前的窗口不显示。

QStackedWidget 通常与 QComboBox和QListWidget等控件一起使用,当选择QComboBox或QListWidget 中的某项(Item)内容时,从QStackedWidget 中显示与之相关的某个窗口界面。

QStackedWidget类是从QFrame继承而来的。用QStackedWidget 类创建实例对象的方法如下所示其中parent 是窗口或者容器类控件。

1
2
3
from PySide6.QtWidgets import QStackedWidget

QStackedWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

控件栈控件QStackedWidget的常用方法

控件栈控件QStackedWidget 的常用方法如表示。

  • 控件栈通过 addWidget(QWidget)方法添加窗口,根据窗口添加的顺序,窗口的索引值从0开始逐渐增加。

  • 用insertWidget(index:int;QWidget)方法可以插人新窗口插入的窗口的索引值是int,如果需要把某个窗口显示出来,需要将窗口设置为当前窗口。

  • 设置当前窗口的方法是SetCurrentWidget(QWidget)或 setCurrentIndex(index:int)可以将指定的窗口或索引值是int的窗口设置成当前窗口。

QStackedWidget的方法及参数类型 返回值的类型 说明
addWidget(QWidget) int 在末尾添加窗口,并返回索引值
insertWidget(index:int,QWidget) int 插入新窗口,插入的窗口索引值是int
[slof]setCurrentWidget(QWidget) None 将指定的窗口设置成当前窗口
[slot]setCurrentIndex(index:int) None. 将索引值是int的窗口设置成当前窗口
widget(index:int) QWidget 获取索引值是int的窗口
currentIndex() int 获取当前窗口的索引值
currentWidget() QWidget 获取当前的窗口
indexOf(QWidget) int 获取指定窗口的索引值
removeWidget(QWidget) None 移除窗口
count() int 获取窗口数量

控件栈控件QStackedWidget的信号

控件栈控件QStackedWidget 的信号有 currentChanged(index:int)和widgetRemoved(index:int)

  • 当前窗口发生变化时发送currentChanged(index:int)信号
  • 移除窗口时发送widgetRemoved(index:int)信号。

QStackedWidget例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/19 2:08
# File_name: 01-QStackedWidget实例.py


import sys
from PySide6.QtWidgets import *


class QStackedWidgetDemo(QMainWindow):
def __init__(self):
super(QStackedWidgetDemo, self).__init__()

self.resize(400, 150)
# 设置窗口标题
self.setWindowTitle("QStackedWidgetDemo")

# 创建列表窗口,添加条目
listWidget = QListWidget()
listWidget.insertItem(0, '联系方式')
listWidget.insertItem(1, '个人信息')
listWidget.insertItem(2, '教育程度')
listWidget.currentRowChanged.connect(self.rowChanged)

# 创建三个小控件
stack1 = QLabel('标签一', self)
stack2 = QLabel('标签二', self)
stack3 = QLabel('标签三', self)

# 在QStackedWidget对象中填充了三个子控件
self.stackedWidget = QStackedWidget(self)
self.stackedWidget.addWidget(stack1)
self.stackedWidget.addWidget(stack2)
self.stackedWidget.addWidget(stack3)

layout = QHBoxLayout()
layout.addWidget(listWidget)
layout.addWidget(self.stackedWidget)

mainFrame = QWidget()
mainFrame.setLayout(layout)
self.setCentralWidget(mainFrame)

def rowChanged(self, i):
self.stackedWidget.setCurrentIndex(i)


if __name__ == '__main__':
app = QApplication(sys.argv)
main = QStackedWidgetDemo()
main.show()
sys.exit(app.exec())

分组容器QGroupBox

分组框控件 QGroupBox 通常是其他控件的容器,将一组意义相同或者一组互斥的QRadioButton 控件放到 QGroupBox 中。QGroupBox 通常带有一个边框和一个标题栏标题栏上可以有勾选项,标题栏可以放到左边、中间或右边。分组框控件的外观如图 2-29 所示。布局时 QGroupBox 可用作一组控件的容器,内部使用布局控件(如 QBoxLayout)进行布局。

用QGroupBox类创建实例对象的方法如下所示。用QGroupBox类创建实例对象的方法如下所示。

  • parent 是窗口或者容器类控件
  • title是控件上显示的文字
1
2
3
4
from PySide6.QtWidgets import QGroupBox

QGroupBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QGroupBox(title: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

分组框控件QGroupBox的常用方法

分组框控件QGroupBox的常用方法如表所示。

  • 用setTitle(str)方法可以设置分组框的标题名称;用title()方法可以获取标题名称
  • 用setCheckable(bool)方法可以设置标题栏上是否有勾选项;
  • 用setAlignment(QAlignment)方法可以设置标题栏的对齐位置,其中参数 Qt.Alignment 可以取:
    • Qt.AlignLeft 把标题栏放到左边
    • QtAlignRight 把标题栏放到右边
    • Qt.AlignHCenter 把标题栏放到中间;
  • 用setGeometr(QRect)方法可以设置分组框在父容器中的位置宽度和高度;
  • 用resize(QSize)方法设置分组框的宽度和高度。
  • 创建分组框控件后,如果要往分组框中添加其他控件,可以在创建控件对象时将其parent 参数设置成QGroupBox 的实例对象,或者用控件的 setParent(QWidget)方法设置控件所在的容器。对其他容器类控件,添加控件的操作方法相同。也可以先创建布局,将控件放到布局中,然后用分组框的 setLayout(QLayout)方法将布局添加到分组框中。
QGroupBox的方法及参数类型 返回值的类型 说明
set Title(str) None 设置标题的名称
title() Str 获取标题的名称
setFlat(bool) None 设置是否处于扁平状态
isFlat() bo0l 获取是否处于扁平状态
setCheckable(bool) None 设置标题栏上是否有勾选项
isCheckable() bool 获取是否有勾选项
[slot]setChecked(bool) None 设置是否处于勾选状态
isChecked() bool 获取勾选项是否处于勾选状态
setAlignment(Qt.Alignment) None 设置标题栏的对齐位置
alignment() Qt.Alignment 获取标题栏的对齐位置
setGeometry(QRect) setGeometry(x:int,y:int,w: int,h:int) None 设置分组框在父容器中的位置、宽度 和高度
resize(QSize) resize(w: int,h:int) None 设置分组框的宽度和高度
setLayout(QLayout) None 设置分组框中的布局

分组框控件的信号

分组框控件的信号有 clicked(),clicked(bool)和 toggled(bool)

  • 有勾选项时,切换勾选状态时的信号 toggled(bool)。

QGroupBox例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 22:59
# File_name: demo.py


import sys
from PySide6.QtWidgets import QRadioButton, QGroupBox, QHBoxLayout, QWidget, QApplication, QMainWindow


class QGroupBoxDemo(QMainWindow):
def __init__(self):
super(QGroupBoxDemo, self).__init__()

# 设置窗口大小
self.resize(400, 150)
# 设置窗口标题
self.setWindowTitle("QGroupBoxDemo")

groupBox = QGroupBox('性别')
radio1 = QRadioButton('男')
radio2 = QRadioButton('女')
radio1.setChecked(True)
hlayout = QHBoxLayout()
groupBox.setLayout(hlayout)
hlayout.addWidget(radio1)
hlayout.addWidget(radio2)

# 创建水平布局
layout = QHBoxLayout()
layout.addWidget(groupBox)

mainFrame = QWidget()
mainFrame.setLayout(layout)
self.setCentralWidget(mainFrame)


if __name__ == '__main__':
app = QApplication(sys.argv)
main = QGroupBoxDemo()
main.show()
sys.exit(app.exec())

工具栏容器ToolBox

工具箱控件QToolBox与切换卡控件QTabWidget 有些类似,也是由多页构成每页有标题名称。

与切换卡不同的是,工具箱的标题是从上到下依次排列,每页的标题呈按钮状态,单击每页的标题,每页的窗口会显示在标题按钮下面,而切换卡的标题是按顺序展开,切换卡的标题面积比卡片窗口的面积小。工具箱界面的外观由两个按钮构成。

QToolBox是从QFrame类继承而来的。用QTolBox类创建实例对象的方法如下所示,其中parent是窗口或者容器类控件,参数 QtWindowFlags 用于设置窗口类型其取值参考31节中的内容,默认值是Qt.Widget。

1
2
3
from PySide6.QtWidgets import QToolBox

QToolBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, f: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

工具箱控件QToolBox的常用方法

工具箱控件QToolBox的常用方法如表所示。

工具箱中的每个窗口称为item(项或条目)。

  • 用addItem(QWidget,text; str)或addItem(QWidget,QIcon,text;str)方法在末尾添加项
    • QWidget 是对应的窗口或控件,
    • text是项的标题名称,可以在文本中添加”&”和字母设置快捷键;
  • 用insertItem(index:int,QWidget,text:str)或 insertItem(index:int,QWidget,QIcon,text;str)方法可以在指定位置插项;
  • 用removeItem(index:int)方法可以删除指定的项;
  • 用count()方法可以获取项的数量;
  • 用setItemText(int;str)方法可以设置项的标题名称;
  • 用setItemIcon(int,QIcon)方法可以指定项的图标
  • 用currentWidget()方法可以获取当前项的窗口;
  • 用widget(index:int)方法可以根据索引值获取项的窗口。
QToolBox的方法及参数类型 返回值的类型 说 明
addItem(QWidget,text:str) int 在末尾添加项,text 是标题名称,QIcon 是图 标或QPixmap 图像
addItem(QWidget,QIcon,text;str) int 在末尾添加项,text 是标题名称,QIcon 是图 标或QPixmap 图像
insertltem(index: int,QWidget,text: str) int 根据索引插入项,新插入项的索引值是index
insertltem(index:int.QWidget,QIcon,str) int 根据索引插入项,新插入项的索引值是index
[slot]setCurrentIndex(index:int) None 将索引值是int的项设置成当前项
currentIndex() int 获取当前项的索引
[slot]setCurrentWidget(QWidget) None 将指定窗口设置成当前窗口
currentWidget() QWidget 获取当前项的窗口
widget(index:int) int 获取索引值是int的窗口
removeItem(index:int) None 移除索引值是 int的项
count() int 获取项的数量
indexOf(QWidget) int 获取指定窗口的索引值
setItenEnabled(index: int, bool) None 设置索引值是int的项是否激活
isltemEnabled(index:int) bool 获取索引值是int的项是否激活
setltemIcon(index: int,QIcon) None 设置项的图标
itemIcon(index:int) QIcon 获取项的图标
setItemText(index:int,str) None 设置项的标题名称
item Text(index:int) str 获取项的标题名称
setItemToolTip(index: int,str) None 设置项的提示信息
itemToolTip(index:int) str 获取项的提示信息

工具箱控件QToolBox的常用方法和信号

工具箱控件只有1个信号currentChanged(index:int)当前项发生变化时发送参数是当前项的索引。

工具箱控件QToolBox实例

image-20230319022348845

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 22:59
# File_name: 01-ToolBox例子.py


import sys
from PySide6.QtCore import Qt.QSize
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import(QApplication, QWidget, QToolBox, QToolButton, QGroupBox, QVBoxLayout, QHBoxLayout)


class DemoToolBox(QWidget):
def __init__(self, parent=None):
super(DemoToolBox, self).__init__(parent)

# 设置窗口标题
self.setWindowTitle('QToolBox Demo!')
# 设置窗口大小
self.resize(480, 360)

self.initUi()

def initUi(self):
self.names =['长跑', '斯诺克', '棒球']

self.gamers =[
[
{'name': '赵一', 'pic': ':../../../Resources/animal/m1.png'},
{'name': '钱二', 'pic': '../../../Resources/animal/m2.png'},
],
[
{'name': '张三', 'pic': '../../../Resources/animal/m3.png'},
{'name': '李四', 'pic': '../../../Resources/animal/m4.png'},
],
[
{'name': '王五', 'pic': '../../../Resources/animal/m5.png'},
{'name': '郑六', 'pic': '../../../Resources/animal/m6.png'},
]
]

vLayout = QVBoxLayout(self)
self.toolBox = QToolBox(self)

self.toolBox.currentChanged.connect(self.onToolBoxCurrentChanged)

for index in range(0, 3):
self.toolBox.addItem(self.createGroup(index), self.names[index])

vLayout.addWidget(self.toolBox)
self.setLayout(vLayout)

def createGroup(self, index):
grpBox = QGroupBox(self)
layout = QHBoxLayout(self)

for category in self.gamers[index]:
gamer = QToolButton(self)
gamer.setText(category['name'])
gamer.setIcon(QIcon(category['pic']))
gamer.setIconSize(QSize(128, 128))
gamer.setAutoRaise(True)
gamer.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
layout.addWidget(gamer)

grpBox.setLayout(layout)
return grpBox

def onToolBoxCurrentChanged(self):
info = '您正在查看{}项目.'.format(self.names[self.toolBox.currentIndex()])
print(info)


if __name__ == '__main__':
app = QApplication(sys.argv)
window = DemoToolBox()
window.show()
sys.exit(app.exec())

按钮控件

抽象按钮QAbstractButton

1
QAbstractButton(self, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

该类QAbstractButton是按钮小部件的抽象基类,提供按钮通用的功能。

QAbstractButton提供对按钮和可检查(切换)按钮的支持。

可检查按钮在QRadioButton和QCheckBox类中实现。按钮在QPushButton和QToolButton类中实现;如果需要,这些还提供切换行为。

可以通过 setDefault()和 setAutoDefault()使按钮成为对话框中的默认按钮。

设置文本/图标

任何按钮都可以显示包含文本和图标的标签。如果一个按钮被禁用,它的标签将被更改为按钮一个”禁用”的外观。

Qt 提供的所有按钮(QPushButton、QToolButton、QCheckBox和QRadioButton)都可以同时显示text和图标。

方法 说明
setText(text) 参数 text:文字str 设置按钮上显示的文本。默认没有文本。如果按钮没有文本,text() 函数将返回一个空字符串。
如果文本包含一个符号字符(‘&’),则会自动为其创建一个快捷方式。’&’ 后面的字符将用作快捷键。
如果文本未定义任何快捷方式,则任何先前的快捷方式都将被覆盖或清除。要显示 &实际的符号,使用”&&”。
text() 获取按钮提示文本
setIcon(QIcon("resource/h1.png")) 设置图标
setIconSize(QSize(w, h)) 设置图标大小
参数 图标–PySide6.QtGui.QIcon 设置按钮上显示的图标。图标的默认大小由 GUI 样式定义,但可以通过设置iconSize属性进行调整。
icon() 获取图标(QSize对象)
返回类型 PySide6.QtGui.QIcon
此属性保存按钮上显示的图标。图标的默认大小由 GUI 样式定义,但可以通过设置iconSize属性进行调整。
iconSize() 获取图标大小(QSize对象)
参数 尺寸–PySide6.QtCore.QSize设置按钮的图标大小。默认大小由 GUI 样式定义。这是图标的最大尺寸。较小的图标不会按比例放大。

快捷键

当用户按下快捷键,按钮将调用animateClick()

设置快捷键有两种方法,一种有设置文本(仅支持英文)可在提示文本中插入 &符号,快捷键将会设置为 ALT和其后面字母的快捷键

可以通过方法设置自定义组合快捷键。

方法 说明
but.setText("&xxx") button=QPushButton(self)button.setText("&ert") # 设置提示文本并自动添加快捷键ALT+Ebutton.setText(“e&rt”) # 设置提示文本并自动添加快捷键ALT+R``button.setText(“er&t”) # 设置提示文本并自动添加快捷键ALT+T
button.setShortcut("key+key") button.setShortcut(“Alt+E”) # 设置快捷键为ALT+E button.setShortcut("Alt+R") # 设置快捷键为ALT+Rbutton.setShortcut(“Alt+T”) # 设置快捷键为ALT+T
shortcut() 返回类型 PySide6.QtGui.QKeySequence 查看按钮关联的助记符。

长按重复点击

方法 说明
setAutoRepeat(arg__1) 设置按钮是否会在用户按住时自动重复。autoRepeatDelay并autoRepeatInterval定义自动重复是如何完成的。
参数 arg__1 – 布尔值``如果启用了autoRepeat,则在按下按钮时会定期发出pressed()、released()和信号。clicked()autoRepeat 默认关闭。
初始延迟和重复间隔由autoRepeatDelay和以毫秒为单位定义autoRepeatInterval。
注意:如果一个按钮被快捷键按下,那么自动重复将被系统启用和计时,而不是这个类。pressed()信号将像正常情况下一样发出released()。clicked()
autoRepeat() 返回类型 整数
返回是否启用autoRepeat。
如果启用了,则在按钮按下时会定期发出pressed()、released()和clicked()信号。autoRepeat默认关闭。初始延迟和重复间隔由autoRepeatDelay和autoRepeatInterval定义,单位为毫秒。
注意:如果一个按钮被快捷键按下,那么自动重复将启用,并由系统计时,而不是由这个类计时。pressed()、released()和clicked()信号将像正常情况下一样发出。
setAutoRepeatInterval(arg__1) 参数 arg__1 – 整数``设置自动重复的间隔。如果autoRepeat启用,则 autoRepeatInterval 定义自动重复间隔的长度(以毫秒为单位)。
autoRepeatInterval() 返回类型 整数
返回自动重复的间隔。``如果autoRepeat启用,则 autoRepeatInterval 定义自动重复间隔的长度(以毫秒为单位)。
setAutoRepeatDelay(arg__1) 参数 arg__1 – 整数``设置自动重复的触发时间。如果autoRepeat启用,则 autoRepeatDelay 定义自动重复开始前的初始延迟(以毫秒为单位)。
autoRepeatDelay() 返回自动重复的触发时间 ,返回类型 整数。如果启用autoRepeat,则autoRepeatDelay定义自动重复开始之前的初始延迟(以毫秒为单位)。

状态

QAbstractButton提供用于按钮的大多数状态:

判断状态 说明
setEnabled(arg__1) arg__1 – bool
返回按钮是否已启用。禁用按钮会将其标签绘制为灰色。禁用小部件会隐式禁用其所有子部件。启用会启用所有子部件,除非它们已被显式禁用。当父控件保持禁用状态时,不可能显式启用不是窗口的子控件。默认情况下,此属性为true。
setCheckable(arg__1) 参数 arg__1 – 布尔值``设置按钮是否可选中。默认情况下,该按钮不可选中,可判断按钮是否为切换按钮。。
返回类型 布尔值,返回按钮是否可选择。默认情况下,该按钮不可选中。
setDown(arg__1) 参数 arg__1 – 布尔值``设置按钮是否被按下。如果此属性为true,则按钮被按下。如果将此属性设置为 true,则不会发出信号pressed()/clicked()默认为假。
isEnabled() 返回按钮是否启用。。(与其他小部件相反,派生自的按钮QAbstractButton在禁用时接受鼠标和上下文菜单事件。)
isCheckable 按钮是否可以被选中。
返回类型 布尔值
isDown() 指示按钮是否被按下。
返回类型 布尔值``该属性保存按钮是否被按下。如果此属性为true,则按钮被按下。如果将此属性设置为 true,则不会发出信号pressed()和。clicked()默认为假。
isChecked() 表示按钮是否被选中。
返回类型 布尔值``该属性保存按钮是否被选中。只能检查可检查的按钮。默认情况下,该按钮未选中。

isDown()和isChecked()的区别如下。

当用户点击一个切换按钮来选中它时,该按钮首先被按下然后释放到选中状态。当用户再次单击它(取消选中它)时,按钮首先移动到按下状态,然后移动到未选中状态(isChecked()并且isDown()都是false)。(需要注意在多选可点击按钮时的区别)

点击

方法 说明
animateClick() 执行动画点击:立即按下按钮,并在 100 毫秒后释放。 在释放按钮之前再次调用此函数会重置释放计时器。 与点击相关的所有信号都会适当发出。
如果按钮未启用(PySide6.QtWidgets.QWidget.setEnabled()),此函数不执行任何操作
click() 执行点击。 所有与点击相关的常见信号都会适当发出。如果按钮选择按钮,则切换按钮状态。
如果按钮未启用(PySide6.QtWidgets.QWidget.setEnabled()),此函数不执行任何操作.类似于animateClick()但无动画
setChecked(arg__1) 参数 arg__1 – 布尔值 设置按钮被选中。 只能设置可选中的按钮。默认情况下,该按钮未选中。 也可以看看checkable
toggle() 切换可选择按钮的状态。 也可以看看checkable

排他性

方法 说明
setAutoExclusive(arg__1) 参数 arg__1 – 布尔值
设置是否启用自动排他性。如果启用了自动排他性,那么属于同一个父小部件的可检查按钮的行为就像它们属于同一个排他按钮组一样。在独占按钮组中,每次只能选中一个按钮;选中另一个按钮会自动取消选中前一个按钮。该属性对属于按钮组的按钮不起作用。autoExclusive默认是关闭的,单选按钮除外。
autoExclusive() 返回类型 布尔值
此属性用于确定是否启用自动排他性。

信号

QAbstractButton提供四种信号:

  • 当在按钮上按下鼠标左键:pressed()
  • 在按钮上松开左键时,先发送released(),在发送clicked()
  • 如果在按钮上按下左键不放则光标移开时发送released(),不再发送clicked()
方法 说明
pressed() 按下按钮时会发出此信号。
也可以看看released() clicked()
released() 当鼠标按下后释放按钮(不松开移出控件范围也会)发出此信号。
clicked([checked=false]) 当鼠标光标在按钮内时按下左键并释放(快捷键被触发 、click()animateClick()被调用时),这个信号被发出。调用setDown()/``setChecked()/toggle()则不会发出此信号。参数checked`:布尔值,checked参数表示是否选中该按钮,按钮被选中-true,按钮未选中-false。
toggled(checked) 参数 check- 布尔 按钮选中状态改变时发送信号<br />只要可检查按钮改变其状态,就会发出此信号。checked如果按钮被选中则为 true,如果按钮未被选中则为 false。这可能是用户操作、click()插槽激活或setChecked()调用的结果。``独占按钮组中按钮的状态在发出此信号之前更新。这意味着插槽可以根据状态已更改的组中按钮发出的”关闭”信号或”打开”信号进行操作。

点击有效区域

方法 说明
hitButton(pos) 查看指定坐标是否可点击,返回类型 布尔值 参数 pos-PySide6.QtCore.QPointtrue如果pos在可点击按钮矩形内则返回;否则返回false。默认情况下,可点击区域是整个小部件。子类可以重新实现此功能以提供对不同形状和大小的可点击区域的支持。

重写 hitButton(QPoint)

QPoint时参考按钮的左上角坐标

  • 有效返回True
  • 无效返回False

虚函数

方法 说明
checkStateSet() 此虚拟处理程序在使用时被调用setChecked(),除非它是从内部调用的nextCheckState()。它允许子类重置它们的中间按钮状态。
nextCheckState() 单击按钮时将调用此虚拟处理程序。默认实现调用setChecked(! isChecked()) 如果按钮isCheckable()。它允许子类实现中间按钮状态。

重写

要继承QAbstractButton,您必须至少重新实现paintEvent()以绘制按钮的轮廓及其文本或像素图。通常也建议重新实现sizeHint(),有时hitButton()(确定按钮按下是否在按钮内)。对于具有两种以上状态的按钮(如三态按钮),您还必须重新实现checkStateSet()和nextCheckState()。

按压按钮控件QPushButton

windows-pushbutton.png

按钮或命令按钮可能是任何图形用户界面中最常用的小部件。按下(单击)按钮以命令计算机执行某些操作或回答问题。

QPushButton继承自QAbstractButton,具有QAbstractButton的方法。

命令按钮是矩形的,通常显示描述其操作的文本标签。可以通过在文本中的首选字符前面加上与号来指定快捷键。

按钮显示文本标签和小图标(可选)。这些可以使用构造函数进行设置,并在以后使用setText()setIcon()进行更改。如果按钮被禁用,文本和图标的外观将根据 GUI 样式进行操作,以使按钮看起来”禁用”。

按钮在鼠标、空格键或键盘快捷键激活时发出clicked() 信号。连接到此信号以执行按钮的操作。按钮还提供不太常用的信号,例如 pressed()release()

对话框中的命令按钮默认为自动默认按钮,即,当它们收到键盘输入焦点时,它们会自动成为默认按钮。默认按钮是当用户在对话框中按 Enter 或 Return 键时激活的按钮。可以使用setAutoDefault()更改此设置。请注意,自动默认按钮会保留一些额外的空间,这是绘制默认按钮指示器所必需的。如果不希望按钮周围有此空间,请调用setAutoDefault(false)

1
2
3
QPushButton(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QPushButton(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QPushButton(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

QPushButton特有方法

方法和参数 返回值类型 说明
setMenu(menu: QMenu) None 设置菜单
menu(self) PySide6.QtWidgets.QMenu 获取菜单
[slot]showMenu(self) None 弹出菜单
setAutoDefault(self, arg__1: bool) None 设置按钮是否是自动默认按钮
autoDefault(self) bool 获取按钮是否是自动默认按钮
setDefault(self, arg__1: bool) None 设置按钮是否默认按钮,按下Enter键发送该按钮的信号
isDefault(self) bool 获取按钮是否是默认按钮
setFlat(self, arg__1: bool) None 设置按钮是否没有突起效果
isFlat(self) bool 获取按钮是否没有突起效果

QPushButton例子

image-20230319022604885

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:54
# File_name: 05-QButton例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import os

os.chdir(os.path.dirname(__file__))


class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
layout = QVBoxLayout()
self.label_show = QLabel('显示按钮信息')
layout.addWidget(self.label_show)

self.button1 = QPushButton("Button1")
self.button1.setCheckable(True)
self.button1.toggle()
self.button1.clicked.connect(lambda: self.button_click(self.button1))
layout.addWidget(self.button1)

self.button_image = QPushButton('image')
self.button_image.setCheckable(True)
self.button_image.setIcon(QIcon(QPixmap("../../../Resources/animal/m1.png")))
self.button_image.clicked.connect(lambda: self.button_click(self.button_image))
layout.addWidget(self.button_image)

self.button_disabled = QPushButton("Disabled")
self.button_disabled.setEnabled(False)
layout.addWidget(self.button_disabled)

self.button_shortcut = QPushButton("&Shortcut_Key")
self.button_shortcut.setDefault(True)
self.button_shortcut.setCheckable(True)
self.button_shortcut.clicked.connect(lambda: self.button_click(self.button_shortcut))
layout.addWidget(self.button_shortcut)

self.setWindowTitle("Button demo")
self.setLayout(layout)

def button_click(self, button):
if button.isChecked():
self.label_show.setText('你按下了' + button.text() + " isChecked=True")
else:
self.label_show.setText('你按下了' + button.text() + " isChecked=False")


if __name__ == '__main__':
app = QApplication(sys.argv)
btnDemo = Form()
btnDemo.show()
sys.exit(app.exec())

命令链接按钮QCommandLinkButton

image-20230212170808038

命令链接是Windows Vista引入的新控件 它的用途类似于单选按钮的用途,因为它用于在一组互斥选项之间进行选择 命令链接按钮不应单独使用,而应作为向导和对话框中单选按钮的替代选项 外观通常类似于平面按钮的外观,但除了普通按钮文本之外,它还允许描述性文本

QCommandLinkButton从QPushButton继承而来

命令链接按钮QCommandLinkButton主要用于由多个对话框构成的向导对话框,其外观通常类似于平面按钮,除了默认按钮文本外还带有一个向右的箭头可通过 setIcon更换

1
2
3
QCommandLinkButton(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QCommandLinkButton(text: str, description: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QCommandLinkButton(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

description是QCommandLinkButton按钮上的功能性描述文本

设置描述性文本

方法 说明
setDescription(self, description: str) -> None 设置描述性文本
description(self) -> str 获取描述性文本

例子

image-20230319022716312

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:46
# File_name: 02-QCommandLinkButton例2.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import os

os.chdir(os.path.dirname(__file__))


class CommandLinkButtonDemo(QDialog):
def __init__(self, parent=None):
super(CommandLinkButtonDemo, self).__init__(parent)
layout = QVBoxLayout()
self.label_show = QLabel('显示按钮信息')
layout.addWidget(self.label_show)

self.button1 = QCommandLinkButton("默认按钮")
self.button1.setCheckable(True)
self.button1.toggle()
self.button1.clicked.connect(lambda: self.button_click(self.button1))
layout.addWidget(self.button1)

self.button_descript = QCommandLinkButton("描述按钮", '描述信息')
self.button_descript.clicked.connect(lambda: self.button_click(self.button_descript))
layout.addWidget(self.button_descript)

self.button_image = QCommandLinkButton('图片按钮')
self.button_image.setCheckable(True)
self.button_image.setDescription('设置自定义图片')
self.button_image.setIcon(QIcon("./images/python.png"))
self.button_image.clicked.connect(lambda: self.button_click(self.button_image))
layout.addWidget(self.button_image)

self.setWindowTitle("QCommandLinkButton demo")
self.setLayout(layout)

def button_click(self, button):
if button.isChecked():
self.label_show.setText('你按下了 ' + button.text() + " isChecked=True")
else:
self.label_show.setText('你按下了 ' + button.text() + " isChecked=False")


if __name__ == '__main__':
app = QApplication(sys.argv)
btnDemo = CommandLinkButtonDemo()
btnDemo.show()
sys.exit(app.exec())

复选框按钮控件QCheckBox

image-20230212175651574

1
2
QCheckBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QCheckBox(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

复选框按钮 QCheckBox是从 QAbstractButton类继承而来的,因此有 QAbstractButton的信号和方法

特有方法

方法及参数 说明
setTristate(y: bool=True) -> None 设置是否有不确定状态
isTristate() -> bool 获取是否有不确定状态
setCheckState(state: PySide6.QtCore.Qt.CheckState) -> None 设置选中状态
Qt.CheckState.Unchecked 没有选中
Qt.CheckState.PartiallyChecked 部分选中
Qt.CheckState.Checked 选中
checkState() 获取当前选择状态,返回值:
0-没有选中
1-不确定
2-选中
nextCheckState() 设置当前状态的下一个状态

信号

复选框按钮 QCheckBoxQAbstractButton多了一个 stateChanged(int)信号。

stateChanged(int)信号在状态发生改变时都会发送信号,而 toggled(bool)信号在从不确定状态转向确定状态时间不发送信号,其他信号相同。

如果过只有一个单选按钮可通过单击改变其选中状态,但多个单选按钮则必须选择其他单击按钮才能改变其选中状态。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import sys
import PySide6
from PySide6.QtCore import Qt.QPoint
from PySide6.QtGui import QAction, QIcon
from PySide6.QtWidgets import *


class win_demo(QWidget):
def __init__(self):
app=QApplication(sys.argv) # 初始化界面
super().__init__()

self.resize(500, 500)
self.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

self.demo_check_btn()

self.show() # 显示窗口以及其子控件
sys.exit(app.exec()) # 主循环和退出

def demo_check_btn(self):
check_btn1=QCheckBox("多选-选中", self)
check_btn2=QCheckBox("多选-未选中", self)
check_btn3=QCheckBox("多选-部分选中", self)

check_btn1.move(self.width() // 2 - 20, 20)
check_btn2.move(self.width() // 2 - 20, 50)
check_btn3.move(self.width() // 2 - 20, 80)

check_btn1.setCheckState(Qt.CheckState.Checked)
check_btn2.setCheckState(Qt.CheckState.Unchecked)
check_btn3.setCheckState(Qt.CheckState.PartiallyChecked)


if __name__=='__main__':
win_demo()

单选按钮控件QRadioButton

windows-radiobutton.png

QRadioButton是一个选项按钮,可以打开(选中)或关闭(未选中)。单选按钮通常为用户提供”众多”选项之一。在一组单选按钮中,一次只能选中一个单选按钮;如果用户选择另一个按钮,则先前选择的按钮将关闭。

默认情况下,单选按钮是自动排除的。如果启用了自动独占,则属于同一父构件的单选按钮的行为就像它们是同一独占按钮组的一部分一样。如果属于同一父小部件的单选按钮需要多个独占按钮组,请将它们放入 QButtonGroup中。

每当按钮打开或关闭时,它都会发出toggled() 信号。如果要在每次按钮更改状态时触发操作,连接到此信号。使用isChecked() 查看是否选择了特定按钮。

QPushButton一样,单选按钮显示文本,并可选择一个小图标。该图标使用setIcon() 设置。文本可以在构造函数中设置,也可以使用setText()设置。可以通过在文本中的首选字符前面加上与号来指定快捷键。

单选按钮控件 QRadioButton为用户提供多个选项,一般只能选择一个。

在一个容器中如果有多个单选按钮,那么这些单选按钮一般都是互斥的,选择其中一个单选按钮时,其它按钮都会取消选择。

1
2
QRadioButton(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QRadioButton(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

单选按钮控件 QRadioButton是从 QAbstractButton类继承而来的,因此有 QAbstractButton的信号和方法。

例子

image-20230319022947062

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:55
# File_name: 05-QRadio例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class Radiodemo(QWidget):
def __init__(self, parent=None):
super(Radiodemo, self).__init__(parent)
layout = QHBoxLayout(self)
self.label = QLabel('显示按钮按下信息')
self.label.setFixedWidth(120)
layout.addWidget(self.label)

# button1,button2未接管按钮
self.button1 = QRadioButton("按钮1")
self.button1.setChecked(True)
self.button1.toggled.connect(lambda: self.button_select(self.button1))
layout.addWidget(self.button1)

self.button2 = QRadioButton("按钮2")
self.button2.toggled.connect(lambda: self.button_select(self.button2))
layout.addWidget(self.button2)

# button3,button4 使用groupbox接管按钮
group_box1 = QGroupBox('QGroupbox', self)
layout_group_box = QVBoxLayout()
self.button3 = QRadioButton("按钮3")
self.button3.setChecked(True)
self.button3.toggled.connect(lambda: self.button_select(self.button3))
layout_group_box.addWidget(self.button3)

self.button4 = QRadioButton("按钮4")
self.button4.toggled.connect(lambda: self.button_select(self.button4))
layout_group_box.addWidget(self.button4)
group_box1.setLayout(layout_group_box)

layout.addWidget(group_box1)

# button5,button6 使用button_group接管按钮
button_group = QButtonGroup(self)
self.button5 = QRadioButton("按钮5")
self.button5.setChecked(True)
self.button5.toggled.connect(lambda: self.button_select(self.button5))
button_group.addButton(self.button5)
layout.addWidget(self.button5)

self.button6 = QRadioButton("按钮6")
self.button6.toggled.connect(lambda: self.button_select(self.button6))
button_group.addButton(self.button6)
layout.addWidget(self.button6)

self.setLayout(layout)
self.setWindowTitle("RadioButton demo")

def button_select(self, button):
if button.isChecked() == True:
self.label.setText(button.text() + " is selected")
else:
self.label.setText(button.text() + " is deselected")


if __name__ == '__main__':
app = QApplication(sys.argv)
radioDemo = Radiodemo()
radioDemo.show()
sys.exit(app.exec())

工具按钮QToolButton

1
QToolButton(self, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

参数:

  • arent – PySide6.QtWidgets.QWidget
  • 使用parent 构造一个空的工具按钮。

工具按钮是一种特殊按钮,可提供对特定命令或选项的快速访问。

普通命令按钮相反,工具按钮通常不显示文本标签,而是显示图标。当然可以同时设置文本和图标但是默认情况下都设置只显示图标。

工具按钮通常在使用创建新QAction实例addAction()或将现有操作添加到工具栏时创建addAction()。也可以用与任何其他小部件相同的方式构建工具按钮,并将它们与布局中的其他小部件一起排列。

工具按钮的一个经典用途是选择工具;例如,绘图程序中的”钢笔”工具。这将通过使用aQToolButton作为切换按钮来实现

QToolButton支持自动提升。在 auto-raise 模式下,按钮仅在鼠标指向它时绘制 3D 框架。当在QToolBar.改变它setAutoRaise()。

工具按钮的图标设置为QIcon。这使得为禁用和活动状态指定不同的像素图成为可能。当按钮的功能不可用时,将使用禁用的像素图。由于鼠标指针悬停在按钮上而自动抬起按钮时,会显示活动像素图。

按钮的外观和尺寸可以用setToolButtonStyle()和调整setIconSize()。当在 a 内使用QToolBar时QMainWindow,该按钮会自动调整为QMainWindow的设置(参见setToolButtonStyle()和setIconSize())。除了图标,工具按钮还可以显示箭头符号,用指定arrowType。

工具按钮可以在弹出菜单中提供额外的选择。可以使用设置弹出菜单setMenu()。用于setPopupMode()配置可用于具有菜单集的工具按钮的不同模式。默认模式是 DelayedPopupMode,它有时与网络浏览器中的”后退”按钮一起使用。按住按钮一段时间后,会弹出一个菜单,显示可能跳转到的页面列表。超时取决于样式,请参阅SH_ToolButton_PopupDelay。

按钮样式风格

方法 说明
toolButtonStyle() 返回类型 ToolButtonStyle 此属性保存工具按钮是仅显示图标、仅显示文本还是在图标旁边/下方显示文本。默认值为ToolButtonIconOnly。要使工具按钮的样式遵循系统设置,请将此属性设置为ToolButtonFollowStyle。在 Unix 上,将使用桌面环境中的用户设置。在其他平台上,ToolButtonFollowStyle仅表示图标。QToolButton自动将此插槽连接到所在位置的相关信号QMainWindow。
[slot]setToolButtonStyle(style: PySide6.QtCore.Qt.ToolButtonStyle) -> None 设置工具按钮是否仅显示图标、仅显示文本、文本显示在图标旁边/下方
style可选:
image-20230211233259599
Qt.ToolButtonStyle.ToolButtonTextOnly - 仅文本
Qt.ToolButtonStyle.ToolButtonIconOnly - 仅图标
Qt.ToolButtonStyle.ToolButtonTextBesideIcon - 文本在图标右侧
Qt.ToolButtonStyle.ToolButtonTextUnderIcon - 文本在图标下方
Qt.ToolButtonStyle.ToolButtonFollowStyle - 工具按钮跟随样式,遵循风格
initStyleOption(option) option-PySide6.QtWidgets.QStyleOptionToolButton使用此 QToolButton 中的值初始化选项。当子类需要 QStyleOptionToolButton 但不想自己填写所有信息时,此方法很有用。

图标箭头

方法 说明
setArrowType(type:PySide6.QtCore.Qt.ArrowType) 参数 输入-ArrowType 设置按钮是否显示箭头而不是普通图标。这会显示一个箭头作为QToolButton的图标。默认情况下,此属性设置为NoArrow。
type可选:
image-20230211231102613
Qt.ArrowType.NoArrow - 无箭头
Qt.ArrowType.UpArrow - 向上箭头
Qt.ArrowType.DownArrow - 向下箭头
Qt.ArrowType.LeftArrow - 向左箭头
Qt.ArrowType.RightArrow - 向右箭头
arrowType() 返回类型 ArrowType``此属性保存按钮是否显示箭头而不是普通图标。这会显示一个箭头作为 的图标QToolButton。默认情况下,此属性设置为NoArrow。

自动提升

方法 说明
autoRaise() 返回类型 布尔值``此属性保存是否启用自动提升(突起效果)。默认为禁用(即 false)。在自动提升模式下,该按钮仅在鼠标指向时才会绘制3D帧使用QMacStyle 时,此属性目前在 macOS 上被忽略。
setAutoRaise(enable:bool) 参数 启用- 布尔``此属性保存是否启用自动提升(突起效果)。默认为禁用(即 false)。在自动提升模式下,该按钮仅在鼠标指向时才会绘制3D帧.
在工具栏(QToolBar)中, 默认就是自动提升
使用QMacStyle 时,此属性目前在 macOS 上被忽略

设置样式例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import *


class win_demo(QWidget):
def __init__(self):
app=QApplication(sys.argv) # 初始化界面
super().__init__()

self.resize(500, 500)
self.setWindowFlags(Qt.WindowStaysOnTopHint) # 置顶

def creat_tool_btn(num, x):
tool_button=QToolButton(self)
tool_button.setText(str(num))
tool_button.setArrowType(Qt.ArrowType.UpArrow)
tool_button.move(x, 50)

return tool_button

tool_button1=creat_tool_btn(1, 10)
tool_button2=creat_tool_btn(2, 110)
tool_button3=creat_tool_btn(3, 210)
tool_button4=creat_tool_btn(4, 310)
tool_button5=creat_tool_btn(5, 410)

tool_button1.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextOnly)
tool_button2.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
tool_button3.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
tool_button4.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)
tool_button5.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonFollowStyle)

# qlabel.move((self.width() - qlabel.width()) // 2,(self.height() - qlabel.height()) // 2) # 居中展示文本

self.show() # 显示窗口以及其子控件
sys.exit(app.exec()) # 主循环和退出


if __name__=='__main__':
win_demo()

按钮菜单弹出模式

方法 说明
popupMode() 返回类型 ToolButtonPopupMode 此属性描述弹出菜单与工具按钮一起使用的方式。默认情况下,此属性设置为DelayedPopup。
setPopupMode(mode:QToolButton.ToolButtonPopupMode) 参数 模式——ToolButtonPopupMode 此属性描述弹出菜单与工具按钮一起使用的方式。默认情况下,此属性设置为DelayedPopup。
QToolButton.DelayedPopup:鼠标按住一会才显示 类似于浏览器后退按钮,点击clicked()信号不会发射 QToolButton.MenuButtonPopup:点击指示箭头才显示,只有点击左侧才会触发点击clicked()信号 QToolButton.InstantPopup:点了按钮就显示 点击clicked()信号不会发射

例子

image-20230319023125579

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 1:03
# File_name: 07-QToolButton例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import QToolButton, QMainWindow, QVBoxLayout, QHBoxLayout, QApplication, QWidget, QToolBar, QMenu, QLabel
import os

os.chdir(os.path.dirname(__file__))


class ToolButtonDemo(QMainWindow):

def __init__(self, parent=None):
super(ToolButtonDemo, self).__init__(parent)
self.setWindowTitle("QToolButton例子")
self.resize(800, 200)
self.label_show = QLabel('这里会显示按钮按下信息', self)
self.label_show.setGeometry(QRect(100, 100, 200, 30))

# 在QWidget中显示工具按钮
widget = QWidget(self)
widget.setGeometry(QRect(40, 30, 500, 60))
layout = QHBoxLayout()
widget.setLayout(layout)

# 文本工具按钮
tool_button = QToolButton(self)
tool_button.setText("工具按钮")
layout.addWidget(tool_button)

# 自动提升
tool_button_AutoRaise = QToolButton(self)
tool_button_AutoRaise.setText("工具按钮-AutoRise")
tool_button_AutoRaise.setAutoRaise(True)
layout.addWidget(tool_button_AutoRaise)

# 图片工具按钮
tool_button_pic = QToolButton(self)
tool_button_pic.setText("工具按钮-图片")
tool_button_pic.setIcon(QIcon("../../../Resources/Icons/python_96px.ico"))
tool_button_pic.setIconSize(QSize(22, 22))
tool_button_pic.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
layout.addWidget(tool_button_pic)

# 工具按钮+箭头
tool_button_arrow = QToolButton(self)
tool_button_arrow.setText("工具按钮-箭头")
tool_button_arrow.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
tool_button_arrow.setArrowType(Qt.UpArrow)
layout.addWidget(tool_button_arrow)

# 菜单工具按钮
tool_button_menu = QToolButton(self)
tool_button_menu.setText("工具按钮-菜单")
tool_button_menu.setAutoRaise(True)
layout.addWidget(tool_button_menu)

# 以下是为tool_button_menu添加menu信息。
menu = QMenu(tool_button_menu)
new_action = QAction("新建", menu)
new_action.setData('NewAction')
menu.addAction(new_action)
open_action = QAction("打开", menu)
open_action.setData('OpenAction')
menu.addAction(open_action)
menu.addSeparator()
# 添加子菜单
sub_menu = QMenu(menu)
sub_menu.setTitle("子菜单")
recent_action = QAction("最近打开", sub_menu)
recent_action.setData('RecentAction')
sub_menu.addAction(recent_action)
menu.addMenu(sub_menu)
tool_button_menu.setMenu(menu)
tool_button_menu.setPopupMode(QToolButton.InstantPopup)

# 工具按钮,嵌入到toolbar
toobar = self.addToolBar("File")
# 添加工具按钮1
tool_button_bar1 = QToolButton(self)
tool_button_bar1.setText("工具按钮-toobar1")
toobar.addWidget(tool_button_bar1)
# 添加工具按钮2
tool_button_bar2 = QToolButton(self)
tool_button_bar2.setText("工具按钮-toobar2")
tool_button_bar2.setIcon(QIcon("../../../Resources/Icons/power_48px.ico"))
tool_button_arrow.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
toobar.addWidget(tool_button_bar2)
# 添加其他QAction按钮
new = QAction(QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/plus.png"), "new", self)
toobar.addAction(new)
open = QAction(QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/folder.png"), "open", self)
toobar.addAction(open)

# 槽函数
tool_button.clicked.connect(lambda: self.button_click(tool_button))
tool_button_AutoRaise.clicked.connect(lambda: self.button_click(tool_button_AutoRaise))
tool_button_pic.clicked.connect(lambda: self.button_click(tool_button_pic))
tool_button_arrow.clicked.connect(lambda: self.button_click(tool_button_arrow))
tool_button_bar1.clicked.connect(lambda: self.button_click(tool_button_bar1))
tool_button_bar2.clicked.connect(lambda: self.button_click(tool_button_bar2))
tool_button_menu.triggered.connect(self.action_call)

def button_click(self, button):
self.label_show.setText('你按下了: ' + button.text())

def action_call(self, action):
self.label_show.setText('触发了菜单action: ' + action.data())


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = ToolButtonDemo()
demo.show()
sys.exit(app.exec())

按钮组QButtonGroup

1
QButtonGroup(self, parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None

继承自QObject类

提供一个抽象的按钮容器, 可以将多个按钮划分为一组,在有多组拥有互斥性的按钮时间使用,保证彼此独立互不影响。

  • 不具备可视化的效果
  • 一般放的都是可以被检查的按钮

QButtonGroup的API

方法 说明
addButton(Button:QAbstractButton,[id:int=-1]) 往按钮组添加按钮
id选填,如果id为-1,则将为该按钮分配一个id。自动分配的ID保证为负数,从-2开始。如果要分配自己的ID,请使用正值以避免冲突
button(ID:int) 根据ID获取对应按钮, 没有则返回None。ID为addButton添加时设置的值
checkedId() 按钮组当前选中的按钮的ID,如果没有选中按钮则返回-1
buttons() 查看所有按钮组中的按钮
checkedButton() 获取选中按钮
id(Button:QAbstractButton) 获取按钮组中指定按钮对象的id,传入按钮对象
setId(Button:QAbstractButton,id:int) 设置按钮组已有组员的id
setExclusive(bool) 统一设置按钮组中的按钮是否互斥
exclusive() 获取按钮组内所有按钮是否互斥
removeButton(Button:QAbstractButton) 从按钮组移除指定按钮

信号

信号 说明
buttonClicked(button:QAbstractButton) 当按钮组中的按钮被点击时, 发射此信号,传递参数为按钮对象
buttonPressed(QAbstractButton) 当按钮组中的按钮被按下时, 发射此信号,传递参数为按钮对象
buttonReleased(QAbstractButton) 当按钮组中的按钮被释放时, 发射此信号,传递参数为按钮对象
buttonToggled(QAbstractButton, bool) 当按钮组中的指定按钮切换到指定选中状态时, 发射此信号
QAbstractButton:指定按钮对象
bool:指定选中状态,如果选中该按钮则为true,如果未选中该按钮则为false。
idClicked(id:int) 当按钮组中的按钮被点击时, 发射此信号,,传递参数为按钮对象在按钮组的id
idPressed(id:int) 当按钮组中的按钮被按下时, 发射此信号,,传递参数为按钮对象在按钮组的id
idReleased(id:int) 当按钮组中的按钮被释放时, 发射此信号,,传递参数为按钮对象在按钮组的id
idToggled(id:int, bool) 当按钮组中的指定id的按钮切换到指定选中状态时, 发送此信号。
id:参按钮对象在按钮组的id
bool:指定选中状态,如果选中该按钮则为true,如果未选中该按钮则为false。

信号发射可选参数为int(按钮组内按钮id值),或按钮对象

信号默认传递的是按钮对象,通过如下方式可获取指定类型也可获取到按钮对象后通过按钮组的 id(Button:QAbstractButton)方法获取 id

PYqt5库没有下面几个id类型的信号,可通过 buttonClicked[int](button:QAbstractButton)直接获取id

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *

app = QApplication(sys.argv)

window = QWidget()
window.setWindowTitle("QButtonGroup的使用")
window.resize(500, 500)
window.move(400, 250)

rb_male = QRadioButton("男", window)
rb_male.move(100, 100)
rb_female = QRadioButton("女", window)
rb_female.move(180, 100)

sex_group = QButtonGroup(window)
sex_group.addButton(rb_male) # 把rb_male按钮添加到sex_group按钮组
sex_group.addButton(rb_female) # 把rb_female按钮添加到sex_group按钮组

rb_yes = QRadioButton("yes", window)
rb_yes.move(100, 220)
rb_no = QRadioButton("no", window)
rb_no.move(180, 220)

answer_group = QButtonGroup(window)
answer_group.addButton(rb_yes)
answer_group.addButton(rb_no)

"""
男、女属于同一按钮组,互斥,只能选中其中之一
yes、no属于另一按钮组,不受男女的影响
"""

window.show()

sys.exit(app.exec())

按钮菜单

可通过 QPushButtonQToolButton或重写 QAbstractButton配合 QMenu实现按钮菜单功能

QMenu实例化

1
2
QMenu(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QMenu(title: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

QAction实例化

1
2
3
QAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None
QAction(parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None
QAction(text: str, parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None

按钮对象添加菜单

方法 说明
button.setMenu(QMenu) 设置菜单
button.menu() 获取菜单
button.showMenu() 弹出菜单

QMenu API

菜单QMenu的常用方法如表所示。菜单的主要方法是在菜单列表中添加动作、子菜单和分隔条,主要方法介绍如下:

  • addAction(QAction)方法可以添加一个已经定义好的动作;用addAction(text:str)addAction(icon:QIcon,text:str)方法可以添加一个新创建的动作,并返回动作,其中text是动作在菜单中的名称,icon是图标。
  • addMenu(QMenu)方法可以将已定义好的菜单作为子菜单加入到菜单中;用addMenu(title:str)方法或 addMenu(icon:QIcon,title:str)方法可以添加新的子菜单,并返回子菜单。
  • addSection(text:str)addSection(icon: QIcon,text: str)addSeparator()方法可以添加分隔条,并返回对应的动作。分隔条的显示样式与操作系统有关,例如忽略动作的名称、图标或子菜单,或者显示成横线或名称。利用分隔条返回的动作,用动作的setSeparator(bool)方法可以将分隔条切换成动作,或者将动作切换成分隔条。
  • setTearOffEnabled(bool)方法可以将菜单定义成可撕扯菜单,可撕扯菜单在其动作列表中显示一条虚线,单击该虚线可以把菜单及动作列表弹出;用showTearOffMenu()方法或 showTearOffMenu(QPoint)方法可以将可撕扯菜单在指定位置显示。
  • popup(pos: QPoint,at: QAction-None)方法或 exec(pos: QPoint,at:QAction-None)方法可以在指定位置(全局坐标系)弹出菜单,如果指定了at参数,则指定的动作显示在指定位置。

addActionaddMenuaddSection用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
addAction用法
addAction(action: PySide6.QtGui.QAction) -> None
addAction(arg__1: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, arg__3: object, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int, NoneType]=None) -> None
addAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str) -> PySide6.QtGui.QAction
addAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, callable: object) -> PySide6.QtGui.QAction
addAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, receiver: PySide6.QtCore.QObject, member: bytes, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int]) -> PySide6.QtGui.QAction
addAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, receiver: PySide6.QtCore.QObject, member: bytes, type: PySide6.QtCore.Qt.ConnectionType=Instance(Qt.AutoConnection)) -> PySide6.QtGui.QAction
addAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int]) -> PySide6.QtGui.QAction
addAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int], callable: object) -> PySide6.QtGui.QAction
addAction(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int], receiver: PySide6.QtCore.QObject, member: bytes, type: PySide6.QtCore.Qt.ConnectionType=Instance(Qt.AutoConnection)) -> PySide6.QtGui.QAction
addAction(text: str) -> PySide6.QtGui.QAction
addAction(text: str, arg__2: object, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int, NoneType]=None) -> None
addAction(text: str, callable: object) -> PySide6.QtGui.QAction
addAction(text: str, receiver: PySide6.QtCore.QObject, member: bytes, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int]) -> PySide6.QtGui.QAction
addAction(text: str, receiver: PySide6.QtCore.QObject, member: bytes, type: PySide6.QtCore.Qt.ConnectionType=Instance(Qt.AutoConnection)) -> PySide6.QtGui.QAction
addAction(text: str, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int]) -> PySide6.QtGui.QAction
addAction(text: str, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int], callable: object) -> PySide6.QtGui.QAction
addAction(text: str, shortcut: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int], receiver: PySide6.QtCore.QObject, member: bytes, type: PySide6.QtCore.Qt.ConnectionType=Instance(Qt.AutoConnection)) -> PySide6.QtGui.QAction


addMenu用法
addMenu(self, icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], title: str) -> PySide6.QtWidgets.QMenu
addMenu(self, menu: PySide6.QtWidgets.QMenu) -> PySide6.QtGui.QAction
addMenu(self, title: str) -> PySide6.QtWidgets.QMenu


addSection用法
addSection(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str) -> PySide6.QtGui.QAction
addSection(text: str) -> PySide6.QtGui.QAction

QMenu常用API

方法 说明
menu.addMenu() --> PySide6.QtGui.QAction 在菜单中添加子菜单
menu.addAction(QAciton) 添加已有动作
menu.addAction(text:str) 在菜单中添加新的动作并设置文字
menu.addAction(icon:QIcon, text:str) 同上但设置图标和文字
addActions(actions: Sequence[PySide6.QtGui.QAction]) -> None 添加多个行为动作
menu.addSeparator(self) -> PySide6.QtGui.QAction 添加分割线
menu.addSection(text:str) -> PySide6.QtGui.QAction 添加分割条
menu.addSection([icon:PySide6.QtGui.QIcon], text:str) -->PySide6.QtGui.QAction 添加分割条
部件样式可以在呈现部分时使用文本和图标信息,也可以选择忽略它们并像简单分隔符一样呈现部分
menu.setTitle(str) 给菜单添加文字
menu.setIcon(QIcon) 给菜单添加图标

发现添加行为动作时需要严格按照说明传参数不然报各种错

QAction常用API

方法 说明
QAction.setTitle(str) 给动作添加文字提示
QAction.setIcon(QIcon) 给动作添加提示
[signal]triggered(QAction *action) 当点击某个action时触发, 并会将action传递出来
QAction对象可以通过 setData(Any):绑定数据 data():获取数据

按钮菜单例子

image-20230319023934398

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:02
# File_name: 实例.py


import sys

from PySide6.QtGui import QAction
from PySide6.QtWidgets import *

app = QApplication(sys.argv)
window = QWidget()

btn = QPushButton("xxx", window)

# 菜单的设置
# 首先创建一个menu对象
menu = QMenu()
# menu后可以添加行为、分割线、图标、子菜单等,可以进入类中查看方法
# 子菜单 最近打开
# 行为动作 新建 打开 分割线 退出
# 方案一
# new_action = QAction()
# new_action.setText("新建")
# 方案二
new_action = QAction("新建", menu)
# 监听行为的信号
new_action.triggered.connect(lambda: print("新建文件"))
open_action = QAction("打开", menu)
open_action.triggered.connect(lambda: print("打开文件"))
exit_action = QAction("退出", menu)
exit_action.triggered.connect(lambda: print("退出文件"))

# 子菜单
oprn_recent_menu = QMenu(menu)
oprn_recent_menu.setTitle("最近打开")
file_action = QAction("python-pyqt")
oprn_recent_menu.addAction(file_action)

menu.addAction(new_action)
menu.addAction(open_action)
menu.addSeparator()
menu.addMenu(oprn_recent_menu)

menu.addAction(exit_action)

# 给按钮后添加菜单
btn.setMenu(menu)
# 菜单的获取
# print(btn.menu())

window.setWindowTitle("按钮的功能")
window.resize(500, 500)

window.show()
# 菜单的显示
# menu.show()
sys.exit(app.exec())

输入和显示

输人输出控件用于向程序输入数据、显示程序输出的数据,输人输出控件是可视化编程最基本的控件

单行文本控件QLineEdit

图形界面上需要输入信息,与程序进行沟通,输人数据信息的控件有单行文本控件、多行文本控件数值输人控件。单行文本输入控件是QLineEdit,继承自QWidget。

可视化应用程序需要在界面上输入数据和显示数据。QLineEdit 控件是单行文本编辑器.用于接收用户输入的字符串数据,并显示字符串数据,输人的整数和浮点数也会当作字符串数据。

可以利用int()和 float()函数将字符串型整数和浮点数转换成整数和浮点数

用QLineEdit类创建单行文本控件的方法如下其中parent是QLineEdit 所在的窗口或容器类控件,text 是显示的文字。

1
2
3
4
from PySide6.QtWidgets import QLineEdit

QLineEdit(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QLineEdit(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

单行文本控件QLineEdit 的常用方法

QLineEdit 控件可以用于密码输人,可以进行复制粘贴、删除等操作。单行文本控件QLineEdit 的常用方法如表所示

主要方法介绍

QLineEdit的方法及参数类型 返回值的类型 说明
[slot]setText(str) None 设置文本内容
insert(str) None 在光标处插人文本
text() str 获取真实文本,而不是显示的文本
displayText() str 获取显示的文本
setMask(QBitmap) None 设置遮掩图像
setModified(bool) None 设置文本更改状态
setPlaceholderText(str) None 设置占位符
placeholderText() str 获取占位符
setClearButtonEnabled(bool) None: 设置是否有清空按钮
isClearButtonEnabled() bool 获取是否有清空按钮
setMaxLength(int) None 设置文本的最大长度
maxLength() int 获取文本的最大长度
setReadOnly(bool) None 设置只读模式,只能显示,不能输人
setAlignment(Q1.Alignment) None 设置对齐方式
setFrame(bool) None 设置是否显示外框
backspace() None 删除光标左侧或选中的文字
isModified() bool 获取文本是否被更政
isReadOnly() bool 获取是否只读模式
del() None 删除光标右侧或选中的文字
[slot]clear() None 删除所有内容
[slot]copy() None 复制选中的文本
[slot]cut() None 剪切选中的文字
[slot]paste() None 粘贴文字
isUndoAvailable() bool 是否可以撤销操作
[slot]undo() None 撤销操作
isRedoAvailable( None 是否可以恢复撤销操作
[slot]redo() None 恢复撤销操作
setDragEnabled(bool) None 设置文本是否可以拖放
setEchoMode(QLineEdit.EchoMode) None 设置显示模式
setTextMargins(QMargins) None 设置文本区域到外框的距离
setCompleter(QCompleter) None 设置辅助补全的内容
  • 由于单行文本控件可以用于输入密码,其显示的内容并不一定是输人的内容。用setText(str)方法设置文本内容,

    • 用text)方法获取真实的文本而不是界面上显示的文本,例如在密码输人模式下,得到的是输人的密码,而不是界面上显示的掩码
    • 用displayText()方法获取显示的文本内容。
  • 用setEchoMode(QLineEdit.EchoMode)方法可以设置成密码输入方式,其中QLineEditEchoMode的取值是枚举类型,可以设置的值如表所示

    QLineEdit.EchoMode的取值 说 明
    QLineEdit.Normal 0 正常显示输入的字符,这是默认值
    QLineEdit.NoEcho 1 输入文字时不显示任何输入,文字内容和个数都不可见,常用于密码保护 i
    QLineEdit.Password 2 显示密码掩码,不显示实际输入的字符,能显示字符个数
    OLineEdit.PasswordEchoOnEdit 3 在编辑的时候显示字符,不编辑的时候显示掩码
  • setPlaceholderText()是在 QLineEdit 中灰色显示的字符常用于提示信息,例如setPlaceholderText(“请输人密码”)。当输人真实文字时,不再显示提示信息。

  • QLineEdit 中输人的数据有时只能为整数,有时只能为点数,这时就需要对输人的数据进行合法性检验。

    • QLineEdit 的合法性检验用setValidator(QValidator)方法它的参数是一个QValidator类,QValidator 类用来检查输人内容的合法性,当输人内容合法时,才能成功输人并在输人框中显示。
    • QValidator 是一个抽象类其子类QIntValidator,QDoubleValidator分别用来设置合法整数和合法浮点数,还有一个子类QRegExpValidator 结合正则表达式来判断输人的合法性。
      • QIntValidator 设置整数范围的下限和上限,其使用方法是QIntValidator(int,int,parent=None),其中第1个int是下限,第2个int是上限;
        • 用QIntValidator的setRange(int,int)、setBottom(int)和 setTop(int)方法来设置下限和上限,
        • 例如 QLineEdit.setValidator(QIntValidator(0,100))可以设置 QLineEdit 只能输人0到100的整数。
      • QDoubleValidator
        • 使用方法是 QDoubleValidator(float,float,int,parent=None),其中第 1个float 参数是下限第2个at 参数是上限int 是小数的位数
          • 同样也可通过 setRange(float,float, int)、setBottom(float)、setTop(float)和setDecimals(int)方法来设置下限、上限和小数位数。
  • 在QLineEdit 中输入数据时,可以有辅助性的提示信息帮助快速完成输入

    • 用setCompleter(QCompleter)方法设置辅助补全的内容,其中QCompleter 是辅助补全的类。

      - 创建辅助补全的方法为 
      QCompleter(cornpletions:Sequence[str],parent:QObject=None)
      QCompleter(model: QAbstractItemModel,parent; QObject=None)
      QCompleter(parent: QObject]=None)
      用QCompleter 的 setModel(QAbstractItemModel)方法设置数据模型有关数据模型的内容参见第5章。
      
      • 用setCompletionMode(mode:QCompleter,CompletionMode)方法设置模式,其中枚举类型QCompleter.CompletionMode可以取:

        • QCompleter,PopupCompletion(弹窗模式)
        • QCompleter.InlineCompletion(输框内选中模式)
        • QCompleter.UnfilteredPopupCompletion(以弹窗模式列出所有可能的选项)

        用代码在QLineEdit 中插人文字或选择文字时,需要定位光标的位置,获取或移动光标的方法如表所示。

        QLineEdit的光标方法 说明
        cursorBackward(mark=True,steps=1) 向左移动step个字符,mark为True时带选中效果
        cursorForward(mark=True,steps=1) 向右移动step个字符,mark为True时带选中效果
        cursorWordBackward(mark=True) 向左移动一个单词的长度,mark为True时带选中效果
        cursorWordForward(mark=True) 向右移动一个单词的长度,mark为True时带选中效果
        home(mark=True) 光标移动至行首,mark为True时带选中效果
        end(mark=True) 光标移动至行尾,mark为True时带选中效果
        setCursorPosition(int) 光标移动至指定位置
        cursorPosition() 获取光标位萱,返回值是int
        cursorPositionAt(OPoint) 获取指定位置处光标位置,返回值是int
  • 对 QLineEdit 中的文本可以进行复制粘贴删除等操作,一般都需要先选择文本然后再操作。选择文本的方法如表所示。

    文本选择方法 说明
    setSelection(int, int) 选择指定范围内的文本
    [slot]selectAll() 选择所有的文本
    deselect() 取消选择
    hasselectedText() 是否有选择的文本
    selectionLength() 获取选择的文本的长度
    selectionStart() 获取选择的文本的起始位置
    selectionEnd( 获取选择的文本的终止位置
    selectedText() 获取选择的文本
  • 对于需要输人固定格式的文本,例如 IP 地址、MAC 地址License 序列号,可以用setInputMask()方法来定义这种固定的格式。

    • 例如 setInputMask(“000.000.000.000”)和setInputMask(“000.000.000.000;_”)方法都可以输人IP地址。后者在未输入字符的位置用下划线来表示空位;

    • setInputMask(“HH:HH:HH:HH:HH:HH”)和 setInputMask(“HH,HH:HH:HH:HH:HH;”)方法都可以输MAC地址;

    • setInputMask(“0000-00-00”)方法可以输入ISO标准格式日期,

    • setInputMask(“>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#”)方法可以用于输人 License 序列号,所有字母转换为大写。可以用于格式化输入的字符如表所示

      字符 含义
      A ASCI字母是必需的,取值范围为A2、az
      a ASCI字母是允许的,但不是必需的
      N ASCII字母和数字是必需的,取值范围为AZ,az,0-9
      n ASCI字母和数字是允许的,但不是必需的
      X 任何字符都是必需的
      x 任何字符都是允许的,但不是必需的
      9 ASCI数字是必需的,取值范围为0~9
      0 ASCII数字是允许的,但不是必需的
      D ASCII数字是必需的,取值范围为1-9
      d ASCII数字是允许的,但不是必需的,取值范围为1~9
      # ASCII数字或加/减符号是允许的,但不是必需的
      H 十六进制数据字符是必需的,取值范围为AF、af,0-9
      h 十六进制数据字符是允许的,但不是必需的
      B 二进制数据字符是必需的,取值为0、1
      b 二进制数据字符是允许的,但不是必需的
      > 所有的字符字母都大写
      < 所有的字符字母都小写
      ! 关闭大小写转换
      \ 使用\去转义上述列出的特殊字符
      ;c 终止输入遮掩,并把空余输入设置成c

文本的设置和获取

  • setText(str) 设置内容文本
  • insert(newText) 在光标处插入文本
  • text() 获取真实内容文本
  • displayText() 获取用户能看到的内容文本

输出模式

  • setEchoMode(QLineEdit.EchoMode)
    • QLineEdit.EchoMode
      • NoEcho=1 不输出
      • Normal=0 正常输出
      • Password=2 密文形式
      • PasswordEchoOnEdit=3 编辑时明文, 结束后密文
  • echoMode() -> QLineEdit.EchoMode 获取输出模式

灰色输入提示字符串(占位文本)

  • setPlaceholderText(notice_str) 设置灰色提示字符串
  • placeholderText() 获取灰色提示字符串

清空按钮显示

用作快速清空文本框内容,实现快速清空已输入信息

  • setClearButtonEnabled(bool) 设置是否添加清空
  • isClearButtonEnabled() -> bool 是否添加清空

添加操作行为

常用于用于密码输入框的明文密文输入切换。

  • addAction(QAction, QLineEdit.ActionPosition)
    • QLineEdit.ActionPosition 添加动作放的位置
      • QLineEdit.LeadingPosition 搁前面
      • QLineEdit.TrailingPosition 搁后面
  • addAction(QIcon, QLineEdit.ActionPosition) -> QAction 添加动作,同菜单的addAction方法

自动补全

设置当输入部分文文本下拉框提示完整文本,类似于QQ登录时输入登录账号不需要输入完整账号名称就提示历史已输入账号名称

  • setCompleter(QCompleter) 设置完成器

    • completer() -> QCompleter 完成器对象

      • 导入:from PySide6.QtWidgets import QCompleter

      • 实例化:

      • QCompleter(completions: Sequence[str], parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None 
        
        QCompleter(model: PySide6.QtCore.QAbstractItemModel, parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None 
        
        QCompleter(parent: Union[PySide6.QtCore.QObject, NoneType]=None) -> None
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36

        - 例子:

        ![image-20230222230249259](https://sixsixsixpeng.gitee.io/my_pictures/202302222302117.png)

        ```python
        import sys
        from PySide6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QCompleter


        class win_demo(QWidget):
        def __init__(self, parent=None):
        super().__init__(parent)
        self.set_windows()
        self.business_demo()

        def set_windows(self):
        self.resize(300, 300) # 设置窗口大小
        self.setWindowTitle("hello world") # 设置窗口标题

        def business_demo(self):
        line_edit=QLineEdit(self)

        # 创建完成器对象,第一个参数需要用字符串即使输入的是数字
        completer=QCompleter(["123", "234", "235", "345", "356", "456", "457", "1234"], self)

        # 设置完成其
        line_edit.setCompleter(completer)


        if __name__=='__main__':
        app=QApplication(sys.argv)
        win=win_demo()

        win.show()
        sys.exit(app.exec())

输入限制

限制用户在文本框中输入的内容

  • 内容长度限制

    • setMaxLength(int) 设置限制输入的最大长度
    • maxLength() 获取输入最大长度
  • 只读限制

    • setReadOnly(bool)
    • isReadOnly()
  • 规则验证

    setValidator(QValidator) 设置验证器

    • QValidator 验证器 用于验证用户输入数据的合法性,下面单独说明

    • setInputMask(mask_str) 掩码验证

  • 判定输入文本是否通过验证

    • hasAcceptableInput()
QValidator验证器

如果一个输入框设置了验证器,用户在文本框中输入内容时,首先会将内容传递给验证器验证方法(validate)进行验证:validate(self, input_text, pos)

  • return QValidator.State.Acceptable, input_text, pos_int #验证通过
  • return QValidator.State.Intermediate, input_text, pos_int #暂不作判定是否通过验证,用于输入过渡时不做判断
  • return QValidator.State.Invalid, input_text, pos_int #验证不通过

如果输入框结束输入后, 上述的验证状态并非有效, 则会调用修复方法fixup(self, input_text)

  • return 修正后文本,
  • 返回修正后的的文本还会再次调用validate验证

是一个抽象类, 使用前需要进行子类化操作

  • 自定义子类
    • 需要实现validate方法
    • 修复方法fixup可以根据需要选择是否进行实现,当validate验证不通过时会把输入字符传给fixup进行修复。
  • 系统提供子类
    • QIntValidator(bottom, top, parent) 限制整型数据范围
    • QDoubleValidator 浮点类型数据限制范围 经测试, 无效 需要手动实现
    • QRegExpValidator 通过正则表达式限定

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import sys

from PySide6.QtGui import QValidator
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QCompleter


class IntValidator60(QValidator):
"""验证输入整数且60-80"""

def validate(self, input_text: str, pos_int: int) -> object:
"""验证方法"""
try:
if input_text=="":
return QValidator.State.Intermediate, input_text, pos_int # 暂不作判定是否通过验证
# return QValidator.State.Acceptable, input_text, pos_int # 验证通过
elif 1 <=int(input_text) <=17:
return QValidator.State.Intermediate, input_text, pos_int # 暂不作判定是否通过验证
elif any([80 > int(input_text), int(input_text) > 180]):
return QValidator.State.Invalid, input_text, pos_int # 验证不通过
else:
return QValidator.State.Acceptable, input_text, pos_int # 验证通过
except(ValueError, BaseException):
return QValidator.State.Invalid, input_text, pos_int # 验证不通过

def fixup(self, arg__1: str) -> str:
"""修复方法"""
print(f"修复方法传入{arg__1},验证不通过,但是强制修复通过了")
return "100"


class IntValidator30(QValidator):
"""验证输入整数且30-40"""

def validate(self, input_text: str, pos_int: int) -> object:
"""验证方法"""
try:
if input_text in["3", ""]:
return QValidator.State.Intermediate, input_text, pos_int # 暂不作判定是否通过验证
elif input_text=="":
return QValidator.State.Acceptable, input_text, pos_int # 验证通过
elif any([40 < int(input_text), int(input_text) < 10]):
return QValidator.State.Invalid, input_text, pos_int # 验证不通过
else:
return QValidator.State.Acceptable, input_text, pos_int # 验证通过
except(ValueError, BaseException):
return QValidator.State.Invalid, input_text, pos_int # 验证不通过


class win_demo(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.set_windows()
self.business_demo()

def set_windows(self):
self.resize(300, 300) # 设置窗口大小
self.setWindowTitle("hello world") # 设置窗口标题

def business_demo(self):
line_60_180=QLineEdit(self)
line_60_180.setPlaceholderText("输入60-180,有修复方法")

line_30_40=QLineEdit(self)
line_30_40.setPlaceholderText("输入30-40,无修复方法")
line_30_40.move(0, line_60_180.height())

# 设置验证器
line_60_180.setValidator(IntValidator60())
line_30_40.setValidator(IntValidator30())


if __name__=='__main__':
app=QApplication(sys.argv)
win=win_demo()

win.show()
sys.exit(app.exec())

是否被编辑

标识文本内容是否被修改过

  • isModified() 获取文本是否原始状态(一般为空白)
  • setModified(bool) 设置当前为原始状态(即使修改过内容也会更改状态,但不会修改文本)

光标控制

控制光标, 以及文本选中操作

  • cursorBackward(mark:bool ,steps :int=1) 向后(左)移动steps个字符
    • mark: bool 是否带选中效果
  • cursorForward(mark:bool ,steps :int=1) 向前(右)移动steps个字符
    • mark: True 是否带选中效果
  • cursorWordBackward(bool mark) 向后(左)移动一个单词长度(以空格为间隔)
    • mark: True 是否带选中效果
  • cursorWordForward(bool mark) 向前(右)移动一个单词长度(以空格为间隔)
    • mark: True 是否带选中效果
  • home(bool) 移动到行首
    • bool标识是否带选中效果
  • end(bool) 移动到行尾
    • bool标识是否带选中效果
  • setCursorPosition(int) 设置光标位置
  • cursorPosition() 获取光标位置
  • cursorPositionAt(pos: PySide6.QtCore.QPoint) 获取指定坐标位置对应文本光标位置

文本边距设置

实际作用是在指定空间内 左右调整输入区域,上下以中心为原点调整文字位置

  • setTextMargins(left: int,top: int,right: int,bottom: int) 设置文本内容边距
  • getTextMargins() 获取文本内容边距

对齐方式

设置用户输入的内容文本对齐方式

setAlignment(Qt.Alignment) 设置输入文本的对齐方式

可通过|连接水平和垂直参数同时设置两个方向对齐方式。

  • Qt.Alignment
    • 水平方向
      • Qt.AlignLeft
      • Qt.AlignRight
      • Qt.AlignHCenter
      • Qt.AlignJustify 自适应
    • 垂直方向
      • Qt.AlignTop
      • Qt.AlignBottom
      • Qt.AlignVCenter
      • Qt.AlignBaseline
    • 居中对齐
      • Qt.AlignCenter 垂直和水平都居中,等同于 Qt.AlignHCenter | Qt.AlignVCenter

常用编辑功能

方法 说明
backspace() 退格,删除选中文本(如果有)或删除光标左侧一个字符
del_() 删除选中文本(如果有)或删除光标右侧一个字符
clear() 清空,删除所有文本框内容
copy() 复制选中文本
cut() 剪切选中文本
paste() 粘贴已复制文本
isUndoAvailable() -> bool 判断当前是否可以撤销
undo() 撤消
isRedoAvailable() -> bool 判断当前是否可以重做
redo() 重做
setDragEnabled(bool) 设置选中文本后是否可以拖拽到其他位置
setSelection(start_pos, length) 选中指定区间的文本
setSelection(start_pos, length) 选中指定区间的文本
selectAll() 选中所有文本
deselect() 取消选中已选择文本
hasSelectedText() 是否有选中文本
selectedText() -> str 获取选中的文本
selectionStart() -> int 选中的开始位置
selectionEnd() -> int 选中的结束位置
selectionLength() -> int 选中的长度

单行文本控件QLineEdit 的信号

QLineDdit 的信号及参数类型 说 明
textEdited(tex: str) 文本被编辑时发送信号,不适用setText()方法引起的文本改变
textChanged(text: str) 文本发生变化时发送信号,包括setIext()方法引起的文本改变
returnPressed() 按 Enter键时发送信号
editingfinished() 按 Enter或失去焦点时发送信号
cursorPostionChanged(oldPosr int,newPos: int) 光标位置发生变化时发送信号,第1个参数是光标原位置,第2个参 数是光标移动后的位置
selectionChanged) 选中的文本发生变化时发送信号
inputRejectedO 拒绝输入时发送信号

单行文本控件QLineEdit的应用实例

下面的程序建立一个学牛考试成绩查询的界面如图所示。在界面中输人名和准考证号,单击”查询”按钮,可以显示查找的学生成绩,如果查不到,会显示”查无此人”,单击”清空”按钮删除输入的姓名、准考证号和查询到的成绩。

image-20230221213122102

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QLineEdit
from PySide6.QtGui import QFont, QIntValidator
from PySide6.QtCore import QRect
import sys


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("生成绩查询系统")
self.setGeometry(400, 200, 480, 370)
self.setupUi()

self.__data=[[202003, '没头脑', 89, 88, 93, 87],
[202002, '不高兴', 80, 71, 88, 98],
[202004, '倒惩蛋', 95, 92, 88, 94],
[202001, "鸭梨头", 93, 84, 84, 77],
[202005, "墙头草", 93, 86, 73, 86]] # 学生信息和成绩,可从文件读取

def setupUi(self): # 创建界面上的控件
self.label_1=QLabel(self)
self.label_1.setGeometry(QRect(120, 40, 231, 31))
font=QFont("楷体", pointSize=20)
self.label_1.setFont(font)
self.label_1.setText("学生考试成绩查询")

self.label_2=QLabel(self)
self.label_2.setGeometry(QRect(113, 130, 60, 20))
self.label_2.setText("姓名(&N);")

self.label_3=QLabel(self)
self.label_3.setGeometry(QRect(100, 160, 70, 20))
self.label_3.setText("准考证号(&T)")

self.label_4=QLabel(self)
self.label_4.setGeometry(QRect(100, 260, 100, 20))
self.label_4.setText("查询结果如下;")

self.lineEdit_name=QLineEdit(self)
self.lineEdit_name.setGeometry(QRect(190, 130, 113, 20))
self.lineEdit_name.setClearButtonEnabled(True)

# 设置"清空"按钮
self.lineEdit_number=QLineEdit(self)
self.lineEdit_number.setGeometry(QRect(190, 160, 113, 20))
self.lineEdit_number.setValidator(QIntValidator(202001, 202100)) # 设置验证
self.lineEdit_number.setEchoMode(QLineEdit.EchoMode.Password) # 设置密码形式
self.lineEdit_number.setClearButtonEnabled(True) # 设置"清空"按钮
self.lineEdit_results=QLineEdit(self)
self.lineEdit_results.setGeometry(QRect(70, 300, 321, 20))

self.lineEdit_results.setReadOnly(True) # 设置只读属性

self.label_2.setBuddy(self.lineEdit_name) # 伙伴关系
self.label_3.setBuddy(self.lineEdit_number) # 伙伴关系
self.btn_enquire=QPushButton(self)
self.btn_enquire.setGeometry(QRect(150, 210, 75, 23))
self.btn_enquire.setText("查询(&E)")
self.btn_enquire.clicked.connect(self.inquire) # 信号与槽的连接

self.btnClear=QPushButton(self)
self.btnClear.setGeometry(QRect(240, 210, 81, 23))
self.btnClear.setText("清空(&C)")
self.btnClear.clicked.connect(self.lineEdit_name.clear) # 信号与槽的连接
self.btnClear.clicked.connect(self.lineEdit_number.clear) # 信号与槽的连接
self.btnClear.clicked.connect(self.lineEdit_results.clear) # 信号与槽的连接
self.lineEdit_name.textChanged.connect(self.text_changed) # 信号与槽的连接
self.lineEdit_number.textChanged.connect(self.text_changed) # 信号与槽的连接
self.text_changed()

def inquire(self):
number=int(self.lineEdit_number.text())
template="{}的考试成绩:语文{} 数学{} 英语{} 物理{}"
for i in range(len(self.__data)):
stu=self.__data[i]
if stu[0]==number and stu[1]==self.lineEdit_name.text():
self.lineEdit_results.setText(template.format(stu[1], stu[2], stu[3], stu[4], stu[5]))
break
else:
if i==len(self.__data) - 1:
self.lineEdit_results.setText("查无此人")

def text_changed(self):
if self.lineEdit_number.text() !="" and self.lineEdit_name.text() !="":
self.btn_enquire.setEnabled(True)

else:
self.btn_enquire.setEnabled(False)

if self.lineEdit_number.text() !="" or self.lineEdit_name.text() !="":
self.btnClear.setEnabled(True)
else:
self.btnClear.setEnabled(False)


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWidget()

win.show()
sys.exit(app.exec())

键位序列编辑keySequenceEdit

控件允许允许用户选择QKeySequence,它通常用作快捷方式。当小部件接收到焦点时开始录制,并在用户释放最后一个键后一秒结束录制。

keySequenceEdit直接继承自QtWidgets

1
2
3
4
5
6
7
8
from PySide6.QtGui import QKeySequence

QKeySequence(self) -> None
QKeySequence(k1: int, k2: int=0, k3: int=0, k4: int=0) -> None
QKeySequence(k1: Union[PySide6.QtCore.QKeyCombination, PySide6.QtCore.Qt.KeyboardModifier, PySide6.QtCore.Qt.Key], k2: Union[PySide6.QtCore.QKeyCombination, PySide6.QtCore.Qt.KeyboardModifier, PySide6.QtCore.Qt.Key]=Instance(QKeyCombination.fromCombined(0)), k3: Union[PySide6.QtCore.QKeyCombination, PySide6.QtCore.Qt.KeyboardModifier, PySide6.QtCore.Qt.Key]=Instance(QKeyCombination.fromCombined(0)), k4: Union[PySide6.QtCore.QKeyCombination, PySide6.QtCore.Qt.KeyboardModifier, PySide6.QtCore.Qt.Key]=Instance(QKeyCombination.fromCombined(0))) -> None
QKeySequence(key: PySide6.QtGui.QKeySequence.StandardKey) -> None
QKeySequence(key: str, format: PySide6.QtGui.QKeySequence.SequenceFormat=Instance(PySide6.QtGui.QKeySequence.SequenceFormat.NativeText)) -> None
QKeySequence(ks: Union[PySide6.QtGui.QKeySequence, PySide6.QtCore.QKeyCombination, PySide6.QtGui.QKeySequence.StandardKey, str, int]) -> None

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import sys

from PySide6.QtGui import QKeySequence
from PySide6.QtWidgets import QWidget, QKeySequenceEdit, QApplication


class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QKeySequenceEdit-快捷键设置 - PyQt5中文网")
self.resize(600, 500)
self.func_list()

def func_list(self):
self.func()

def func(self):
# 设置快捷键
kse=QKeySequenceEdit(self)
ks=QKeySequence('Ctrl+A') # 直接使用字符串设置
# ks=QKeySequence(QKeySequence.Copy) # 使用枚举值设置
# ks=QKeySequence(Qt.CTRL + Qt.Key_C, Qt.CTRL + Qt.Key_A) # 使用枚举值设置
kse.setKeySequence(ks)

# 获取快捷键
# print(kse.keySequence()) # 获取快捷键对象
# print(kse.keySequence().toString()) # 获取快捷键

# 清除
# kse.clear()

# 信号
# editingFinished() # 结束编辑时
# keySequenceChanged() # 键位序列发生改变时
kse.editingFinished.connect(lambda: print(kse.keySequence().toString())) # 结束之后一秒
# kse.keySequenceChanged.connect(lambda val: print('AAAA', val.toString()))


if __name__=='__main__':
app=QApplication(sys.argv)
window=Window()

window.show()
sys.exit(app.exec())

方法

方法 返回值 说明
setClearButtonEnabled(enable:bool) None 设置键序列编辑在不为空时是否显示清除按钮。
如果启用,键序列编辑在包含某些文本时会显示尾随清除按钮,否则行编辑不会显示清除按钮(默认)。
isClearButtonEnabled() bool 获取键序列编辑在不为空时是否显示清除按钮。
如果启用,键序列编辑在包含某些文本时会显示尾随清除按钮,否则行编辑不会显示清除按钮(默认)。
[Slots]clear() None 清除当前键序列。
[Slots]setKeySequence(keySequence:PySide6.QtGui.QKeySequence) None 设置当前选定键序列。
快捷方式可以由用户或通过setter函数进行更改。
keySequence() PySide6.QtGui.QKeySequence 返回当前选定的键序列。。
快捷方式可以由用户或通过setter函数进行更改。

信号

信号 说明
editingFinished() 当用户完成输入快捷方式时发出该信号。
keySequenceChanged(keySequence:PySide6.QtGui.QKeySequence) 快捷方式改变时发出该信号。

例子

image-20230319024039049

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/14 23:54
# File_name: 03-QKeySequenceEdit的用法.py
"""
QKeySequenceEdit的用法,QKeySequence用法请见qt_QShortcut文件。
"""
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class KeySequenceEdit(QMainWindow):
def __init__(self, parent=None):
super(KeySequenceEdit, self).__init__(parent)

# 基本框架
label1 = QLabel('菜单save快捷键绑定:')
self.keyEdit1 = QKeySequenceEdit(self)
label2 = QLabel('菜单copy快捷键绑定:')
self.keyEdit2 = QKeySequenceEdit(self)
layout1 = QHBoxLayout()
layout1.addWidget(label1)
layout1.addWidget(self.keyEdit1)
layout2 = QHBoxLayout()
layout2.addWidget(label2)
layout2.addWidget(self.keyEdit2)
self.label_show = QLabel('显示按键信息')
self.text_show = QTextBrowser()
self.text_show.setMaximumHeight(60)

# 信号与槽绑定
# self.keyEdit1.editingFinished.connect(lambda :print('输入完毕1'))
# self.keyEdit2.editingFinished.connect(lambda :print('输入完毕2'))
self.keyEdit1.keySequenceChanged.connect(lambda key: self.save.setShortcut(key))
self.keyEdit2.keySequenceChanged.connect(lambda key: self.copy.setShortcut(key))
self.keyEdit1.keySequenceChanged.connect(self.show_key)
self.keyEdit2.keySequenceChanged.connect(self.show_key)

# 菜单栏
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
self.save = QAction("Save", self)
file.addAction(self.save)
self.copy = QAction('Copy', self)
file.addAction(self.copy)
file.triggered[QAction].connect(lambda q: self.statusBar().showMessage('触发菜单:%s;快捷键:%s' %(q.text(), q.shortcuts()), 3000))

# 布局管理
layout = QVBoxLayout()
layout.addLayout(layout1)
layout.addLayout(layout2)
layout.addWidget(self.label_show)
layout.addWidget(self.text_show)
widget = QWidget(self)
widget.setLayout(layout)
self.setCentralWidget(widget)
self.resize(300, 200)

def show_key(self, key: QKeySequence):
self.statusBar().showMessage('更新快捷键' + str(key), 2000)
key1 = self.keyEdit1.keySequence()
key2 = self.keyEdit2.keySequence()
_str = f'菜单栏快捷键更新成功;\nsave绑定:{key1}\ncopy绑定:{key2}'
# self.label_show.setText(_str)
self.text_show.setText(_str)


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = KeySequenceEdit()
demo.show()
sys.exit(app.exec())

多行文本控件QTextEdit

多行文本控件可以用于编辑和显示多行文本和图片,并可对文本进行格式化。

多行文本编辑控件有QTextEdit 和QPlainTextEdit 两种,QTextEdit 和QPlainTextEdit 都是直接继承自QAbstractScrollArea。

QAbstractScrollArea 为其子类提供中心视口(viewport)控件,从而保证子类显示的内容超过控件窗口的范围时,提供竖直和水平滚动条。QTextEdit 是主要用于显示并编辑多行文本的控件,支持富文本,当文本内容超出控件显示范围时,可以显示水平和竖直滚动条。

QTextEdit 不仅可以用来显示文本,还可以用来显示html文档。用QTextEdit类创建实例的方法如下,其中 :

  • parent 是 QTextEdit 所在的窗口或容器类控件
  • text 是要显示的文本内容。

QTextEdit 可以显示、输入和编辑文本。另外还有个从QTextEdit 继承的类QTextBrowser,通常只用于显示文本。

1
2
3
4
from PySide6.QtWidgets import QTextEdit

QTextEdit(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QTextEdit(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

多行文本控件QTextEdit的常用方法

多行文本控件QTextEdit 的常用方法如表所示,用这些方法可以编写文字处理工具。

  • QTextEdit通常用setPlainText(str)方法设置纯文本;
    • 用setHtml(str)方法设置 html格式的文本;
    • 用toPlainText()方法获取纯文本,
    • 用toHtml()方法获取 tml格式的文本
    • 用append(str)方法在末尾追加文本;
    • 用insertPlainText(str)和isertHtml(str)方法在光标处插入纯文本和 html格式文本;
    • 用setReadOnly(bool)方法可以设置成只读模式,这时用户不能输入数据;
    • 用setCurrentCharFormat(QTextCharFormat)方法设置当前的文本格式
    • 用setTextCuror(QTextCursor)方法设置文档中的光标,可以在光标处插入文字、图像表格选择文字;
    • 用setHorizontalScrollBarPolicy(Qt ScrollBarPolicy)方法和 setVerticalScrollBarPolicy(Qt ScrollBarPolicy)方法可以分别设置水平滚动条和竖直滚动条的调整策略,枚举值 Qt.ScrollBarPolicy 可取:
      • Qt.ScrollBarAsNeeded
      • Qt.ScrollBarAlwaysOff
      • Qt.ScrollBarAlwaysOn;
    • QTextEdit显示的内容是一个QTextDocument文档,用setDocument(QTextDocument)方法可以对文档进行设置。
QTextEdit的方法及参数类型 返回值的类型 说明
[slot]setText(str) None 设置显示的文字
slotlappend(str) None 添加文本
slotlsetPlainText(str) None 设置纯文本文字
slot setHtml(str None 设置成html格式的文字
slotlinsert Html(str) None 插入html格式的文本
slot]insertPlainText(str) None 插入文本
toHtml() str 获取html格式的文字
toPlainText() str 获取纯文本文字
createStandardContextMenu([QPoint1) QMenu 创建标准的右键快捷菜单
setCurrentCharFormat(OTextCharFormat) None 设置当前的文本格式
find(str) bool 查找,若找到则返回True
print(QPrinter) None 打印文本
setAcceptRichText(bool) None 设置是否接受富文本
acceptRichText() bool 获取是否接受富文本
setCursorWidth(int) None 设置光标宽度(像素)
[slot]setAlignment(Qt.Alignment) None 设置文字对齐方式
setTextCuror(QTextCursor) None 设置文本光标
textCursor QTextCursor 获取文本光标
setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy) None 设置水平滚动条的策略
setDocument(QTextDocument) None 设置文档
setDocumentTitle(str) None 设置文档标题
[slot]setCurrentFont(QFont) None 设置当前的字体
currentFont() OFont 获取当前的文字字体
[slot setFontFamily(str) None 设置当前字体名称
fontFamily() str 获取当前的字体名称
[slot]setFontItalic(bool) None 设置当前为斜体
fontItalic() bool 查询当前是否斜体
[slot]setFontPointSize(float) None 设置当前字体大小
fontPointSize() float 获取当前字体大小
[slot]setFontUnderline(booll None 设置当前为下划线
fontUnderline() bool 查询当前是否为下划线
[slot]setFontWeight(int) None 设置当前字体加粗
fontWeight() in 获取当前字体粗细值
setOverwriteMode(bool) None 设置替换模式
overwriteMode() bool 查询是否是替换模式
setPlaceholderText(str) None 设置占位文本
placeholderText() str 获取占位文本
setReadOnly(bool) None 设置是否只读
isReadOnly() bool 获取是否只读
setTabStopDistance(float) None 设置按Tab键时后退距离(像素)
tabStopDistance() float 获取按Tab键时的后退距离
[slot]set TextBackgroundColor(QColor) None 设置背景色
textBackgroundColor() QColor 获取背景色
[slot]set TextColor(QColor) None 设置文字颜色
textColor() QColor 获取文字颜色
setUndoReloEnabled(bool) None 设置是否可以撤销恢复
setWordWrapMode(WrapMode: PySide6.QtGui.QTextOption.WrapMode) None 设置长单词换行到下一行模式
from PySide6.QtGui import QTextOption
WrapMode可选(前三个都是不换行,后两个会换行):
NoWrap
WordWrap
ManualWrap
WrapAnywhere
WrapAtWordBoundaryOrAnywhere
setVerticalScrollBarPolicy(Qt.ScrollBar Policy) None 设置竖直滚动条的策略
[slot]zoomIn(range: int=1) None 放大
zoomlnF(range: float) None 放大
[slot]zoomOut(range: int=1) None 缩小
[slot]select AllC) None 全选
[slot]clear() None 清空全部内容
[slot]copy() None 复制旋转的内容
[slot]cut() None 剪切选中的内容
canPaste() bool 查询是否可以粘贴
[slot]paste() None 粘贴
isUndoRedoEnabled() bool 获取是否可以进行撤销、恢复
[slot]undo() None 撤销上步操作
[slot]redo() None 恢复撤销

多行文本控件QTextEdit的信号

多行文本控件QTextEdit的信号如表

信号 描述
copyAvailable(bool) 可以进行复制时发送信号
urrentCharFormatChanged(QTextCharFormat) 当前文字的格式发生变化时发送信号
cursorPositionChanged() 光标位置变化时发送信号
redoAvailable(bool) 可以恢复撤销时发送信号
selectionChanged() 选择的内容发生变化时发送信号
texiChanged() 文本内容发生变化时发送信号
undoAvailable(bool) 可以撤销操作时发送信号

文字格式QTextCharFormat

用QTextEdit的 setCurrentCharFormat(QTextCharFormat)方法可以设置文字的字体格式,QTextCharFormat类用于定义宇体的格式参数。文字格式QTextCharFormat的常用方法如表所示。

  • 用setFont(QFont,behavior=QTextCharFormat.FontProperticsAll)方法设置字体,其中参数 behavior 可以取:

    • QTextCharFormat.FontPropertiesSpccifiedOnly 在没有明确改变一个属性时不改变属性的值
    • QTextCharFormat.FontPropertiesAll,用默认的值覆盖现有的值
  • 用setUnderlineStyle(QTextCharFormat.UnderlineStyle)方法设置下划线的风格,其中枚举值 QTextCharFormat.UnderlineStyle 可以取以下值,对应值分别是0~7:

    • QTextCharFormat.NoUnderline
    • QTextCharFormat.SingleUInderline
    • QTextCharFormat.DashUnderline
    • QTextCharFormat.DotLine
    • QTextCharFormat.DashDotLine
    • QTextCharFormat.DashDotDotLine
    • QTextCharFormat.WaveUnderline
    • QTextCharFormat.SpellCheckUnderline
  • 用setVerticalAlignment(QTextCharFormat.VerticalAlignment)方法设置文字在竖直方向的对齐方式举值 QTextCharFormat.VerticalAlignment 可以取以下值,对应值分别是 0~6:

    • QTextCharFormat.AlignNormal
    • QTextCharFormat.AlignSuperScript
    • QTextCharFormat.AlignSubScript
    • QTextCharFormat.AlignMiddle
    • QTextCharFormat.AlignBottom
    • QTextCharFormat.AlignTop
    • QTextCharFormat.AlignBaseline
    QTextCharFormat的方法及参数类型 说明
    setFont(QFont, bebavior=QTextCharFormat FontPropertiesAll) 设置字体
    setFontCapitalization(QFont.Capitalization) 设置大小写
    setFontFamilies(families: Sequence[str]) 设置字体名称
    setFontFamily(family: str) 设置字体
    setFontFixedPitch(fixedPitch: bool) 设置固定宽度
    setFontItalic(italic: bool) 设置斜体
    setFontKerning(enable: bool) 设置字距
    setFontLetterSpacing(float) 设置字符间院
    setFontLetterSpacing Type(QFont.Spacing Type) 设置字符间隙样式
    setFontOverline(overline: bool) 设置上划线
    setFontPointSize(size: float) 设置字体尺寸
    setFontStretch(factor: int) 设置拉伸百分比
    setFontStrikeOut(strikeOut: bool) 设置删除线
    setFontUnderline(underline: bool) 设置下划线
    setFontWeight(weight; int) 设置字体粗细程度
    setFont WordSpacing(spacing: float) 设置字间距
    setSubScriptBaseline(baseline: float=16,67) 设置下标位置(字体高度百分比值)
    setSuperScriptBaseline(baseline: float=50) 设置上标位置(字体高度百分比值)
    setTextOutline(pen: Union Qt.PenStyle.OColorl) 设置轮廓线的颜色
    setBaselineOffset(baseline: float) 设置文字上下偏移的百分比,正值向上移动,负值向下移动
    setToolTip(tip: str) 设置片段文字的提示信息
    setUnderlineColor(Union[QColor, Qt.GlobalColor]) 设置下划线的颜色
    setUnderlineStyle(QTextCharFormat.UnderlineStvle) 设置下划线的风格
    setVerticalAlicnment(QTextCharFormat.VerticalAlianmet) 设置文字竖直方向对齐样式
    setAnchor(anchor: bool) 设置成锚点
    setAnchorHref(value: str) 将给定文本设置成超链接
    setAnchorNames(names: Sequence[str]) 设置超链接名,目标公须用setAnchor()和 setAnchorHref()方法设置过

文本光标QTextCursor

QTextCursor 类是 QTextEdit 文档中的光标用于获光标在文档中的位置,选择文字,在光标位置处插人文本、图像文本块(段落)和表格等。

用QTextCursor 创建光标对象的方法如下所示,可以为一个文档创建多个 QTextCursor 光标。

1
2
3
4
5
6
7
from PySide6.QtGui import QTextCursor

QTextCursor(self) -> None
QTextCursor(block: PySide6.QtGui.QTextBlock) -> None
QTextCursor(cursor: PySide6.QtGui.QTextCursor) -> None
QTextCursor(document: PySide6.QtGui.QTextDocument) -> None
QTextCursor(frame: PySide6.QtGui.QTextFrame) -> None

文本光标 QTextCursor 的常用方法

如果文档中有锚点 anchor(),则在锚点位置和光标位置 position()之间的文本会被选中。

  • 用setPosition(pos:int,mode=QTextCursorMoveAnchor)方法移动光标或点到指定位置,参数 mode可取:
    • QTextCursor。MoveAnchor
    • QTextCursor。KeepAnchor;
  • 用setCharFormat(QTextCharFormat)方法可以设置文本的格式;
  • 用insertText(str)或insertHtml(str)方法插人文本;
  • 用insertImage(QTextImageFormat)方法插入图像;
  • 用insertTable(rows;int;cols:int)方法插人表格
QTextCursor的方法及参数类型 返回值的类型 说 明
setCharFormat(QTextCharFormat) None 设置文本的格式
setPosition(pos: int,mode=QTextCursor.MoveAnchor) None 移动光标或锚点到指定位置
setBlockCharFormat(QTextCharFormat) None 设置块内文本的格式
setBlockFormat(QTextBlockFormat) None 设置块(段落)的格式
insertText(str) None 插人文本
insertText(str,QTextCharFormat) None 同上
insertBlock() None 插人新文本块
insertBlock(QTextBlockFormat) None 同上
insertFragment(fragment: QTextDocumentFragment) None 插人文本片段
insertFrame(QTextFrameFormat) QTextFrame 插人框架
insertHtml(str) None 插人 html文本
insertImage(QTextImageFormat) None 插入带格式的图像
insertImage(QImagename: str=”) None 插入图像
insertImage(name:str) None 同上
insertList(QTextListFormat) QTextList 插入列表标识
insertList(QTextListFormat.Style) QTextList 同上
insertTable(rows: int,cols: int) QTextTable 插入表格
insertTable(rows: int,cols: int,QTextTableFormat) QTextTable 插入带格式的表格
atBlockStart() bool 获取光标是否在块的起始位置
atEnd() b001 获取光标是否在文档的末尾
atStart() bool 获取光标是否在文档的起始 位置
block() QTextBlock 获取光标所在的文本块(段落)
blockCharFormat() QTextCharFormat 获取字符格式
blockFormat() QTextBlockFormat 获取文本块的格式
charPormat() QTextCharFormat 获取字符格式
clearSelection() None 清除选择,将锚点移到光标 位置
deleteChar() None 删除选中的或当前的文字
deletePreviousChar() None 删除选中的或光标之前的文字
document() QTextDocument 获取文档
position() int 获取光标的绝对位置
positionInBlock() int 获取光标在块中的位置
removeSelectedText() None 删除选中的文字
selectedText() Str 获取选中的文本

扩展:

对QTextEdit 中的文字进行更详细的排版格式化插人表格等操作,还需要其他一些类的支持,这些类包括:

  • QTextBlock
  • QTextBlockFormat
  • QTextBlockGroup
  • QTextBlockUserData
  • QTextDocument
  • QTextDocumentFragment
  • QlextDocumentWriter
  • QTextFragment
  • QTextFrame
  • QTextFrameFormat
  • QTextInlineObject
  • QTextltem
  • QTextLayout
  • QTextLength
  • QTextLineQTextList
  • QTextListFormat
  • QTextObject
  • QTextObjectInterface
  • QTextOption
  • QTextTabale
  • QTextTableCell
  • QTextTableCellFormat
  • QTextTableFormat

多行文本控件QTextEdit的应用实例

下面的程序建立一个简单的文字处理界面,如图所示,单击”打开文本文件”按钮可以从 txt文件中导人数据到 QTextEdit 中;

单击”插人文本”按钮,可以在光标处插人文本和超链接文本;

单击”插人图像文件”按钮,可以从硬盘上打开一个图形文件并插人到光标位置;

单击”作为系统输出”按钮,将把 help()print()函数的输出内容直接输出到QTextEdit中。

为了将窗口作为系统的标准输出这里使用了sysstdout=self和sysstderr=self语另外还必须为窗口编写write()函数读者还可以进一步编写设置字体名称、尺寸和颜色的代码,还可以增加复制粘贴剪切撤销、恢复撤销等的代码

image-20230221222458625

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import sys
from PySide6.QtWidgets import(QApplication, QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QTextEdit)
from PySide6.QtGui import QTextImageFormat
from PySide6.QtWidgets import QFileDialog


class MyWidget(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("文字处理")

self.setupUi()
self.btnOpen.clicked.connect(self.openText) # 信号与槽的连接
self.btnInsert.clicked.connect(self.insertText) # 信号与槽的连接
self.btnImage.clicked.connect(self.openImage) # 信号与槽的连接
self.btnOutput.clicked.connect(self.sysOutput) # 信号与槽的连接

def setupUi(self): # 建立界面上的控件
self.textEdit=QTextEdit(self)

self.btnOpen=QPushButton(self)
self.btnOpen.setText("打开文本文件")

self.btnInsert=QPushButton(self)
self.btnInsert.setText("插人文本")

self.btnImage=QPushButton(self)
self.btnImage.setText("插入图像文件")

self.btnOutput=QPushButton(self)
self.btnOutput.setText("作为系统输出")

self.horizontalLayout=QHBoxLayout() # 水平排列
self.horizontalLayout.addWidget(self.btnOpen)
self.horizontalLayout.addWidget(self.btnInsert)
self.horizontalLayout.addWidget(self.btnImage)
self.horizontalLayout.addWidget(self.btnOutput)

self.verticalLayout=QVBoxLayout(self) # 竖直排列
self.verticalLayout.addWidget(self.textEdit)
self.verticalLayout.addLayout(self.horizontalLayout)

def openText(self): # 按钮的槽函数
name=""

name, filter=QFileDialog.getOpenFileName(self, "选择文件", ".", "文本(*.txt)")

print(name)

if len(name) > 0:
fp=open(name, 'r')
strings=fp.readlines()
for i in strings:
i=i.strip("\n")
self.textEdit.append(i)
fp.close()

def insertText(self): # 按钮的槽函数
self.textEdit.setFontFamily('楷体') # 定义格式字体

self.textEdit.setFontPointSize(20) # 定义格式字体大小

self.textEdit.insertHtml("<a href='http://www.qq.com'>QQ</a>") # 插入html 文本

def openImage(self): # 按钮的槽函数
self.textEdit.insertPlainText('Hello,Nice to meet you!') # 按格式插入字体

name, filter=QFileDialog.getOpenFileName(self, "选择文件", ".", "图像(*.png *.jpg)")

textCursor=self.textEdit.textCursor()

pic=QTextImageFormat()

pic.setName(name) # 图片路径
pic.setHeight(100) # 图片高度
pic.setWidth(100) # 图片宽度

textCursor.insertImage(pic) # 插入图片

def sysOutput(self): # 按钮的槽函数
sys.stdout=self # 修改系统的标准输出
sys.stderr=self # 修改系统的异常信息输出
print("我是chuiniubi公司,很高兴认识你!")

def write(self, info): # 将系统标准输出改成窗口,需要定义一个write()函数
info=info.strip("\r\n")

self.textEdit.insertPlainText(info)


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWidget()

win.show()
sys.exit(app.exec())

文本浏览器QTextBrowser

扩展了QTextEdit(只读模式),添加了一些导航功能,以便用户可以跟踪超文本文档中的链接。

  • 如果要为用户提供可编辑的富文本编辑器,请使用QTextEdit 。
  • 如果想要一个没有超文本导航的文本浏览器,使用QTextEdit,并使用setReadOnly()禁用编辑。
  • 如果只需要显示一小段富文本,使用QLabel

QTextBrowser 是 QTextEdit 的只读版本,它继承了 QTextEdit 全部的特性,支持的 HTML 标记语言子集也是一样的。

QTextBrowser 还有更多增强功能,用于打开浏览 HTML 内部的超链接。QTextBrowser 本身就是 HTML 文件浏览器,虽然支持的只是 HTML 子集。

1
2
3
from PySide6.QtWidgets import QTextBrowser

QTextBrowser(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

QTextBrowser 显示的内容可以用基类的 setHtml() 、setPlainText() 等函数,另外 QTextBrowser 还有自己专属的打开文件链接函数:

setSource(const :QUrl str)

1
2
doSetSource(name: Union[PySide6.QtCore.QUrl, str], 
type: PySide6.QtGui.QTextDocument.ResourceType=Instance(PySide6.QtGui.QTextDocument.UnknownResource)) -> None

这是一个槽函数,它参数类似 QUrl(“file:///D:/QtProjects/ch05/simplebrowser/opensuse.htm”) 文件链接,自动打开并解析 HTML 文件内容,然后显示到控件界面。

当源文件链接 Source 发生变化时,会触发信号:

sourceChanged(const QUrl & src)

参数 src 是新的链接地址,通过这个信号可以跟踪浏览的源文件链接变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QTextEdit, QTextBrowser, QHBoxLayout, QVBoxLayout


class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.edit_label=QLabel('QTextEdit', self)
self.browser_label=QLabel('QTextBrowser', self)
self.text_edit=QTextEdit(self)
self.text_edit.insertPlainText("<font color='red'>Hello World~</font>")

self.text_browser=QTextBrowser(self)

self.edit_v_layout=QVBoxLayout()
self.browser_v_layout=QVBoxLayout()
self.all_h_layout=QHBoxLayout()

self.layout_init()
self.text_edit_init()

def layout_init(self):
self.edit_v_layout.addWidget(self.edit_label)
self.edit_v_layout.addWidget(self.text_edit)

self.browser_v_layout.addWidget(self.browser_label)
self.browser_v_layout.addWidget(self.text_browser)

self.all_h_layout.addLayout(self.edit_v_layout)
self.all_h_layout.addLayout(self.browser_v_layout)

self.setLayout(self.all_h_layout)

def text_edit_init(self):
self.text_edit.textChanged.connect(self.show_text_func) # 1

def show_text_func(self):
self.text_browser.setText(self.text_edit.toPlainText()) # 2


if __name__=='__main__':
app=QApplication(sys.argv)
demo=Demo()
demo.show()
sys.exit(app.exec())

方法

方法 返回值 说明
backwardHistoryCount() int 返回历史中向后的位置数。
clearHistory() None 清除已访问文档的历史记录,并禁用向前和向后导航。
forwardHistoryCount() int 返回历史记录中向前的位置数。
historyTitle(arg__1:int) str 返回 HistoryItem 的文档标题()。
i< 0 向后() 历史
i==0 当前,请参阅源()
i> 0 前进() 历史
historyUrl(arg__1:int) PySide6.QtCore.QUrl 返回历史记录项的 URL。
i< 0 向后() 历史
i==0 当前,请参阅源()
i> 0 前进() 历史
isBackwardAvailable() bool 返回在文档历史记录中是否可以回退使用back()
isForwardAvailable() bool 返回在文档历史记录中是否可以前进使用forward()
openExternalLinks() bool 获取是否应使用openUrl()自动打开指向外部源的链接,而不是发出anchorClickd信号。如果链接的方案既不是文件也不是qrc,则将其视为外部链接。
默认值为false。
openLinks() bool 获取是否自动打开用户通过鼠标或键盘激活的链接。
无论此属性的值如何,始终发出 anchorClicked 信号。
setSearchPaths(paths) None 设置存文本浏览器用于查找支持内容的搜索路径。
paths:list
searchPaths() list of strings 此属性保存文本浏览器用于查找支持内容的搜索路径。
QTextBrowser使用此列表来查找图像和文档。
默认情况下,此属性包含一个空字符串列表。
setOpenExternalLinks(open) bool 指定 QTextBrowser 是否应使用openUrl()而不是发出 anchorClicked 信号自动打开指向外部源的链接。如果链接的方案既不是文件也不是 qrc,则将其视为外部链接。
默认值为 false。
setOpenLinks(open) bool 此属性指定 QTextBrowser 是否应自动打开用户尝试通过鼠标或键盘激活的链接。
无论此属性的值如何,始终发出 anchorClicked 信号。
默认值为 true。
[Slots]setSource(name:PySide6.QtCore.QUrl[,type=QTextDocument.UnknownResource]) None 尝试以指定类型加载给定url处的文档。
如果类型为UnknownSource(默认值),则将检测文档类型:
如果url以扩展名.md、.mkd或.makdown结尾,则将通过setMarkdown()加载文档;
否则将通过setHtml()加载。可以通过显式指定类型来绕过此检测。
source() PySide6.QtCore.QUrl 此属性保存所显示文档的名称。。
如果没有显示文档或源未知,则这是一个无效的url。
设置此属性时,QTextBrowser会尝试在当前源的searchPaths属性和目录的路径中查找具有指定名称的文档,除非该值是绝对文件路径。它还检查可选的锚点并相应地滚动文档
如果文档中的第一个标记是<qt-type=detail>,则该文档在浏览器窗口中显示为弹出窗口,而不是新文档。否则,文档将在文本浏览器中正常显示,文本将通过setHtml()或setMarkdown()设置为命名文档的内容,具体取决于文件名是否以任何已知的Markdown文件扩展名结尾。
如果希望避免自动类型检测并显式指定类型,请调用setSource()而不是设置此属性。
默认情况下,此属性包含空URL。
sourceType() ResourceType 此属性保存所显示文档的类型。
如果未显示任何文档或源的类型未知,则为UnknownSource。
否则,它保存检测到的类型,或调用setSource()时指定的类型。

功能性方法

槽方法 说明
backward() 将显示的文档更改为通过导航链接生成的文档列表中的上一个文档。如果没有以前的文档,则不执行任何操作。
doSetSource(name[, type=QTextDocument.UnknownResource]) 尝试以指定类型加载给定url处的文档。
setSource()调用doSetSource。在Qt 5中,setSource(const QUrl&url)是虚拟的。
在Qt6中,doSetSource()是虚拟的,因此可以在子类中重写。
forward() 将显示的文档更改为通过导航链接生成的文档列表中的下一个文档。如果没有下一个文档,则不执行任何操作。
home() 将显示的文档更改为历史记录中的第一个文档。
reload() 重新加载当前集合源。

文档来源和内容

QTextEdit的内容是使用setHtml() 或 setPlainText() 设置的,

QTextBrowser 实现了 setSource()函数,可设置文本,在搜索路径列表和当前系统目录中查找指定名称名称。

如果文档名称以锚点结尾(例如#anchor),文本浏览器会自动滚动到该位置(使用scrollToAnchor())。

当用户单击超链接时,浏览器将使用链接的值作为参数调用setSource() 本身。可以通过连接到 sourceChanged() 信号来跟踪当前源。

导航

  • back()和forward()槽,可以使用它们来实现”后退”和”前进”按钮

  • home() 插槽将文本设置为显示的第一个文档。

  • 当用户单击锚点时,会发出 anchorClicked() 信号。要覆盖浏览器的默认导航行为,调用setSource() 函数以在连接到此信号的插槽中提供新的文档文本。

  • 如果要加载存储在Qt资源系统中的文档,使用URL中的方案来加载。例如,对于文档资源路径qrc:/docs/index.html作为 URL,使用setSource() 。

信号

信号 说明
anchorClicked(QUrl:PySide6.QtCore.QUrl) 当用户单击锚点时发出该信号。锚引用的URL在链接中传递。
注意,除非openLinks属性设置为false或在连接的插槽中调用setSource(),否则浏览器将自动处理导航到link指定的位置。此机制用于覆盖浏览器的默认导航功能。
backwardAvailable(bool) 当backward()的可用性发生变化时,会发出此信号。当用户在家时,available为false();否则这是真的。
forwardAvailable(bool) 当forward()的可用性发生变化时,会发出此信号。available在用户向后导航()后为true,在用户向前导航()时为false。
highlighted(QUrl:PySide6.QtCore.QUrl) 当用户已选择但未激活文档中的锚点时,发出该信号。锚引用的URL在链接中传递。
historyChanged() 当历史发生变化时,会发出此信号。
sourceChanged(src) 该信号在源发生变化时发出,src是新的源。
当调用setSource()、forward()、backward()或home()时,或者当用户单击链接或按下等效的键序列时,都会以编程方式更改源代码。

QTextBrowser例子

image-20230319024223873

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 1:01
# File_name: 02-QTextBrowser例子.py


import sys
from PySide6.QtWidgets import(QApplication, QWidget, QMainWindow
, QLineEdit, QTextBrowser, QPushButton, QVBoxLayout, QHBoxLayout, QFrame, QLabel)
from PySide6.QtCore import QUrl
import urllib
import os

os.chdir(os.path.dirname(__file__))


class TextBrowser(QMainWindow):

def __init__(self):
super().__init__()
self.initUI()

def initUI(self):
self.lineEdit = QLineEdit()
self.lineEdit.setPlaceholderText("在这里添加你想要的数据,回车确认")
self.lineEdit.returnPressed.connect(self.append_text)

self.textBrowser = QTextBrowser()
self.textBrowser.setAcceptRichText(True)
self.textBrowser.setOpenExternalLinks(True)
self.textBrowser.setSource(QUrl(r'.\support\textBrowser.html'))
self.textBrowser.anchorClicked.connect(lambda url: self.statusBar().showMessage('你点击了url' + urllib.parse.unquote(url.url()), 3000))
self.textBrowser.historyChanged.connect(self.show_anchor)

self.back_btn = QPushButton('Back')
self.forward_btn = QPushButton('Forward')
self.home_btn = QPushButton('Home')
self.clear_btn = QPushButton('Clear')

self.back_btn.pressed.connect(self.textBrowser.backward)
self.forward_btn.pressed.connect(self.textBrowser.forward)
self.clear_btn.pressed.connect(self.clear_text)
self.home_btn.pressed.connect(self.textBrowser.home)

layout = QVBoxLayout()
layout.addWidget(self.lineEdit)
layout.addWidget(self.textBrowser)
frame = QFrame()
layout.addWidget(frame)

self.text_show = QTextBrowser()
self.text_show.setMaximumHeight(70)
layout.addWidget(self.text_show)

layout_frame = QHBoxLayout()
layout_frame.addWidget(self.back_btn)
layout_frame.addWidget(self.forward_btn)
layout_frame.addWidget(self.home_btn)
layout_frame.addWidget(self.clear_btn)
frame.setLayout(layout_frame)

widget = QWidget()
self.setCentralWidget(widget)
widget.setLayout(layout)

self.setWindowTitle('QTextBrowser 案例')
self.setGeometry(300, 300, 300, 300)
self.show()

def append_text(self):
text = self.lineEdit.text()
self.textBrowser.append(text)
self.lineEdit.clear()

def show_anchor(self):
back = urllib.parse.unquote(self.textBrowser.historyUrl(-1).url())
now = urllib.parse.unquote(self.textBrowser.historyUrl(0).url())
forward = urllib.parse.unquote(self.textBrowser.historyUrl(1).url())
_str = f'上一个url:{back},<br>当前url:{now},<br>下一个url:{forward}'
self.text_show.setText(_str)

def clear_text(self):
self.textBrowser.clear()


if __name__ == '__main__':
app = QApplication(sys.argv)
ex = TextBrowser()
sys.exit(app.exec())

多行纯文本控件QPlainTextEdit

QPlainTextEdit是一个多行纯文本编辑器,用于显示和编辑多行纯文本,不支持富文本其功能比QTextEdit 很多。QPlainTextEdit 继承自QAbstractScrollArea。用QPlainTextEdit创建实例对象的方法如下所示其中parent 是继承自QWidget的窗口或控件,text是显示的文字。

1
2
3
4
from PySide6.QtWidgets import QPlainTextEdit

QPlainTextEdit(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QPlainTextEdit(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

多行纯文本控件OPlainTextEdit的常用方法

QPlainTextEdit的大部分方法与QTextEdit 的方法相同其常用方法如表所示:

  • 用setPlainText(str)方法可以设置显示的纯文本;
  • 用toPlainText()方法可以获取纯文本内容;
  • 用insertPlainText(str)方法可以在光标处插人文本;
  • 用appendPlainText(str)方法和appendHtml(str)方法可以在末尾添加文本和 html格式的文本;
  • 用setOverwriteMode(boo1)方法可以设置是否是覆盖模式
aPhTxEdt的方法及参数类型 返回值的类型 说明
gckgroundVisiblebool None 设置文档区之外调色板背景是否可见
rTibStopDistance float None 设置按Tab 键时光标移动的距离(像素)
8Doeument(QTextDocument None 设置文档
getDoeumentTitletstr None 设置文档标题
setCursorWidth(int) None 设置光标宽度(像素)
setReadOnly(bool) None 设置是否只读模式
sUndoRedoEnabled(bool) None 设置是否可以撤销、重复
setPlaceholderText(str) None 设置掩码
setOverwriteMode(bool) None 设置是否是覆盖模式
setTextCursOr(QTextCursor) None 设置文本光标
[slot]centerCursor() None 将光标移到竖直中间位置
[slot]selectAll() None 选中所有文本
[slot]undo() None 撤销
[slot]clear() None 清空内容
[slot]copy() None 复制选中的内容
[slot]cut() None 剪切选中的内容
[slot]paste() None 粘贴内容
[slot]redo() None 恢复撤销
[slot]zoomIn(range: int=1) None 缩小
[slot]zoomOut(range: int=1) None 放大
[slot]setPlainText(str) None 设置纯文本
toPlainText() Str 获取纯文本
[slot]insertPlainText(str) None 在光标处插入文本
[slot]appendPlainText(str) None 在末尾添加文本
[slot]appendHtml(str) None 在末尾添加html格式文本
setCenterOnScroll(bool) None 移动竖直滚动条使光标所在的位置可见

多行纯文本控件QPlainTextEdit的信号

多行纯文本控件QPlainTextEdit 的信号如表所示

copy Available(available:bool) 有选中的文本时发送信号
cursorPositionChanged() 光标位置发生变化时发送信号
modificationChanged(changed: bool) 修改内容发生变化时发送信号
redoAvailable(available: bool) 可以恢复撤销时发送信号
selectionChanged() 选中的内容发生变化时发送信号
textChanged() 文本内容发生变化时发送信号
undoAvailable(available: bool) 可以撤销时发送信号
blockCountChanged(newBlockCount; int) 块(段落)数量发生变化时发送信号

QPlainTextEdit例子

image-20230319024347624

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:54
# File_name: 09-QPlainTextEdit例子.py


from PySide6.QtWidgets import QApplication, QWidget, QTextEdit, QPlainTextEdit, QVBoxLayout, QPushButton
from PySide6.QtGui import QFont
import sys


class TextEditDemo(QWidget):
def __init__(self, parent=None):
super(TextEditDemo, self).__init__(parent)
self.setWindowTitle("QPlainTextEdit 例子")
self.resize(300, 270)
self.textEdit = QPlainTextEdit()
# 布局管理
layout = QVBoxLayout()
layout.addWidget(self.textEdit)

# 显示文本
self.btn_plain = QPushButton("显示纯文本")
self.btn_plain.clicked.connect(self.btn_plain_Clicked)
layout.addWidget(self.btn_plain)

self.setLayout(layout)

def btn_plain_Clicked(self):
font = QFont()
font.setFamily("Courier")
font.setFixedPitch(True)
font.setPointSize(14)
self.textEdit.setFont(font)
self.textEdit.setPlainText("Hello Qt for Python!\n单击按钮")


if __name__ == "__main__":
app = QApplication(sys.argv)
win = TextEditDemo()
win.show()
sys.exit(app.exec())

标签控件QLabel

在可视化图形界面上标签通常用来显示提示性信息,也可以显示图片和 gif 格式的动画。它通常放到输入控件的左边,也用在状态栏上。

标签控件的类是 QLabel,继承自QFrame,QFrame为其子类提供外边框,可以设置外边框是否显示和显示的样式。

QLabel类在QtWidgets模块中,用QLabel类创建实例的方法如下

  • parent是容纳QLabel控件的容器该容器通常是继承自QWidget 的窗口或容器类控件,
  • text 是标签上显示的文字
  • f的取值为Qt.WindowFlags 的举值。有关QtWindowFlags 的取值请参考QWidget相关
1
2
3
4
from PySide6.QtWidgets import QLabel

QLabel(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, f: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None
QLabel(text: str, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None, f: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags)) -> None

标签控件QLabel的方法

标签控件QLabel的主要方法介绍如下

  • 可以在创建标签控件时设置其所在的父容器,也可用setParent(QWidget)方法设置标签控件的父容器或父控件。

  • 用setText(str)方法设置标签上的文字,用text()方法获取标签的文本用setNum(float)和 setNum(int)方法显示数值,用clear()方法清空显示的内容。

  • 用setPixmap(QPixmap)方法设置标签上显示的图像,参数QPixmap 表示QPixmap的实例对象;用pixmap()方法获取标签上显示的QPixmap图像,显示图像也可用setPicture(QPicture)方法;

  • 用setMovie(QMovie)方法播放 gif格式的动画。关于QMovie的介绍请参考 9.1.4节的内容。如果所显示的图片较小,可用setScaledContents(True)方法设置将图像填充整个空间。

  • 用setAlignment(Qt.Alignment)方法设置文字的水平和竖直对齐方式,用alignment()方法获取对齐方式。

    • 其中参数Qt.Alignment 是举类型水平方向的对齐方式可以取:
      • Qt.AlignLeft(左对齐)
      • Qt.AlignRight(右对齐)
      • Qt.AlignCenter(中心对齐)
    • AtAlignJustify(两端对齐)竖直方向的对齐方式有
      • Qt.AlignTop(上对齐)
      • Qt.AlignBottom(下对齐)
      • Qt.AlignVCenter(居中对齐)。
    • Qt.AlignCenter 是水平和竖直中心对齐。

    当同时对水平和竖直方向进行设置时,可以用运算符””将两个对齐方式连接起来,例如Qt.AlignLeftl | Qt.AlignVCenter

  • 用setFont(QFont)方法设置标签显示的文字的字体,用font()方法获取文字的字体,用setPalette(QPalette)方法设置调色板,用palette()方法获取调色板。

  • 用setBuddy(QWidget)方法设置具有伙伴关系的控件,用buddy()方法获取具有伙伴关系的控件

标签控件QLabel的常用方法如表所示

QLabel的方法及参数类型 返回值的类型 说明
[slot]setText(str) None 设置显示的文字
text() str 获取QLabel的文字
setText Format(Qt.Text Format) None 设置文本格式
[slot]setNum(float) None 设置要显示的数值
[slot]setNum(int) None 设置要显示的数值
[slot]clear() None 清空显示的内容
setParent(QWidget) None 设置标签所在的父容器
setSelection(int,int) None 根据文字的起始和终止索引,选中相应的文字
selectedText() str 获取被选中的文字
hasSelectedText() bool 判断是否有选择的文字
selectionStart() int 获取选中的文字起始位置的索引,-1表示没有选中的文字
setIndent(int) None 设置缩进量
indent() int 获取缩进量
Fslot]setPixmap(QPixmap) None 设置图像
pixmap() QPixmap 获取图像
setToolTip(str) None 当光标放到标签上时,设置显示的提示信息
setWordWrap(bool) None 设置是否可以换行
wordWrap() bool 获取是否可以换行
setAlignment(Qt.Alignment) None 设置文字在水平和竖直方向的对齐方式
setOpen ExternalLinks(bool) None 设置是否打开超链接
setFont(QFont) None 设置字体
font() Qfont 获取字体
setPalette(QPalette) None 设置调色板
palette() QPalette 获取调色板
setGeometry(QRect) None 设置标签在父容器中的范围
geometry() Red 获取标签的范围
[slot]setMovie(QMovie) Non 没置动画
setBuddy(QWidget) None 设置具有伙伴关系的控件
buddy() QWidget 获取具有伙伴关系的控件
minimumSizeHint() QSize 获取最小尺寸
setScaledContents(bool) None 设置显示的图片是否充满整个标签空间
setMargin(int) None 设置内部文字边框与外边框的距离,默认为0
setEnabled(bool) None 设置是否激活标签控件
setAutoFillBackground(bool) None 设置是否自动填充背景色

QLabel的信号

QLabel的信号有 linkActivated(link)和 linkHovered(link).

  • linkActivated(link)为单击文字中嵌入的超链接时发送信号,如果需要打开超链接,需要把setOpenExternalLink()设置成True,传递的参数link 是链接地址;
  • linkHovered(link)为当光标放在文字中的超链接上时发送信号。

标签控件OLabel的应用实例

下面的程序涉及 QLabel的图形显示超链接和信号的应用。这个程序可以改用QtDesigner 来设计界面,并进行界面布置,这样在窗口缩放时可以保证控件同时移动或缩放,也可手动编写布局。

image-20230221204950232

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 21:58
# File_name: 09- 标签控件OLabel的应用实例.py
import sys
from PySide6.QtGui import QPixmap, QFont
from PySide6.QtWidgets import QApplication, QWidget, QLabel
from PySide6.QtCore import QRect, Qt.QSize


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedSize(QSize(600, 400))
w = self.width() # 窗口的宽度
h = self.height() # 窗口的高度

self.label1 = QLabel(self)
self.label2 = QLabel(self)
self.label3 = QLabel(self)
self.label4 = QLabel(self)

self.label1.setGeometry(QRect(0, 0, w, h))
self.label1.setPixmap(QPixmap("../../Resources/animal/m1.png"))

self.label2.setGeometry(QRect(int(w / 2) - 150, 150, 300, 30))
font = QFont("黑体", pointSize=20)
self.label2.setFont(font)
self.label2.setText("<A href='https://www.baidu.com/'>欢迎来到百度!</A>")
self.label2.setToolTip("我喜欢的网站 www.mysmth.net")
# 设置提示信息
self.label2.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
self.label2.linkHovered.connect(self.hover)
# 定义信号与槽的连接
self.label2.linkActivated.connect(self.activated)

# 定义信号与槽的连接
self.label3.setGeometry(QRect(int(w / 2), h - 50, int(w / 2), 50))
font = QFont("楷体", pointSize=20)
self.label3.setFont(font)
self.label3.setText(">>进人<A href='https://www.baidu.com/'>百度</A>")
self.label3.setOpenExternalLinks(True)

def hover(self, link):
# 光标经过超链接的关联函数
print("欢迎来到我的世界!")

def activated(self, link):
# 单击超链接的关联函数
rect = self.label3.geometry()
rect.setY(rect.y() - 50)
self.label4.setGeometry(rect)
self.label4.setText("单击此链接, 进人网站" + link)


if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWidget()
window.show()
sys.exit(app.exec())

液晶显示控件QLCDNumber

液晶显示控件QLCDNumber 用来显示数字和一些特殊符号,常用来显示数值日期和时间。可以显示的数字和符号有 O0123456789-g.(小数点)、A,B,CDEFhHLoPruUY:度数(在字符串中用单引号表示)和空格。QLCDNumber将非法字符换为空格。
用QLCDNumber 类创建实例对象的方法如下所示其中参数如下,QLCDNumber 是从 QFrame类继承而来的。

  • parent 是控件所在的窗体或容器控件,
  • numDigits是能显示的数字个数。
1
2
3
4
from PySide6.QtWidgets import QLCDNumber

QLCDNumber(numDigits: int, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QLCDNumber(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

液晶显示控件OLCDNumber的常用方法

液晶显示控件QLCDNumber 的常用方法如表所示。

由于液晶显示控件是从QFrame类继承来的,因而可以设置液晶显示控件的边框样式,如凸起、凹陷、平面等,液晶显示控件的主要方法介绍如下。

  • 用setDigitCount(int)方法设置液晶显示控件的最大显示数字个数,包括小数点。

  • 用display(str)display(float)和 display(int)方法分别显示字符串、浮点数和整数显示的内容只能是O0123456789-g.(小数点)、A,B,CDEFhHLoPruUY:度数(在字符串中用单引号表示)和空格,如果显示的整数部分长度超过了允许的最大数字个数则会产生溢出,溢出时会发送overflow()信号。

    • 可以用checkOverflow(float)和checkOverflow(int)方法检查浮点数和整数值是否会溢出,
    • 用intValue()和 value()方法可以分别返回整数和浮点数如果显示的是整数,
    • 以用setMode(QLCDNumber.Mode)方法将整数转换成二进制、八进制和十六进制显示,其中参数 QLCDNumber.Mode可以取以下值。也可以使用setDecMode()、setHexMode()、setOctMode(),setBinMode()方法设置
      • QLCDNumber.Hex 十六进制
      • QLCDNumber.Dec 十进制
      • QLCDNumber.Oct 八进制
      • QLCDNumber.Bin 二进制
    • 用setSegmentStyle(QLCDNumber.SegmentStyle)方法可以设置液晶显示器的外观,其中参数QLCDNumber.SegmentStyle可以取:
      • QLCDNumber.Outline(用背景色显示数字,只显示数字的轮廓)
      • QLCDNumber。Filled(用窗口的文字颜色显示文字)
      • QLCDNumber.Flat(平面,没有凸起效果)。
    QLCDNumber的方法及参数类型 返回值的类型 说明
    setDigitCount(int) None 设置可以显示的数字个数
    digitCount() int 获取可以显示的数字个数
    setSegmentStyle(QLCDNumber.SegmentStyle) None 设置外观显示样式
    [slot]display(str:str) None 显示字符串
    [slot]display(num:float) None 显示浮点数
    [slot]display(num:int) None 显示整数
    checkOverflow(float) bool 取浮点数是否会溢出
    checkOverflow(int) bool 获取整数是否会溢出
    intValue() int 按四舍五入规则返回整数值,老 显示的不是数值,则返回0
    value() float 返回浮点数值
    setMode(QLCDNumber.Mode) None 设置数字的显示模式
    [slot]setDecMode() None 转成十进制显示模式
    [slot]setHexMode() None 转成十六进制显示模式
    [slot]setOctMode() None 转成八进制显示模式
    [slot]setBinMode() None 转成二进制显示模式
    [slot]setSmallDecimalPoint(bool) None 设置小数点的显示是否占用一位

液晶显示控件OLCDNumber的信号

液晶显示控件QLCDNumber 只有一个信号overflow(),当显示的整数部分长度超过了允许的最大数字个数时发送信号。

液晶显示控件QLCDNumber的应用实例

下面的程序从本机上读取时间,计算到 2024 年春节的剩余时间,并用液晶显示控件显示剩余时间。

image-20230226020001934

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QLCDNumber
from PySide6.QtCore import QTimer, QDateTime


class MyWindow(QWidget):

def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("ICD Number")
self.resize(500, 200)
self.label=QLabel("距离2030年春节还有:", self)
font=self.label.font()
font.setPointSize(20)

self.label.setFont(font)
self.label.setGeometry(100, 50, 300, 50)

self.LcdNumber=QLCDNumber(13, self)

self.LcdNumber.setGeometry(100, 100, 300, 50)
self.sprintDay=QDateTime(2030, 2, 2, 0, 0, 0) # 2030年春节时间
self.timer=QTimer(self)

self.timer.setInterval(1000)

self.timer.timeout.connect(self.change)

self.timer.start()

def change(self):
self.current=QDateTime.currentDateTime() # 获取系统的当前日期时间

seconds=self.current.secsTo(self.sprintDay) # 计算到目的日期的秒数
days=seconds //(3600 * 24) # 计算剩余天
hours=(seconds - days * 3600 * 24) // 3600 # 计算剩余小时
minutes=(seconds - days * 3600 * 24 - hours * 3600) // 60 # 计算剩余分钟
seconds=seconds - days * 3600 * 24 - hours * 3600 - minutes * 60 # 计算剩余秒

string="{:03d}:{:02d}:{:02d}:{:02d}".format(days, hours, minutes, seconds)

self.LcdNumber.display(string)


if __name__=='__main__':
app=QApplication(sys.argv)
win=MyWindow()

win.show()
sys.exit(app.exec())

数字输入控件QSpinBox和QDoubleSpinBox

QSpinBox 和QDoubleSpinBox 控件是专门用于输入数值的控件,前者只能输人整数后者只能输人浮点数,在右边可以有按钮,也可以没有。

QSpinBox和 QDoubleSpinBox 控件是 QLineEdit 控件和按钮控件组合而来的。

这两个控件都继承自抽象类 QAbstractSpinBox,它们的方法信号和槽函数基本一致。

用QSpinBox和 QDoubleSpinBox 实例化对象的方法如下所示,其中 parent 是控件所在的父窗口或容器控件。

1
2
3
4
from PySide6.QtWidgets import QSpinBox, QDoubleSpinBox

QSpinBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QDoubleSpinBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

数字输入控件QSpinBox和QDoubleSpinBox 的常用方法

数字输人控件 QSpinBox和 QDoubleSpinBox 的常用方法如表所示,主要方法介绍如下:

  • 可以设置允许输入的最小值和最大值
    • 通过 setMinimum()setMaximum()和setRange()方法来设置允许输入的最小值和最大值。
  • QSpinBox和QDoubleSpinBox 控件都提供一个微调控件,通过单击向上/向下按钮或按键盘的↑/↓键来增加/减少当前显示的值。
    • 用setSingleStep()方法可以设置每次增加或减少的微调量,
    • 用setWrapping(True)方法可以设置到达最大或最小值时是否进行循环。
  • QDoubleSpinBox的默认精度是2位小数,
    • 可以通过 setDecimals(int)方法设置允许输人的小数的位数。
  • 用setPrefix(str)和setSuffix(str)方法分别可以设置前缀符号和后缀符号,例如货币或计量单位。
  • 值可以用setValue(int)方法来设置,
    • 当前值可以用value()方法获取,
    • 文本可以用text()方法(包括前缀和后缀)或者 cleanText()方法(没有前缀和后缀)来获取。
    • 按钮的样式可以用setButtonSymbols(QAbstractSpinBox ButtonSymbols)方法设置,枚举类型参数QAbstractSpinBox ButtonSymbols可以取:
      • QAbstractSpinBox.UpDownArrows
      • QAbstractSpinBox.PlusMinus
      • QAbstractSpinBox.NoButtons。
  • 用setCorrectionMode(QAbstractSpinBox,CorrectionMode)方法设置当输人有误时使用自动修正模式参数可取:
    • QAbstractSpinBoxCorrectToPreviousValue(修正成最近正确的值)
    • QAbstractSpinBoxCorrectToNearestValue(修正成最接近正确的值)
  • setKeyboardTracking(bool)方法设置是否可以跟踪按键输入
    • 例如要输人 123,在setKeyboardTracking(True)时,会发送3信号valueChanged() andtextChanged(),信号传递的值分别是 112和123;
    • setKeyboardTracking(False)时,只发送最后的值 123。
QSpinBox和 QDoubleSpinBox的方法及参数类型 说 明
[slot]setValue(int) 设置当前的值,用于QSpinBox控件
[slot]setValue(float) 设置当前的值,用于QDoubleSpinBox控件
value() 获取当前的值
setDisplayIntegerBase(int) 设置整数的进位值,例如2、8、16,默认为10
displayIntegerBase() 获取整数的进位值,仅用于QSpinBox控件
setDecimals(int) 设置允许的小数位数,用于QDoubleSpinBox控件
decimals() 获取允许的小数位数,用于QDoubleSpinBox控件
setMaximum(inb)、setMaximum(float) 设置允许输人的最大值
setMinimum(int)、setMinimum(float) 设置允许输入的最小值
setRange(int,int),setRangel(float, float) 设置允许输入的最小值和最大值
minimum()、maximum( 获取允许的最小值和最大值
selSingleStep(int),setSingleStep(float) 设置微调步长
singleStep() . 获取微调值
setPrefix(str) 设置前缀符号,例如‘¥
setSuffix(str) 设置后缀符号,例如‘km
cleanText() 获取不含前缀和后缀的文本
text() 获取含前缀和后缀的文本
[slot]selectA11() 选择显示的值,不包括前级和后级
setAlignment(Qt.Alignment) 设置对齐方式
setButonSymbols(QAbstractSpinBox BurtonSymbols) 设置右侧的按钮样式
selCorrectionMode(QAbstractSpinBoxCarrectionMode 设置自动修正模式
setFrame(bool) 设置是否有外边框
setGroupSeparatorShown(bool) 设置按照千位(3位)用逗号隔开
setKeyboardTracking(bool) 设置是否跟踪键盘的每次输入
setReadOnly(bool) 设置只读,不能编辑
setSpecialValueText(str) 设置特殊文本,当显示的值等于允许的最小值时,显 示该文本
setWrapping(bool) 设置是否可以循环,即最大值后再增大则变成最小 值,最小值后再减小则变成最大值
setAccelerated(bool) 当按住增大和减小按钮时,是否加速显示值
[slot]clear() 清空内容,不包含前缀和后缀
[slot]stepDown() 增大值
[slot]stepUp() 减小值

数字输入控件 QSpinBox和 QDoubleSpinBox的信号

数字输人控件 QSpinBox 和 QDoubleSpinBox 的信号相同,如表所示。

当QSpinBox和QDoubleSpinBox 的值发生改变时,都会发送重载型信号 valueChanged()其中一个带int(或 float)类型参数,另一个带 str 类型参数str 类型的参数包含前缀和后缀

信号及参数类型 说 明
editingFinished() 输人完成,按Enter键或失去焦点时发送信号
textChanged(str) 文本发生变化时发送信号
valueChanged(int) 数值发生变化时发送信号,用于 QSpinBox控件
valueChanged(float) 数值发生变化时发送信号,用于QDoubleSpinBox控件

QSpinBox 例子

image-20230319024625583

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:57
# File_name: 05-QSpinBox 例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class spindemo(QWidget):
def __init__(self, parent=None):
super(spindemo, self).__init__(parent)
self.setWindowTitle("SpinBox 例子")
self.resize(300, 100)

layout = QFormLayout()

self.label = QLabel("current value:")
# self.label.setAlignment(Qt.AlignCenter)
self.label.setAlignment(Qt.AlignLeft)
layout.addWidget(self.label)

self.spinbox = QSpinBox()
layout.addRow(QLabel('默认显示'), self.spinbox)
self.spinbox.valueChanged.connect(lambda: self.on_valuechange(self.spinbox))

label = QLabel("步长和范围:")
self.spinbox_int = QSpinBox()
self.spinbox_int.setRange(-20, 20)
self.spinbox_int.setMinimum(-10)
self.spinbox_int.setSingleStep(2)
self.spinbox_int.setValue(0)
layout.addRow(label, self.spinbox_int)
self.spinbox_int.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_int))

label = QLabel("循环:")
self.spinbox_wrap = QSpinBox()
self.spinbox_wrap.setRange(-20, 20)
self.spinbox_wrap.setSingleStep(5)
self.spinbox_wrap.setWrapping(True)
layout.addRow(label, self.spinbox_wrap)
self.spinbox_wrap.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_wrap))

label = QLabel("前后缀")
self.spinbox_price = QSpinBox()
self.spinbox_price.setRange(0, 999)
self.spinbox_price.setSingleStep(1)
self.spinbox_price.setPrefix("¥")
self.spinbox_price.setSuffix("/每个")
self.spinbox_price.setValue(99)
layout.addRow(label, self.spinbox_price)
self.spinbox_price.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_price))

self.groupSeparatorSpinBox = QSpinBox()
self.groupSeparatorSpinBox.setRange(-99999999, 99999999)
self.groupSeparatorSpinBox.setValue(1000)
self.groupSeparatorSpinBox.setGroupSeparatorShown(True)
groupSeparatorChkBox = QCheckBox()
groupSeparatorChkBox.setText("千分隔符:")
groupSeparatorChkBox.setChecked(True)
layout.addRow(groupSeparatorChkBox, self.groupSeparatorSpinBox)
groupSeparatorChkBox.toggled.connect(self.groupSeparatorSpinBox.setGroupSeparatorShown)
self.groupSeparatorSpinBox.valueChanged.connect(lambda: self.on_valuechange(self.groupSeparatorSpinBox))

label = QLabel("特殊文本:")
self.spinbox_zoom = QSpinBox()
self.spinbox_zoom.setRange(0, 1000)
self.spinbox_zoom.setSingleStep(10)
self.spinbox_zoom.setSuffix("%")
self.spinbox_zoom.setSpecialValueText("Automatic")
self.spinbox_zoom.setValue(100)
layout.addRow(label, self.spinbox_zoom)
self.spinbox_zoom.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_zoom))

self.setLayout(layout)

def on_valuechange(self, spinbox):
self.label.setText("current value:" + str(spinbox.value()))


if __name__ == '__main__':
app = QApplication(sys.argv)
ex = spindemo()
ex.show()
sys.exit(app.exec())

QDoubleSpinBox 例子

image-20230319024716332

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:49
# File_name: 02-QDoubleSpinBox 例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class spindemo(QWidget):
def __init__(self, parent=None):
super(spindemo, self).__init__(parent)
self.setWindowTitle("SpinBox 例子")
self.resize(300, 100)

layout = QFormLayout()

self.label = QLabel("current value:")
# self.label.setAlignment(Qt.AlignCenter)
self.label.setAlignment(Qt.AlignLeft)
layout.addWidget(self.label)

self.spinbox = QDoubleSpinBox()
layout.addRow(QLabel('默认显示'), self.spinbox)
self.spinbox.valueChanged.connect(lambda: self.on_valuechange(self.spinbox))

self.spinbox_decimal = QDoubleSpinBox()
self.spinbox_decimal.setDecimals(4)
layout.addRow(QLabel('显示4位小数'), self.spinbox_decimal)
self.spinbox_decimal.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_decimal))

label = QLabel("步长和范围:")
self.spinbox_int = QDoubleSpinBox()
self.spinbox_int.setRange(-20, 20)
self.spinbox_int.setMinimum(-10)
self.spinbox_int.setSingleStep(2)
self.spinbox_int.setValue(0)
layout.addRow(label, self.spinbox_int)
self.spinbox_int.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_int))

label = QLabel("循环:")
self.spinbox_wrap = QDoubleSpinBox()
self.spinbox_wrap.setRange(-20, 20)
self.spinbox_wrap.setSingleStep(5)
self.spinbox_wrap.setWrapping(True)
layout.addRow(label, self.spinbox_wrap)
self.spinbox_wrap.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_wrap))

label = QLabel("前后缀")
self.spinbox_price = QDoubleSpinBox()
self.spinbox_price.setRange(0, 999)
self.spinbox_price.setSingleStep(1)
self.spinbox_price.setPrefix("¥")
self.spinbox_price.setSuffix("/每个")
self.spinbox_price.setValue(99)
layout.addRow(label, self.spinbox_price)
self.spinbox_price.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_price))

self.groupSeparatorSpinBox = QDoubleSpinBox()
self.groupSeparatorSpinBox.setRange(-99999999, 99999999)
self.groupSeparatorSpinBox.setValue(1000)
self.groupSeparatorSpinBox.setGroupSeparatorShown(True)
groupSeparatorChkBox = QCheckBox()
groupSeparatorChkBox.setText("千分隔符:")
groupSeparatorChkBox.setChecked(True)
layout.addRow(groupSeparatorChkBox, self.groupSeparatorSpinBox)
groupSeparatorChkBox.toggled.connect(self.groupSeparatorSpinBox.setGroupSeparatorShown)
self.groupSeparatorSpinBox.valueChanged.connect(lambda: self.on_valuechange(self.groupSeparatorSpinBox))

label = QLabel("特殊文本:")
self.spinbox_zoom = QDoubleSpinBox()
self.spinbox_zoom.setRange(0, 1000)
self.spinbox_zoom.setSingleStep(10)
self.spinbox_zoom.setSuffix("%")
self.spinbox_zoom.setSpecialValueText("Automatic")
self.spinbox_zoom.setValue(100)
layout.addRow(label, self.spinbox_zoom)
self.spinbox_zoom.valueChanged.connect(lambda: self.on_valuechange(self.spinbox_zoom))

self.setLayout(layout)

def on_valuechange(self, spinbox):
self.label.setText("current value:" + str(spinbox.value()))


if __name__ == '__main__':
app = QApplication(sys.argv)
ex = spindemo()
ex.show()
sys.exit(app.exec())

下拉列表框控件QComBox

下拉列表框控件提供一个下拉式选项列表供用户选择,它可以最大限度地减少所占窗口的面积。

下拉列表框控件的类是 QComboBox,它继承自QWidget。下拉列表框由多行内容构成,下拉列表框控件可以看成是一个 QLineEdit 和一个列表控件的组合体,每行除有必要的文字外,还可以设置图标。

下拉列表中的内容可以是程序运行前就确定的内容,也可以是用户临时添加的内容。当单击下拉列表框时,下拉列表框呈展开状态,显示多行选项供用户选择,根据用户选择的内容发送信号,进行不同的动作。

通常下拉列表框处于折叠状态,只显示一行当前内容。

QComboBox 除了显示可见的文字和图标外,还可以给每行设置一个关联数据,数据类型任意,可以是字符串、文字、图片、类的实例等.通过客户选择的内容,可以读取关联的数据。

可以采用下列方式创建QComboBox类的实例对象其中parent是继承自QWidget的窗口或容器控件

1
2
3
from PySide6.QtWidgets import QComboBox

QComboBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

下拉列表框控件QComboBox的常用方法

QComboBox由一列多行内容构成每行称为一个项(item)。

QComboBox的方法主要是有关项的方法,可以添加项、插入项和移除项。如果用Qt Designer 设计界面,则双击QComboBox控件,可以为QComboBox添加项。

下拉列表框控件QComboBox的常用方法如表所示,主要方法介绍如下。

  • 在QComboBox控件中添加项的方法有

    • addItem(str[,userData=None])
    • addItem(QIcon;str[,userData=None])
    • addItems(Sequence[str])

    前两种只能逐个增加,最后一种可以把一个元素是字符串的迭代序列(列表、元组)加人到 QComboBox中。前两种在增加项时,可以为项关联任何类型的数据。

  • 在QComboBox控件中插人项的方法有

    • insertItem(index:int,str[;userData=None])
    • insertItem(index: int, QIcon, str[,userData=None])
    • insertItems(index;int,Sequence[str])。

    当插人项时,用setInsertPolicy(QComboBox.InsertPolicy)方法可以设置插入项的位置其中QComboBoxInsertPolicy 的取值如表2所示:

    QComboBox.InsertPolicy的取值 说明
    QComboBox.NoInsert 不允许插人项
    QComboBox.InsertAtTop 在顶部插人项
    QComboBox.InsertAtCurrent 在当前位置插入项
    QComboBox.InsertAtBottom 在底部插人项
    QComboBox.InsertAfterCurrent 在当前项之后插入
    QComboBox.InsertBeforeCurrent 在当前项之前插入
    QComboBox.InsertAlphabetically 根据字母顺序插人项
  • 移除

    • 用removeItem(index:int)方法可以从列表中移除指定索引值的项;
    • 用clear()方法可以清除所有的项;
    • 用clearEditText()方法可以清除显示的内容,而不影响项
  • 项编辑和获取

    • 通过设置 setEditable(True),即QComboBox 是可编辑状态,可以输人文本,按Enter键后文本将作为项插入列表中在添加和插入项时,可以定义关联的数据

    • 另外也可以用setItemData(index:int,any[,role=QtUserRole])方法为索引号是int 的项追加关联的数据,数据类型任意。

    • 可以为项定义多个关联数据,第1个数据的角色值 role=QtUserRole(Q.UserRole 的值为256),当追加第2个关联的数据时取role=Qt.UserRole+1,追加第3个关联的数据时取role=QtUserRole+2依次类推

    • 用currentData(role=QtUserRole+i)或itemData(index:int,role=Qt.UserRole十i)方法获取关联的数据,其中role=QtUserRole+i表示第i个关联数据的索引,i=0,1,2,

  • 宽高调整策略

    • 利用setSizeAdjustPolicy(QComboBox,SizeAdjustPolicy)方法可以设置QComboBox的宽度和高度根据项的文字的长度进行调整,其中 QComboBox.SizeAdjustPolicy可以取 :
      • QComboBox.AdjustToContents(根据内容调整)
      • QComboBox.AdjustToContentsOnFirstShow(根据第1次显示的内容调整)
      • QComboBox.AdjustToMinimumContentsLengthWithIcon(根据最小长度调整)
QComboBox的方法及参数类型 说明
addItem(str,userData=None) 添加项,并可设置关联的任意类型的数据
addItem(QIcon,str,userData=None) 添加带图标的项
addItems(Sequence[str]) 用列表、元组等序列添加多个项
insertItem(index:int,str,userData=None) 在索引处插入项
insertItem(index; int,QIcon,str,userData=None) 在索引处插入带图标的项
insertItems(index: int,Sequence[str]) 在索引处插人多个项
renoveItem(index:int) 根据索引值移除项
count() 返回项的数量
currentIndex() 返回当前项的索引
currentText() 返回当前项的文本
[slot]setCurrentText(str) 设置当前显示的文本
[slot]setCurrentIndex(index:int) 根据索引设置为当前项
[slot]setEditText(str) 设置编辑文本
setEditable(bool) 设置是否可编辑
setIconSize(QSize) 设置图标的尺寸
set1nsertPolicy(QComboBox.InsertPolicy) 设置插入项的策略
setltemData(index: int,any[.role=Qt.UserRole]) 根据索引设置关联数据
setItemIcon(index: int.QIcon) 根据索引设置图标
setltemText(index: int.str) 根据索引设置文本
setMaxCount(int) 设置项的最大数量,超过部分不显示
setMaxVisibleltems(int) 设置最多能显示的项的数量,超过显示滚动条
setMinimumContentsLength(int) 设置子项目显示的最小长度
setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy) 设置宽度和高度的调整策略
serValidator(QValidator) 设置输入内容的合法性验证
currentData(role=Qt.UserRole) 获取当前项关联的数据
iconSize() 返回图标尺寸 QSize
itemIcon(index:int) 根据索引获取图标QIcon
itemText(index:int) 根据索引获取项的文本
showPopup()、hidePopup() 显示或隐裁列表
itemData(index: int,role=Qt.UserRole) 根据索引获取项的关联数据
[slot]clear() 从控件中清空所有的项
[slot]clearEditText() 只清空可编辑的文字,不影响项

下拉列表框控件QComboBox的信号

下拉列表框控件QComboBox的信号如表所示

QComboBox的信号 说明
activated(text:str) 由用户激活某项时发送信号,而程序激活时不发送信号。如果有两个项的名称相同,则只发送带整数参数的信号
activated(index: int) 由用户激活某项时发送信号,而程序激活时不发送信号。如果有两个项的名称相同,则只发送带整数参数的信号
currentIndexChanged(text:str) 用户或程序改变当前项的索引时发送信号
currentIndexChanged(index:int) 用户或程序改变当前项的索引时发送信号
highlighted(text: str) 当光标经过列表的项时发送信号
highlighted(index: int) 当光标经过列表的项时发送信号
editTextChanged(text:str) 在可编辑状态下,改变可编辑文本时发送信号
currentTextChanged(text: str) 用户或程序改变当前项的文本时发送信号

QComboBox 案例:地区选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import sys

from PySide6 import QtWidgets

"""
QComboBox 案例:地区选择

由2个combobox组成,分别用于选择省、市,选中城市后获得对应的邮政编码

当第1个combobox的选中改变时,第2个combobox中的选项自动变换至对应列表
当第2个combobox的选中改变时,使用QLabel显示该地的邮政编码
"""


class MyWidget(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle("QComboBox-案例")
self.resize(800, 600)

# 创建存储城市信息的字典
self.city_dic = {
"北京": {
"东城区": "100010",
"西城区": "100032",
"朝阳区": "100020",
"丰台区": "100071",
"石景山区": "100043",
"海淀区": "100080",
},
"上海": {"黄浦区": "200001", "徐汇区": "200030", "长宁区": "200050"},
}
self.setup_ui()

def setup_ui(self) -> None:
"""设置界面并初始化"""

self.province_cbb = QtWidgets.QComboBox()
self.city_cbb = QtWidgets.QComboBox()
self.code_label = QtWidgets.QLabel()

# 使用布局管理器布局控件
layout = QtWidgets.QHBoxLayout()
layout.addWidget(self.province_cbb)
layout.addWidget(self.city_cbb)
layout.addWidget(self.code_label)
self.setLayout(layout)

# 初始化并连接信号
self.province_cbb.addItems(self.city_dic.keys())
self.province_cbb.currentTextChanged.connect(self.province_changed) # type: ignore
self.city_cbb.currentIndexChanged.connect(self.city_changed) # type: ignore

# 手动执行一次以为城市combobox添加初始项
self.province_changed(self.province_cbb.currentText())

def province_changed(self, pro_name: str) -> None:
"""
省份改变时的槽函数 \n
:param pro_name: 新的省名
:return: None
"""
# 先清空之前的条目
self.city_cbb.clear()

# 再添加条目
cities = self.city_dic[pro_name]
for city_name, city_code in cities.items():
# 将城市名作为text、邮政代码作为data添加条目
self.city_cbb.addItem(city_name, city_code)

def city_changed(self, item_index: int) -> None:
"""
城市改变时的槽函数 \n
:param item_index: 新的选中的条目索引
:return: None
"""
city_name = self.city_cbb.itemText(item_index)
city_code = self.city_cbb.itemData(item_index)
self.code_label.setText(f"{city_name}的邮政编码为{city_code}")
self.code_label.adjustSize() # 调节标签控件尺寸以适应新的内容


if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MyWidget()
window.show()
sys.exit(app.exec())

字体选择下拉框QFontComboBox

PySide6专门定义了一个字体下拉列表框控件QFontComboBox,列表内容是操作系统支持的字体,这个控件主要用在工具栏中,用于选择字体。

1
2
3
from PySide6.QtWidgets import QFontComboBox

QFontComboBox(parent: Union[PySide6.QtWidgets.QWidget, NoneType] = None) -> None

QFontComboBox 方法

QFontComboBox 继承自QComboBox,因此具有QComboBox 的方法。

QFontComhoBox也有自己的方法主要有:

  • setCurrentFont(QFont)(设置当前的字体,槽函数)
  • currentFont()(获取当前字体)
  • setFontFilters(QFontComboBox.FontFilter)(设置字体列表的过滤器),其中字体过滤器可以取:
    • QFontComboBox.AllFonts(显示所有字体)
    • QFontComboBox.ScalableFonts(显示可缩放字体)
    • QFontComboBox,NonScalableFonts(显示不可缩放的字体)
    • QFontComboBox,MonospacedFonts(显示等宽字体)
    • QFontComboBox.ProportionalFonts(显示比例字体)

QFontComhoBox也有自己的信号:

QFontComhoBox的特有信号为currentFontChanged(QFont)当前字体更改时发送

QFontComboBox 例子

image-20230319025032022

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:02
# File_name: 03-QFontComboBox 例子.py


import sys
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import *
import os

os.chdir(os.path.dirname(__file__))


class FontComboBoxDemo(QMainWindow):
def __init__(self, *args, **kwargs):
super(FontComboBoxDemo, self).__init__(*args, **kwargs)
self.setWindowTitle("QFontComboBox案例")
widget = QWidget()
self.setCentralWidget(widget)
layout = QVBoxLayout(widget)
self.text_show = QTextBrowser()

layout.addWidget(self.text_show)

toolbar = self.addToolBar('toolbar')

# 设置字体,all
font = QFontComboBox()
font.currentFontChanged.connect(lambda font: self.text_show.setFont(font))
toolbar.addWidget(font)

# 设置字体,仅限中文
font2 = QFontComboBox()
font2.currentFontChanged.connect(lambda font: self.text_show.setFont(font))
font2.setWritingSystem(QFontDatabase.SimplifiedChinese)
toolbar.addWidget(font2)

# 设置字体,等宽字体
font3 = QFontComboBox()
font3.currentFontChanged.connect(lambda font: self.text_show.setFont(font))
font3.setFontFilters(QFontComboBox.MonospacedFonts)
toolbar.addWidget(font3)

# 设置字体大小
font_size_list =[str(i) for i in range(5, 40, 2)]
combobox = QComboBox(self, minimumWidth=60)
combobox.addItems(font_size_list)
combobox.setCurrentIndex(-1)
combobox.activated.connect(lambda x: self.set_fontSize(int(font_size_list[x])))
toolbar.addWidget(combobox)

# 加粗按钮
buttonBold = QToolButton()
buttonBold.setShortcut('Ctrl+B')
buttonBold.setCheckable(True)
buttonBold.setIcon(QIcon("./images/Bold.png"))
toolbar.addWidget(buttonBold)
buttonBold.clicked.connect(lambda: self.setBold(buttonBold))

# 倾斜按钮
buttonItalic = QToolButton()
buttonItalic.setShortcut('Ctrl+I')
buttonItalic.setCheckable(True)
buttonItalic.setIcon(QIcon("./images/Italic.png"))
toolbar.addWidget(buttonItalic)
buttonItalic.clicked.connect(lambda: self.setItalic(buttonItalic))

self.text_show.setText('显示数据格式\n textEdit \n Python')

def setBold(self, button):
if button.isChecked():
self.text_show.setFontWeight(QFont.Bold)
else:
self.text_show.setFontWeight(QFont.Normal)
self.text_show.setText(self.text_show.toPlainText())

def setItalic(self, button):
if button.isChecked():
self.text_show.setFontItalic(True)
else:
self.text_show.setFontItalic(False)
self.text_show.setText(self.text_show.toPlainText())

def set_fontSize(self, x):
self.text_show.setFontPointSize(x)
self.text_show.setText(self.text_show.toPlainText())


if __name__ == "__main__":
app = QApplication(sys.argv)
w = FontComboBoxDemo()
w.show()
sys.exit(app.exec())

滚动条控件QScrolIBar和滑块控件QSlider

滚动条控件QScrollBar 和滑块控件QSlider 用于输人整数通过滚动条和滑块的位置来确定控件输人的值。

滚动条和滑块控件的外观都有水平和竖直两种样式。这两个控件的功能相似,外观有所不同,QScrollBar 两端有箭头而QSlider没有,QSlider可以设置刻度。

用QScrolIBar 和QSlider 创建实例对象的方法如下所示,QScrollBar 类和QSlider 类是从 QAbstraotSlider 类继承而来的。

  • parent是窗口或者容器类控件
  • Qt.Orientation.Orientation 可以取
    • Qt.Orientation.Horizontal 水平
    • Qt.Orientation.Vertical 垂直
1
2
3
4
5
6
7
from PySide6.QtWidgets import QScrollBar, QSlider

QScrollBar(arg__1: PySide6.QtCore.Qt.Orientation, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QScrollBar(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

QSlider(orientation: PySide6.QtCore.Qt.Orientation, parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None
QSlider(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

滚动条控件QScrollBar 和滑块控件QSlider 的常用方法

QScrollBar和QSlider 都是从 QAbstractSlider类继承而来的,因此它们的多数方法是相同的。

QScrollBar和QSlider 的常用方法如表所示,主要方法介绍如下:

  • 滑块的位置和值

    • 通过 setMaximum()和setMinium()方法来设置也可以用setRange()方法来设置;
    • 滑块的当前值可以通过setValue()和setPosition()方法来设置,通过 value()方法可以获取滑块的当前值
  • 步长

    • 鼠标或键盘改变

      • 可以用鼠标拖动滑块的位置或单击两端的箭头
      • 如果焦点在控件上,还可以通过键盘上的左右箭头来控制
        • 如果用键盘来移动滑块的位置QScrollBar 控件默认是不获得焦点的,可以通过setFocusPolicy(Qt.FocusPolicy)方法设置其能获得焦点,例如Qt.FocusPolicy 取 QtClickFocus 可以通过单击获得焦点,取QtTabFocus 可以通过按 Tab键获得焦点当设置setTracking()为 False时,用鼠标拖动滑块连续移动时(鼠标按住不松开)控件不发送valueChanged 信号。
      • 还可以单击滑块的滑行轨道,或者用键盘上的PageUp和PageDown键来改变值
      • 值的增加或减少的步长由setSingleStep()方法来设置
    • 移动控件改变

      • 在 Windows 系统中光标移动到 slider 上使用滚轮操作时的默认步长是min(3*singleStep;pageStep)。
    • setInvertedControls()方法可以使键盘上的PageUP和PageDown 键的作用反向。

  • 设置刻度

    • QSlider可以设置刻度,方法是 setTickInterval(int),其中参数int 是刻度间距。
    • 用tickInterval()方法可以获取刻度间距值,
    • 用setTickPosition(QSliderTickPosition)方法可以设置刻度的位置,
    • 用tickPosition()方法可以获取刻度位置其中 QSlider.TickPosition可以取:
      • QSlider.NoTicks
      • QSlider.TicksBothSides
      • QSlider.TicksAbove
      • QSlider.TicksBelow
      • QSlider.TicksLeft
      • QSlider.TicksRight。
    • 用setTickPosition(QSlider.TickPosition)方法设置 QSlider 控件刻度的位置,其中QSlider,TickPosition 可取:
      • QSlider.NoTicks
      • QSlider.TicksBothSides
      • QSlider.TicksAbove
      • QSlider.TicksBelow
      • QSlider.TicksLeft
      • QSlider.TicksRight
QScrollBar 和 QSlider的方法及参数类型 说 明
[slot]setOrientation(Qt.Orientation) 设置控件的方向,可设置为水平或竖直方向
orientation() 获取方向
setInvertedAppearance(bool) 设置几何外观左右或上下颠倒
invertedAppearance() 获取几何外观是否颠倒
setInvertedControls(bool) 设置键盘上PageUP和PageDown键是否进行逆向控制
invertedControls() 获取是否进行逆向控制
setMaximum(int) 设置最大值
maximum() 获取最大值
setMinimum(int) 设置最小值
minimum() 获取最小值
setPageStep(int) 设置每次单击滑动区域,控件值的变化量
pageStep() 获取单击滑块区域,控件值的变化量
[slot]setRange(int,int) 设置最小值和最大值
setSingleStep(int) 设置单击两端的箭头或拖动滑块时,控件值的变化量
singleStep() 获取单击两端的箭头或拖动滑块时,控件值的变化量
setSliderDown(bool) 设置滑块是否被按下,该值的设置会影响isSliderDown 的返回值
isSliderDown() 用鼠标移动滑块时,返回True;单击两端的箭头或滑动 区域时,返回False
setSliderPosition(int) 设置滑块的位置
sliderPosition() 获取滚动条的位置
setTracking(bool) 设置是否追踪滑块的连续变化
[slot]setValue(int) 设置滑块的值
value() 获取滑块的值
setTicklnterval(int) 设置滑块两个刻度之间的值,仅用于 QSlider 控件
setTickPosition(QSlider.TickPosition) 设置刻度的位置,仅用于 QSlider 控件

滚动条控件QScrollBar和滑块控件QSlider 的信号

滚动条控件QScrollBar 和滑块控件 QSlider 的信号如表所示

  • 最常用的信号是valueChanged(value:int)

  • actionTriggered(action:int)信号在用户用鼠标或键盘键改变滑块位置时发送,根据改变方式的不同,信号的参数值也不同action 的值可以取以下值,对应的值分别是0~7,例如

    • 单击两端的箭头改变滑块位置,参数的值是1或2
    • 如果单击滑块的轨道改变滑块位置,参数的值是3或4
    • 如果拖动滑块参数的值是 7
    QAbstractSlider.SliderNoAction
    QAbstractSlider.SliderSingleStepAdd
    QAbstractSlider.SliderSingleStepSub
    QAbstractSlider.SliderPageStepAdd
    QAbstractSlider.SliderPageStepSub
    AbstractSlider.SliderToMinimum
    QAbstractSlider.SliderToMaximum
    QAbstractSlider.SliderMove
QScrollBar和QSlider的信号及参数类型 说 明
valueChanged(value:int) 当值发生变化时发送信号
rangeChanged(min:int, max: int) 当最小值和最大值发生变化时发送信号
sliderMoved(value:int) 当滑块移动时发送信号
sliderPressed() 当按下滑块时发送信号
sliderReleased() 当释放滑块时发送信号
actionTriggered(action:int) 当用鼠标改变滑块位置时发送信号,参数 action根据改 变方式的不同也会不同

QScrollBar 例子

image-20230319025311121

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:56
# File_name: 02-QScrollBar 例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()

def initUI(self):
hbox = QHBoxLayout()
self.label = QLabel("拖动滑动条去改变颜色")
self.label.setFont(QFont("Arial", 16))
hbox.addWidget(self.label)

self.scrollbar1 = QScrollBar()
self.scrollbar1.setMaximum(255)
self.scrollbar1.sliderMoved.connect(self.sliderval)
hbox.addWidget(self.scrollbar1)

self.scrollbar2 = QScrollBar()
self.scrollbar2.setMaximum(255)
self.scrollbar2.setSingleStep(5)
self.scrollbar2.setPageStep(50)
self.scrollbar2.setValue(150)
self.scrollbar2.setFocusPolicy(Qt.StrongFocus)
self.scrollbar2.valueChanged.connect(self.sliderval)
hbox.addWidget(self.scrollbar2)

self.scrollbar3 = QScrollBar()
self.scrollbar3.setMaximum(255)
self.scrollbar3.setSingleStep(5)
self.scrollbar3.setPageStep(50)
self.scrollbar3.setValue(100)
self.scrollbar3.setFocusPolicy(Qt.TabFocus)
self.scrollbar3.valueChanged.connect(self.sliderval)
hbox.addWidget(self.scrollbar3)

self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QScrollBar 例子')
self.setLayout(hbox)

def sliderval(self):
value_tup =(self.scrollbar1.value(), self.scrollbar2.value(), self.scrollbar3.value())
_str = "拖动滑动条去改变颜色:\n左边不支持键盘,\n中间通过tab键or点击获取焦点,\n右边只能通过tab键获取焦点。\n当前选中(%d,%d,%d)" % value_tup
palette = QPalette()
palette.setColor(QPalette.WindowText, QColor(*value_tup, 255))
self.label.setPalette(palette)
self.label.setText(_str)


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Example()
demo.show()
sys.exit(app.exec())

QSlider 例子

image-20230319025744592

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:57
# File_name: 05-QSlider 例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class SliderDemo(QWidget):
def __init__(self, parent=None):
super(SliderDemo, self).__init__(parent)
self.setWindowTitle("QSlider 例子")
self.resize(300, 100)

layout = QVBoxLayout()
self.label = QLabel("Hello Qt for Python")
self.label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.label)

# 水平滑块
self.slider_horizon = QSlider(Qt.Horizontal)
self.slider_horizon.setMinimum(10)
self.slider_horizon.setMaximum(50)
self.slider_horizon.setSingleStep(3)
self.slider_horizon.setPageStep(10)
self.slider_horizon.setValue(20)
self.slider_horizon.setTickPosition(QSlider.TicksBelow)
self.slider_horizon.setTickInterval(5)
layout.addWidget(self.slider_horizon)

# 垂直滑块
self.slider_vertical = QSlider(Qt.Vertical)
self.slider_vertical.setMinimum(5)
self.slider_vertical.setMaximum(25)
self.slider_vertical.setSingleStep(1)
self.slider_vertical.setPageStep(5)
self.slider_vertical.setValue(15)
self.slider_vertical.setTickPosition(QSlider.TicksRight)
self.slider_vertical.setTickInterval(5)
self.slider_vertical.setMinimumHeight(100)
layout.addWidget(self.slider_vertical)

# 连接信号槽
self.slider_horizon.valueChanged.connect(lambda: self.valuechange(self.slider_horizon))
self.slider_vertical.valueChanged.connect(lambda: self.valuechange(self.slider_vertical))

self.setLayout(layout)

def valuechange(self, slider):
size = slider.value()
self.label.setText('选中大小:%d' % size)
self.label.setFont(QFont("Arial", size))


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = SliderDemo()
demo.show()
sys.exit(app.exec())

仪表盘控件QDial

仪表盘控件 QDial与滑块控件 QSlider 类似,只不过是把滑槽由直线变成圆。仪表盘控件可以设置仪表盘上显示的刻度,最大值刻度和最小值刻度可以重合,也可以不重合。

QDial 继承自 QAbstractSlider,继承了QAbstractSlider 的方法和信号。

用QDial类创建仪表盘实例的方法如下所示其中参数parent是仪表盘控件所在的窗口或容器控件。

1
2
3
from PySide6.QtWidgets import QDial

QDial(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

仪表盘控件QDial的常用方法

仪表盘控件QDial的常用方法如表所示。

  • 用setNotchesVisible(visible:bool)方法设置刻度是否可见,
  • 用setNotchTarget(target: float)方法设置刻度之间的像素距离,
  • 用setWrapping(on:bool)方法设置最大值刻度和最小值刻度是否重合,
  • 用setRange(min:int,max;int)方法设置最小值刻度和最大值刻度所代表的值
  • 用setValue(int)方法设置滑块当前指向的值,
  • 用value()方法获取滑块的值。
QDial的方法及参数类型 返回值的类型 说 明
[slot]setNotchesVisible(visible:bool) None 设置刻度是否可见
notchesVisible() bool 获取刻度是否可见
setNotchTarget(target:float) None 设置刻度之间的距离(像素)
notchTarget() float 获取刻度之间的距离
[slot]setWrapping(on: bool) None 设置最大刻度和最小刻度是否重合
wrapping() bool 获取最大值和最小值刻度是否重合
notchSize() int 获取相邻刻度之间的值
setRange(min: int,max: int) None 设置刻度代表的最小值和最大值
setMaximum(int) None 设置刻度代表的最大值
setMinimum(int) None 设置刻度代表的最小值
setInvertedAppcarance(bool) None 设置刻度反向
[slot]setValue(int) None 设置滑块当前所在的位置
value() int 获取滑块的值
setPageStep(int) None 设置按PgUp键和PgDn键时滑块移动的 距离
setSingleStep(int) None 设置按上下左右箭头键时滑块移动的距离
setTracking(enable: bool) None 设置移动滑块时是否连续发送 valueChanged(int)信号

QDial控件的信号

QDial控件的信号与 QSlider 控件的信号相同

滚动条控件QScrollBar 和滑块控件 QSlider 的信号如表所示

  • 最常用的信号是valueChanged(value:int)

  • actionTriggered(action:int)信号在用户用鼠标或键盘键改变滑块位置时发送,根据改变方式的不同,信号的参数值也不同action 的值可以取以下值,对应的值分别是0~7,例如

    • 单击两端的箭头改变滑块位置,参数的值是1或2
    • 如果单击滑块的轨道改变滑块位置,参数的值是3或4
    • 如果拖动滑块参数的值是 7
    QAbstractSlider.SliderNoAction
    QAbstractSlider.SliderSingleStepAdd
    QAbstractSlider.SliderSingleStepSub
    QAbstractSlider.SliderPageStepAdd
    QAbstractSlider.SliderPageStepSub
    AbstractSlider.SliderToMinimum
    QAbstractSlider.SliderToMaximum
    QAbstractSlider.SliderMove
QScrollBar和QSlider的信号及参数类型 说 明
valueChanged(value:int) 当值发生变化时发送信号
rangeChanged(min:int, max: int) 当最小值和最大值发生变化时发送信号
sliderMoved(value:int) 当滑块移动时发送信号
sliderPressed() 当按下滑块时发送信号
sliderReleased() 当释放滑块时发送信号
actionTriggered(action:int) 当用鼠标改变滑块位置时发送信号,参数 action根据改 变方式的不同也会不同

QDial 例子

image-20230319025631241

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/15 0:48
# File_name: 03-QDial 例子.py


import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class dialDemo(QWidget):
def __init__(self, parent=None):
super(dialDemo, self).__init__(parent)
self.setWindowTitle("QDial 例子")
self.resize(600, 600)

layout = QVBoxLayout()
self.label = QLabel("Hello Qt for Python")
self.label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.label)

# 普通qdial
self.dial1 = QDial()
self.dial1.setMinimum(10)
self.dial1.setMaximum(50)
self.dial1.setSingleStep(3)
self.dial1.setPageStep(5)
self.dial1.setValue(20)
layout.addWidget(self.dial1)

# 开启循环
self.dial_wrap = QDial()
self.dial_wrap.setMinimum(5)
self.dial_wrap.setMaximum(25)
self.dial_wrap.setSingleStep(1)
self.dial_wrap.setPageStep(5)
self.dial_wrap.setValue(15)
self.dial_wrap.setWrapping(True)
self.dial_wrap.setMinimumHeight(100)
layout.addWidget(self.dial_wrap)

# 连接信号槽
self.dial1.valueChanged.connect(lambda: self.valuechange(self.dial1))
self.dial_wrap.valueChanged.connect(lambda: self.valuechange(self.dial_wrap))

self.setLayout(layout)

def valuechange(self, dial):
size = dial.value()
self.label.setText('选中大小:%d' % size)
self.label.setFont(QFont("Arial", size))


if __name__ == '__main__':
app = QApplication(sys.argv)
app.setWheelScrollLines(2)
demo = dialDemo()
demo.show()
sys.exit(app.exec())

进度条控件QProgressBar

进度条控件QProgressBar 通常用来显示一项任务完成的进度例如复制文件导出数据的进度。进度条QProgressBar是从QWidget 继承而来的。

用QProgressBar类创建实例对象的方法如下所示其中 parent 是窗口或者容器类控件。
QProgressBar(parent;QWidget=None)

进度条控件QProgressBar的常用方法

进度条控件QProgressBar 的常用方法如表所示,主要方法介绍如下

  • 值设置

    • 设置进度条的最小值可以用setRange(int,int)方法,也可以用setMinimum(int)和setMaximum(int)方法;

    • 设置当前值用setValue(int)方法;

    • 获取当前值用value()方法;

    • 用reset()方法可以清空进度,重新回到初始位置。

    • 当不知道总的工作量,或工作量还无法估计时,可以设置进度条的最大值和最小值都是 0。进度条显示繁忙指示时,不会显示当前的值。

  • 进度条的方向

    • 用setOrientation(Qt.Orientation)方法可以设置进度条的方向,参数Q.Orientation 可以取:

      • Qt.Horizontal
      • Qt.Vertical;
    • 用setTextDirection(QProgressBar,Direction)方法设置进度条上文本的方向,参数 QProgressBar.Direction可以取:

      • QProgressBar,TopToBottom 文本顺时针旋转 90°
      • QProgressBar.BottomToTop 逆时针旋转 90
    • 设置文本在进度条上的对齐方式

      • 用setAlignment(Qt.Alignment)方法,如果Qt.Alignment 取 Qt.AlignHCenter,文本将会放置到进度条的中间。
    • 用setFormat(str)方法设置显示的文字格式,

      • 在文字中%p%表示百分比值

      • %v表示当前值

      • %m 表示总数,

      • 默认显示的是%p%,例如 setFormat(“当前步数%v/总步数%m,%p%”);获取文本格式用ormat)方法;

      • 获取格式化的文本用text()方法。

QProgressBar的方法及参数类型 返回值的类型 说明
[slot]setMaximum(int) None 设置最大值
[slot]setMinimurm(int) None 设置最小值
[slot]setRange(int,int) None 设置范围(最小值和最大值)
maximum()、minimum() int 获取最大值和最小值
[slot]setOrientation(Qt.Orientation) None 设置方向
orientation() Qt.Orientation 获取方向
setAlignment(Qt.Alignment) None 设置文本对齐方式
alignment() Qt.Alignment 获取文本对齐方式
setFormat(str) None 设置文本的格式
format() str 获取文本的格式
resetFormat() None 重置文本格式
setInverted Appearance(bool) None 设置外观是否反转
invertedAppearance() bool 获取外观是否反转
setTextDirection(QProgressBar.Direction) None 设置进度条文本的方向
textDirection() QProgressBar.Direction 获取进度条文本的方向
setTextVisible(bool) None 设置进度条文本是否可见
isTextVisible() bool 获取进度条文本是否可见
[slot]setValue(int) None 设置当前值
value() int 获取当前值
text() Str 获取文本
[slot]reset() None 重置进度条,返回初始位置

进度条控件QProgressBar的信号

进度条控件QProgressBar 只有一个信号 valueChanged(value;int),当值发生变化时发送该信号。

进度条控件QProgressBar例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import sys

from PySide6.QtCore import QTimer
from PySide6.QtGui import Qt
from PySide6.QtWidgets import QWidget, QProgressBar, QPushButton, QApplication


class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QProgressBar")
self.resize(500, 500)
self.move(400, 250)
self.setup_ui()

def setup_ui(self):
pb = QProgressBar(self)
pb.move(100, 100)

timer = QTimer(pb)

def change_progress():
if pb.value() == pb.maximum():
timer.stop()
pb.setValue(pb.value() + 1)

timer.timeout.connect(change_progress)
timer.start(500)

pb.valueChanged.connect(lambda val: print(f"当前进度值为{val}"))


if __name__ == "__main__":
app = QApplication(sys.argv)

window = Window()
window.show()

sys.exit(app.exec())

尺寸手柄QSizeGrip

此小部件的工作方式类似于标准的Windows调整大小手柄。在X11版本中,如果X11窗口管理器不支持必要的现代后ICCCM规范,则该调整大小句柄的工作方式通常与系统提供的不同。
将此小部件放在小部件树中的任何位置,用户可以使用它来调整顶层窗口或设置了SubWindow标志的任何小部件的大小。通常,这应该在右下角。

注意,QStatusBar已经使用了这个小部件,所以如果有一个状态栏(例如,您正在使用QMainWindow),那么您不需要显式使用这个小部件。QDialog也是如此,只需调用setSizeGripEnabled()即可。
在某些平台上,当窗口全屏显示或最大化时,QSizeGrip会自动隐藏。

在macOS上,尺寸夹不再是人机界面指南的一部分,除非在QMdiSubWindow中使用,否则不会显示。在要在主窗口中显示的尺寸夹点上设置另一种样式。

QSizeGrip类继承了QWidget,并重新实现了mousePressEvent()和mouseMoveEvent()函数,以提供调整大小功能,以及paintEvent()功能,以渲染大小夹控件。

构造一个调整大小的角作为给定父控件的子控件

1
2
3
from PySide6.QtWidgets import QSizeGrip

QSizeGrip(parent: PySide6.QtWidgets.QWidget) -> None

image-20230319030549111

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:03
# File_name: 尺寸手柄QSizeGrip例子.py


import sys
from PySide6.QtWidgets import *


class qsizegripDemo(QWidget):
def __init__(self, parent=None):
super(qsizegripDemo, self).__init__(parent)
self.setWindowTitle("QSlider 例子")
self.resize(300, 100)

self.setUi()

def setUi(self):
qsizegrip = QSizeGrip(self)
# 需要自己移动到指定位置


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = qsizegripDemo()
demo.show()
sys.exit(app.exec())

橡皮筋选中QRubberBand

QRubberBand

提供一个矩形或线来指示选择或边界, 一般结合鼠标事件一同协作

如果将父级传递给QRubberBand的构造函数,则橡皮筋将仅显示在其父级内部,但保留在其他子部件的顶部。如果没有传递父级,QRubberBand将充当顶级小部件。

构造方法

调用show()使橡皮筋可见;当橡皮筋不是顶级时也是如此。隐藏或破坏小部件将使橡皮筋消失。橡皮筋可以是矩形或直线(垂直或水平),这取决于构造时给出的形状()。

继承自QWidget

Shape-此枚举指定QRubberBand应具有的形状。这是一个传递给样式系统的绘图提示,可以由每个QStyle解释。

  • QRubberBand.Line QRubberBand可以表示垂直或水平线。几何体仍然是在rect()中给出的,在大多数样式中,线条将填充给定的几何体。
  • QRubberBand.Rectangle QRubberBand可以表示矩形。有些样式会将其解释为填充(通常为半透明)矩形或矩形轮廓。

构造形状为Shape的橡皮筋,父对象为parent。
默认情况下,矩形橡皮筋将使用遮罩,以便矩形的小边框是可见的。某些样式(例如,本机macOS)将更改此设置,并调用setWindowOpcity()以生成半透明的填充选择矩形。

1
2
3
4
from PySide6.QtWidgets import QRubberBand

QRubberBand(Shape: PySide6.QtWidgets.QRubberBand.Shape,
parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

方法

继承自QWidget直接使用move、resize、setGeometry等父类方法即可

方法 说明
move(x, y) 移动到指定xy坐标点
move(QPoint) 移动到指定坐标
resize(width, height) 更新橡皮筋的大小传入宽高值
resize(QSize) 更新橡皮筋的大小传入QSize对象
setGeometry(x:int, y:int, width:int, height:int) 设置显示大小和位置,传入xy坐标和宽高
setGeometry(rect:QRect) 设置显示大小和位置,传入QRect对象
shape() -> QRubberBand.Shape 返回此橡皮筋的形状。
initStyleOption(option:PySide6.QtWidgets.QStyleOptionRubberBand) 用这个QRubberBand的值初始化选项。当子类需要QStyleOptionRubberBand,但不想自己填写所有信息时,此方法非常有用。

橡皮筋通常用于显示新的边界区域(如QSpliter或QDockWidget中的脱离坞)。历史上,这是使用QPainter和XOR实现的,但这种方法并不总是正常工作,因为渲染可能发生在橡皮筋下方的窗口中,但在橡皮筋被”擦除”之前。
每当需要渲染给定区域周围的橡皮筋(或表示一条直线)时,可以创建一个QRubberBand,然后调用setGeometry()、move()或resize()来定位和调整其大小。一种常见的模式是结合鼠标事件执行此操作。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def mousePressEvent(self, event):

origin = event.pos()
if not rubberBand:
rubberBand = QRubberBand(QRubberBand.Rectangle, self)
rubberBand.setGeometry(QRect(origin, QSize()))
rubberBand.show()

def mouseMoveEvent(self, event):

rubberBand.setGeometry(QRect(origin, event.pos()).normalized())

def mouseReleaseEvent(self, event):

rubberBand.hide()
# determine selection, for example using QRect::intersects()
# and QRect::contains().

案例

在一个空白窗口内, 展示多个复选框控件,通过橡皮筋实现批量选中与取消选中效果

效果图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import sys

from PySide6.QtCore import QRect, QSize, QPoint
from PySide6.QtGui import QMouseEvent
from PySide6.QtWidgets import QWidget, QRubberBand, QApplication, QCheckBox


class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QRubberBand-综合案例")
self.resize(500, 500)
self.move(400, 250)
self.setup_ui()

def setup_ui(self):
# 0. 添加许多子控件
for i in range(0, 32):
cb = QCheckBox(self)
cb.setText(f"{i}")
cb.move(i % 4 * 50, i // 4 * 60)

# 1. 创建一个橡皮筋选中控件
self.rb = QRubberBand(QRubberBand.Rectangle, self)

def mousePressEvent(self, a0) -> None:
# 2. 尺寸大小:鼠标点击的位置点,00
self.origin_pos = a0.position().toPoint()
self.rb.setGeometry(QRect(self.origin_pos, QSize()))
# 3. 展示橡皮筋控件
self.rb.show()

def mouseMoveEvent(self, a0) -> None:
# 4. 调整橡皮筋选中的位置以及尺寸
self.rb.setGeometry(QRect(self.origin_pos, a0.position().toPoint()).normalized())
# QRect.normalized() 方法解决反向拖动矩形出现负数的情况

def mouseReleaseEvent(self, a0) -> None:
# 5. 获取橡皮筋控件的尺寸范围
rect = self.rb.geometry()
# 6. 遍历所有子控件,查看哪些子控件在区域范围
for child in self.children():
if rect.contains(child.geometry()) and child.inherits("QCheckBox"):
child.toggle()
self.rb.hide()


if __name__ == "__main__":
app = QApplication(sys.argv)

window = Window()
window.show()

sys.exit(app.exec())

欢迎界面QSplashScreen

QSplashScreen 小组件提供了一个初始屏幕,可以在应用程序启动期间显示。

初始屏幕是通常在启动应用程序时显示的小组件。初始屏幕通常用于启动时间较长的应用程序(例如,需要时间建立连接的数据库或网络应用程序),以向用户提供应用程序正在加载的反馈。

初始屏幕显示在屏幕中央。如果要将其保留在桌面上所有其他窗口之上,则将其添加到初始小部件的窗口标志可能会很有用。WindowStaysOnTopHint

某些 X11 窗口管理器不支持”停留在顶部”标志。解决方案是设置一个计时器,该计时器定期在初始屏幕上调用,以模拟”保持最佳”效果。raise()

最常见的用法是在主小部件显示在屏幕上之前显示初始屏幕。以下代码片段对此进行了说明,其中显示初始屏幕,并在显示应用程序的主窗口之前执行一些初始化任务:

1
2
3
4
5
6
7
8
9
10
11
if __name__ == "__main__":

app = QApplication([])
pixmap = QPixmap(":/splash.png")
splash = QSplashScreen(pixmap)
splash.show()
app.processEvents() ...
window = QMainWindow()
window.show()
splash.finish(window)
sys.exit(app.exec())

用户可以通过用鼠标单击初始屏幕来隐藏它。由于初始屏幕通常在事件循环开始运行之前显示,因此需要定期调用以接收鼠标单击。processEvents()

有时,使用消息更新初始屏幕很有用,例如,在应用程序启动时宣布已建立的连接或加载的模块:

1
2
3
4
5
6
7
8
9
pixmap = QPixmap(":/splash.png")
splash = QSplashScreen(pixmap)
splash.show()
...// Loading some items
splash.showMessage("Loaded modules")
QCoreApplication.processEvents()
...// Establishing connections
splash.showMessage("Established connections")
QCoreApplication.processEvents()

QSplashScreen 通过 showMessage() 函数支持这一点。

如果你想自己绘制,可以用pixmap()获得一个指向初始屏幕中使用的pixmap的指针。

或者可以对 QSplashScreen 进行子类化并重新实现 drawContent()。

如果有多个屏幕,也可以在与主屏幕不同的屏幕上显示初始屏幕。例如:

1
2
3
4
screen = QGuiApplication.screens().at(1)
pixmap = QPixmap(":/splash.png")
splash = QSplashScreen(screen, pixmap)
splash.show()

实例化

1
2
3
4
5
6
from PySide6.QtWidgets import QSplashScreen

QSplashScreen(pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]= Default(PySide6.QtGui.QPixmap),
f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None
QSplashScreen(screen: PySide6.QtGui.QScreen, pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]= Default(PySide6.QtGui.QPixmap),
f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None
  • screen – PySide6.QtGui.QScreen
  • pixmap – PySide6.QtGui.QPixmap
  • f –WindowFlags

这是一个重载函数。此功能允许您指定屏幕的屏幕。

此构造函数的典型用法是,如果您有多个屏幕,并且希望在与主屏幕不同的屏幕上显示启动屏幕。在这种情况下,通过适当的屏幕。构建一个显示像素图的启动屏幕。

不需要设置小部件标志f,除了WindowStaysOnTopHint。

方法

方法 返回值 说明
finish(w) str w – PySide6.QtWidgets.QWidget
在调用close()之前,使启动屏幕等待小部件mainWin显示。
message() str 返回当前显示在初始屏幕上的消息。
pixmap() PySide6.QtGui.QPixmap 返回启动屏幕中使用的位图。
该图像没有通过showMessage()调用绘制的任何文本。
setPixmap(pixmap) None pixmap – PySide6.QtGui.QPixmap
将用作启动屏幕图像的位图设置为pixmap
drawContents(painter) None painter– PySide6.QtGui.QPainter
使用painter.painter绘制闪屏的内容。
默认实现绘制showMessage()传递的消息。如果您想在启动屏幕上绘制自己的图形,请重新实现此功能。
[Slot]clearMessage() None 删除启动屏幕上显示的消息
showMessage(message[,alignment=Qt.AlignLeft[,color=Qt.black]]) None message - – STR
alignment- 对齐方式
color – PySide6.QtGui.QColor
用彩色将消息文本绘制到启动屏幕上,并根据对齐的标志对齐文本。此函数调用重新绘制()以确保立即重新绘制启动屏幕。因此,该消息将与应用程序正在执行的操作(例如加载文件)保持最新。

信号

信号 说明
QSplashScreen.messageChanged(message) message – str
当启动屏幕上的信息发生变化时,会发出此信号。message是新消息,当消息被删除时为空字符串。

例子

首先我们实例化一个QSplashScreen控件,并调用setPixmap()方法设置图片,接着调用show()方法进行显示。

showMessage(str, alignment, color)方法在程序启动画面上显示文字。

alignment为文字在启动画面上的位置,我们这里设为底部居中;color为文字的颜色,我们这里设为白色。

由于程序启动并不耗时,启动画面会一闪而过,所以我们在这里加一行time.sleep(2)来暂停两秒看一下效果。当我们决定可以开始显示主窗口时,调用finish()传入主窗口实例就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:03
# File_name: demo.py


import sys
import time
from PySide6.QtGui import QIcon, QPixmap
from PySide6.QtCore import QMimeData, Qt
from PySide6.QtWidgets import *


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.set_windows()
self.business_demo()

def set_windows(self):
self.resize(300, 300) # 设置窗口大小
self.setWindowTitle("hello world") # 设置窗口标题

def business_demo(self):
qlabel = QLabel(self)
qlabel.setText("hello world") # 设置label文字
qlabel.move((self.width() - qlabel.width()) // 2,(self.height() - qlabel.height()) // 2) # 居中展示文本


if __name__ == '__main__':
app = QApplication(sys.argv)

splash = QSplashScreen()
splash.setPixmap(QPixmap('../../../Resources/Images/Python-code.jpg'))
splash.show()
splash.showMessage('Welcome to Use This PySide6 Notebook~', Qt.AlignBottom | Qt.AlignCenter, Qt.white)
time.sleep(2)

demo = MyWindow()
demo.show()
splash.finish(demo)

sys.exit(app.exec())

日期时间类及控件

日期和时间类也是PySide6 中的基本类,利用它们可以设置纪年法、记录某个日期时间点、对日期时间进行计算等。用户输入日期时间及显示日期时间时需要用到日期时间控件

日历类QCalender

日历类QCalender构造方法

日历类QCalendar 主要用于确定纪年法,当前通用的是公历纪年法,这也是默认值QCalendar 类在 PySide6,QtCore 块中。

用QCalendar 类创建日历实例的方法如下:

1
2
3
4
5
6
7
from PySide6.QtCore import QCalendar

QCalendar(self) -> None
QCalendar(QCalendar: PySide6.QtCore.QCalendar) -> None
QCalendar(id: PySide6.QtCore.QCalendar.SystemId) -> None
QCalendar(name: str) -> None
QCalendar(system: PySide6.QtCore.QCalendar.System) -> None
  • name 可以取以下值(均是字符串):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Julian
    Jalali
    IslamicCivil
    Milankovic
    Gregorian
    islamicc
    Islamic
    gregory
    Persian
    islamic-civil
  • system是QCalendar,System 的枚举值,可取以下值,默认值是 QCalendar.System.Gregorian

    • QCalendar.System.Gregorian
    • QCalendar.System.Julian
    • QCalendar.System.Milankovic
    • QCalendar.System.Jalali
    • QCalendar.System.IslamicCivil

日历类QCalendar 的常用方法

日历类QCalendar 的常用方法如表所示

  • 用name()方法获取当前使用的日历纪年法
  • 用dateFromParts(year,month,day)方法可以创建一个 QDate对象。
QCalendar的方法及参数类型 返回值的类型 说明
name() str 获取当前使用的日历纪年法
[static]availableCalendars() ListCstr] 获取可以使用的日历纪年法
dateFromParts(year: int.month; int,day: int) QDate 返回指定年、月、日构成的日期
dayOfWeek(QDate) int 获取指定日期在一周的第几天
daysInMonth(month:int,year:int=None) int 获取指定年指定月的总天数
daysInYear(year:int) int 获取指定年中的总天数
isDateValid(year:int,month: int,day:int) bool 获取指定的年、月、日是否有效
isGregorian() bool 获取是否是公历纪年
isLeapYear(year: int) bool 获取某年是否是闰年
isLunar() bool 获取是否是月历
isSolar() bool 获取是否是太阳历
maximumDaysInMonth() int 获取月中最大天数
maximumMonthsInYear() int 获取年中最大月数
minimumDaysInMonth() int 获取月中最小天数

日历类QCalendar例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:03
# File_name: 01-QCalendarWidget 例子.py


import sys
from PySide6 import QtCore
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtCore import QDate


class CalendarExample(QWidget):
def __init__(self):
super(CalendarExample, self).__init__()
self.setGeometry(100, 100, 400, 350)
self.setWindowTitle('Calendar 例子')
layout = QVBoxLayout()
self.dateTimeEdit = QDateTimeEdit(self)
self.dateTimeEdit.setCalendarPopup(True)

self.cal = QCalendarWidget(self)
self.cal.setMinimumDate(QDate(1980, 1, 1))
self.cal.setMaximumDate(QDate(3000, 1, 1))
self.cal.setGridVisible(True)
self.cal.setSelectedDate(QDate(2010, 1, 30))
self.cal.setHorizontalHeaderFormat(QCalendarWidget.LongDayNames)
# self.cal.setFirstDayOfWeek(Qt.Wednesday)
self.cal.setFirstDayOfWeek(Qt.Wednesday)
self.cal.move(20, 20)

self.label = QLabel('此处会显示选择日期信息')

self.cal.clicked.connect(lambda: self.showDate(self.cal))
self.dateTimeEdit.dateChanged.connect(lambda x: self.cal.setSelectedDate(x))
self.cal.clicked.connect(lambda x: self.dateTimeEdit.setDate(x))

layout.addWidget(self.dateTimeEdit)
layout.addWidget(self.cal)
layout.addWidget(self.label)
self.setLayout(layout)

def showDate(self, cal):
date = cal.selectedDate().toString("yyyy-MM-dd dddd")
month = cal.monthShown()
year = cal.yearShown()
_str = '当前选择日期: %s;\n当前选择月份: %s;\n当前选择年份: %s;' %(date, month, year)
self.label.setText(_str)


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = CalendarExample()
demo.show()
sys.exit(app.exec())

日期类QDate

日期类QDate构造方法

日期类QDate 用年、月日来记录某天,例如date=QDate(2023,8,22)date记录的是2023年8月22日,它可以从系统时钟中读取当前日期。

QDate提供了操作日期的方法,例如添加和减去日期、月份和年份得到新的日期,与日期字符串相互转换等。

QDate 在PySide6,QtCore模块中,用QDate创建日期实例的方法如下所示:

1
2
3
4
5
6
from PySide6.QtCore import QDate

QDate(self) -> None
QDate(QDate: PySide6.QtCore.QDate) -> None
QDate(y: int, m: int, d: int) -> None
QDate(y: int, m: int, d: int, cal: PySide6.QtCore.QCalendar) -> None

日期QDate的常用方法

日期QDate的常用方法如表所示,其中[]中的内容是可选项,主要方法介绍如下。

  • 日期时间设置获取

    • 用setDate(year:int,month;int,day;int)方法可以设置年、月
    • 用getDate()方法可以获取记录的年月日,返回值是元组Tuple(year,month,day);
    • 用currentDate()方法可以获取系统日期;
    • 用day()month()和 year()方法可分别获取日、月、年。
  • 时间计算

    • 用addDays(days:int) addMonths(months:int) addYears(years:int)方法可以在当前记录的时间上增加或减少天月和年;
    • 用daysTo(QDate)方法可计算与指定日期之间的天数间隔
  • 字符串<==>QDate时间转换

    • 用fromString(string: str,format:Qt.DateFormat=Qt.TextDate)或 fromString(string:str,format:str)方法可以将字符串型的日期数据转换成QDate
    • 用toString(format:Qt.DateFormat=Qt.TextDate)或 toString(format: str)方法将记录的年、月、日转换成字符串

以上 Qt.DateFormat 是枚举类型常量,Qt.DateFormat可以取的值如表所示,用Qt.DateFormat 进行指定格式的转换时与操作系统有关。

Qt.DateFormat的取值 举例
Qt.DefaultLocaleLongDate [romString(“2022年8月22 日*,Q1.DefaultLocaleLongDate)
Qt.DefaultIocaleShortDate [romString(“2022/08/22”,Qt.DelaultLocaleSbortDate)
Qt.ISODate fromString(*2022-G8-22”,Qt.ISODate)
Qt.LocaleDate fromString(*2022/08/22”,Qt.LocaleDate)
Qt.SystemLocaleDate fromString(“2022/08/22”,Qt.SystemLocaleDate)
Qt.SystemLocaleLongDate fromString(“2022年8月 22 日*:Qt.SystemLocaleLongDate)
Qt.SystemLocaleShortDate fromString(“2022/8/22”.Qt.SystemLocaleShortDate)
Qt.TextDate fromString(“周六8月 22 2022*.Qt.TextDate)

format 是格式化文本,可以取的格式符号如表所示

日期格式符 说 明
d 天数用1到31表示(不补0)
dd 天数用01到31表示(补0)
ddd 天数用英文简写表示(‘Mon’~’Sun’)或汉字表示
dddd 天数用英文全写表示(‘Monday’~’Sunday’)或汉字表示
M 月数用1到12表示(不补0)
MM 月数用01到12 表示(补 0)
MMM 月数用英文简写表示(‘Jan’~’Dec’)或汉字表示
MMMM 月数用英文全写表示(‘January’~’December’)或汉字表示
yy 年数用C0~99表示
yyyy 年数用4 位数表示

例如date=QDate(2022,822),datetoString(“日期是yyyy年M月d日”)的返回值是”日期是2022年8月22日

datetoString(“今天是dddd”的返回值是”今天是星期六”,date.toString(“今天是ddd”)的返回值是”今天是周六”。

再例如以下方法的返回值都是 QDate(2022,8,22):

1
2
3
4
QDate.fromString('20220822','yyyyMMdd')
QDate.fromString('2022/08/22', 'yyyy/MM/dd')
QDate.fromString('2022-08-22','yyyy-MM-dd')
QDate.fromString('2022,08,22','yyyy,MM,dd')
QDate的方法及参数类型 返回值的类型 说 明
setDate(year: int, month: int, day: int[, cal: QCalendar]) bool 根据年、月、日设置日期
getDate() Tuple[int, int, int] 获取记录的年、月、日
day(), day(cal:QCalendar) int 获取记录的日
month()、month(cal:QCalendar) int 获取记录的月
year()、year(cal:QCalendar) int 获取记录的月
addDays(days:int) QDate 返回增加指定天后的日期, 参数可为负
addMonths(months: int[, cal: Qcalendar]) QDate 返回增加指定月后的日期, 参数可为负
addYears(years:int[, cal:Qcalendar]) QDate 返回增加指定年后的日期, 参数可为负
dayOfWeek([cal: Qcalendar]) int 获取记录的日期是一周中的第几天
dayOfYear([cal: Qcalendar]) int 获取记录的日期是一年中的第几天
dayslnMonth([cal:Qcalendar]) int 获取日期所在月的月天数
daysInYear([cal: Qcalendar]) int 获取日期所在年的年天数
daysTo(d:QDate) int 获取记录的日期到指定日期的天数 ·
isNull() bool 获取是否不含日期数据
toJulianDay() int 换算成儒略日
toString(format=Qt.TextDate) Str 将年、月、日按指定格式转换成字符串
toString(format: str, cal: QCalendar=Default(QCalendar)) str 将年、月、日按指定格式转换成字符串
weekNumber() Tuple[int, int] 获取日期在一年中的第几周, 返回的元 组的第1个整数是周数, 第2个是年
[static]currentDate() QDate 获取系统的日期
[static]fromJulianDay(jd:int) QDate 将儒略日时间转换成日期
[static]fromString(string: str, format: Qt.DateFormat=Qt.TextDate) QDate 从字符串中获取日期
[static]fromString(string:str, format: str, cal=Default(QCalendar)) QDate 从字符串中获取日期
[static]isLeapYear(year:int) b001 获取指定的年份是否是闰年
[static]isValid(Ly: int.m:int, d:int]) bool 获取指定的年、月、日是否有效

时间类QTime

时间类QTime的构造方法

时间类QTime用时分秒和毫秒来记录某个时间点,它采用24 小时制,没有AM/PM和时区概念

例如time=QTime(22,35,15,124),time 记录的时间是22时35分15秒124 毫秒。

它可以对时间进行操作,例如增加或减少毫秒、秒;进行时间与字符串的相互转换等。

用QTime创建时间实例的方法如下所示:

1
2
3
4
5
from PySide6.QtCore import QTime

QTime(self) -> None
QTime(QTime: PySide6.QtCore.QTime) -> None
QTime(h: int, m: int, s: int=0, ms: int=0) -> None

时间QTime的常用方法

时间QTime的常用方法如表所示,主要方法介绍如下:

  • 时间设置和获取

    • 用setHMS(h:int, m:int, s:int, ms:int=0)方法可以设置一个时间点
    • 用hour() minute() second()和 mse()方法可以分别获取小时分钟秒和毫秒数据。
    • 用addMSecs(ms:int)方法获取在记录的时间上增加ms 毫秒后的时间
    • 用addSecs(secs:int)方法获取在记录的时间上增加 secs 秒后的时间。
  • 时间<==>字符串转换

    • 用fromString(str,format; Qt.DateFormat=Qt.TextDate)或 fromString(str,format:str)方法可以将时间字符串转换成日期
    • 用toString(f:QtDateFormat=Qt.TextDate)或toString(format:str)方法可以按照格式将时间转换成字符串

以上其中format是格式字符串可以取的格式字符如表所示。

  • 例如time=QTime(18,23,15,124),则time.toString("hh:mm:ssA")的值是"06:23:15下午"
  • 再如time=QTime.currentTime(),则 timetoString("现在时间是h: m: s: zzz")的值是"现在时间是 16:19:44:698"
时间格式字符 说 明
+ 小时用0~23表示,或 1~12表示(如果显示am/pm)
hh 小时用00~23表示,或01~12表示(如果显示am/pm)
H 小时用0~23表示(不论是否显示am/pm)
HH 小时用00~23表示(不论是否显示am/pm)
m 分钟用0~59表示(不补0)
mm 分钟用00~59表示(补0)
S 秒用0~59表示(不补0)
SS 秒用00~59表示(补0)
z 毫秒用0~999表示(不补0)
zzz 毫秒用000~999表示(补0)
t 时区,例如”CEST”
ap或a 使用am/pm表示上午/下午或汉字
AP或A 使用AM/PM表示上午/下午或汉字

日期时间类QDateTime

日期时间类QDateTime的构造方法

日期时间类QDateTime是将 QDate 和QTime的功能合并到一个类中,用年、月、日、时、分、秒、毫秒记录某个日期和某个时间点,它有时区的概念。

用QDateTime创建日期时间实例的方法如下所示,其中Qt.TimeSpec 可以取以下值,对应的值分别是 0~3;当spec取 Qt.OffsetFromUTC时,offsetSeconds 才有意义。

  • Qt.LocalTime
  • Qt.UTC
  • Qt.OffsetFromUTC
  • Qt.TimeZone
1
2
3
4
5
6
7
8
9
from PySide6.QtCore import QDateTime

QDateTime(self) -> None
QDateTime(arg__1: int, arg__2: int, arg__3: int, arg__4: int, arg__5: int, arg__6: int) -> None
QDateTime(arg__1: int, arg__2: int, arg__3: int, arg__4: int, arg__5: int, arg__6: int, arg__7: int, arg__8: PySide6.QtCore.Qt.TimeSpec = Instance(Qt.LocalTime)) -> None
QDateTime(arg__1: int, arg__2: int, arg__3: int, arg__4: int, arg__5: int, arg__6: int, arg__7: int, arg__8: int = Instance(Qt.LocalTime)) -> None
QDateTime(date: PySide6.QtCore.QDate, time: PySide6.QtCore.QTime, spec: PySide6.QtCore.Qt.TimeSpec = Instance(Qt.LocalTime), offsetSeconds: int = 0) -> None
QDateTime(date: PySide6.QtCore.QDate, time: PySide6.QtCore.QTime, timeZone: PySide6.QtCore.QTimeZone) -> None
QDateTime(other: PySide6.QtCore.QDateTime) -> None

日期时间类QDateTime的常用方法

日期时间类QDateTime的常用方法如表所示其大部分方法与QDate 和QTime的方法相同。

利用QDateTime将日期时间与字符串进行相互转换时,可以参考 QDate 和QTime的格式字符。.

QDateTime的方法及参数类型 返回值的类型 说 明
setDate(date:QDate) None 设置日期
setTime(time: QTime) None 设置时间
date() QDate 获取日期
time() QTime 获取时间
setTimeSpec(spec:Qt.TimeSpec) None 设置计时准则
setSecsSinceEpoch(secs: int) None 设置从1970年1月1日零时开始的时间(秒)
setMSecsSinceEpoch(msecs;int) None 将日期时间设置为从1970年1月1日零时开 始的时间
setOffsetFromUtc(offsetSeconds:int) None 将日期时间设置为国际统一时间偏移指定 offsetSeconds秒开始的时间,偏移时间不超 过士14小时
addYears(years:int) QDateTime 增加年
addMonths(months:int) QDateTime 增加月
addDays(days:int) QDateTime 增加天
addSecs(secs:int) QDateTime 增加秒
addMSecs(msecs:int) QDateTime 增加毫秒
[static]currentDateTime() QDateTime 获取当前系统的日期和时间
[static]currentDateTimeUtc() QDateTime 获取当前世界统一时间
[static]currentSecsSinceEpoch() int(秒) 返回从1970年1月1日零时到现在为止的秒数
[static]currentMSecsSinceEpoch() int 返回从1970年1月1日零时到现在为止的毫秒数
daysTo(QDateTime) int(天) 获取与指定日期时间的间隔
secsTo(QDateTime) int(秒) 获取与指定日期时间的间隔
msecsTo(QDateTime) int(毫秒) 获取与指定日期时间的间隔
[static]fromString(str, format: Qt.DateFormat=Qt.TextDate) QDateTime 将字符串转换成日期时间
[static]fromString(str,format: str,cal: QCalendar=Default(QCalendar)) QDate Time 将字符串转换成日期时间
[static]fromSecsSinceEpoch(secs:int, spec:Qt.TimeSpec=Qt.LocalTime, offsetFromUtc:int=0) QDateTime 指定秒创建日期时间
[static]fromMSecsSinceEpoch(msecs: int, spec: Qt.TimeSpec=Qt.LocalTime, offsetFromUte: int=0) QDateTime 指定毫秒创建日期时间
toString(format: str, cal: QCalendar=Default(QCalendar)) str 根据格式将日期时间转换成字符串
toString(format=Qt.TextDate) Str 根据格式将日期时间转换成字符串
toUTC() QDateTime 转换成国际统一时间
toTimeSpec(spec;Qt.TimeSpec) QDateTime 转换成指定的计时时间
toSecsSinceEpoch() int(秒) 返回从1970年1月1日开始计时的秒数
toMSecsSinceEpoch() int(毫秒) 返回从1970年1月1日开始计时的毫秒数
toLocalTime() QDateTime 转换成当地时间
isNull() boo1 所记录的日期时间是否为空
isValid() b001 所记录的日期时间是否有效

日历控件QCalenderWidget

QCalendarWidget

日历控件QCalenderWidget的构造方法

日历控件QCalendarWidget 主要用于显示日期星期和周数,可以设置日历控件显示的最小日期和最大日期,还可以设置日历表头的样式。

用QCalendarWidget类创建实例对象的方法如下所示其中parent是日历控件所在的窗体或容器控件。QCalendarWidget 继承自QWidget类。

1
2
3
from PySide6.QtWidgets import QCalendarWidget

QCalendarWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]=None) -> None

日历控件QCalendarWidget的常用方法

日历控件QCalendarWidget 的常用方法如表所示,主要方法介绍如下。

  • 日期选择和选择模式
    • 用selectedDate()方法可以获取当前选择的日期;
    • 用setSelectedDate(QDate)方法可以用代码选中某个日期;
    • 用setDateRange(min:QDate,max:QDate)方法或setMaximumDate(date:QDate)和 setMinimumDate(date:QDate)方法可以设置选择的日期范围;
    • 用setSelectionMode(QCalendarWidget,SelectionMode)方法可以设置选择日期的模式,其中参数QCalendarWidget.SelectionMode可以取:
      • QCalendarWidget,NoSelection(不允许选择)
      • QCalendarWidget,SingleSelection(单选)
  • 显示指定时间段
    • 用showSelectedDate()方法可以跳转到选中的日期
    • 用setCurrentPage(yearmonth)方法可以显示指定年指定月的日历
    • 用showNextMonth()showNextYear()方法可以显示下个月、明年同一日期的日历。
  • 日历控件外观
    • 用setGridVisible(bool)方法可以设置是否显示网格线,
    • 用setNavigationBarVisible(bool)方法可以设置是否显示导航条。
    • 用setVerticalHeaderFormat((QCalendarWidget.VerticalHeaderFormat)方法可以设置竖直表头的格式,其中参数 QCalendarWidget.VerticalHeaderFormat 可以取:
      • QCalendarWidget,ISOWeekNumbers(标准格式的周数)
      • QCalendarWidget,NoVerticalHeader(隐藏周数)。
    • 用setHorizontalHeaderFormat(QCalendarWidget.HorizontalHeaderFormat)方法可以设置水平表头的格式其中参数QCalendarWidget.HorizontalHeaderFormat 可以取:
      • QCalendarWidget.SingleLetterDayNames(用单个字母代替全拼,如M代表Monday)
      • QCalendarWidget.ShortDayNames(用缩写代替全拼,如Mon 代表Monday)
      • QCalendarWidget,LongDayNames(全名)
      • QCalendarWidget.NoHorizontalHeader(隐藏表头)。
    • 用setFirstDayOfWeek(Qt.DayOfWeek)方法可以设置一周中哪天排在最前面,其中参数 QtDayOfWeek 可以取Qt.Monday~Qt.Sunday。
QCalendarWidget 的方法及参数类型 返回值的类型 说明
[slot]setSelectedDate(date:QDate) None 用代码设置选中的日期
selectedDate() QDate 获取选中的日期
setCalendar(calendar:QCalendar) None 设置日历
calendar() QCalendar 获取日历
[slot]setCurrentPage(year:int,month:int) None 设置当前显示的年和月
setDateTextFormat(QDate,QTextCharFormat) None 设置表格的样式
dateTextFormat(date:QDate) . QTextCharFormat 获取表格的样式
setFirstDayOfWeek(Qt.DayOfWeek) None 设置一周第一天显示哪天
firstDayOfWeek() Qt.DayOfWeek 获取一周第一天显示的是哪天
[slot]setGridVisible(bool) None 设置是否显示网格线
isGridVisible() bool 获取是否已经显示网格线
setHorizontalHeaderFormat(QCalendarWidget.HorizontalHeaderFormat) None 设置水平表头的格式
setVerticalHeaderFormat(QCalendarWidget.VerticalHeaderFormat) None 设置竖直表头的格式
[slot]setDateRange(min:QDate.max: QDate) None 设置日历控件可选择的最小日期 和最大日期
setMaximumDate(date: QDate) None 设置日历控件可选的最大日期
maximumDate() QDate 获取日历控件可选的最大日期
setMinimumDate(date:QDate) None 设置日历控件可选的最小日期
minimumDate() QDate 获取日历控件可选的最小日期
setSelectionMode(QCalendarWidget.SelectionMode) None 设置选择模式
[slot]setNavigationBarVisible(bool) None 设置导航条是否可见
isNavigationBarVisible() bo01 获取导航条是否可见
[slot]showSelectedDate() None 显示已经选中日期的日历
[slot]showNextMonth() None 显示下个月的日历
[slot]showNextYear() None 显示明年的日历
[slot]showPreviousMonth() None 显示上个月的日历
[slot]showPreviousYear() None 显示去年的日历
[slot]showToday() None 显示当前日期的日历
monthShown() int 获取日历显示的月份
yearShown() Int 获取日历显示的年份

日历控件QCalendarWidget例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:03
# File_name: 01-QCalendarWidget 例子.py


import sys
from PySide6 import QtCore
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtCore import QDate


class CalendarExample(QWidget):
def __init__(self):
super(CalendarExample, self).__init__()
self.setGeometry(100, 100, 400, 350)
self.setWindowTitle('Calendar 例子')
layout = QVBoxLayout()
self.dateTimeEdit = QDateTimeEdit(self)
self.dateTimeEdit.setCalendarPopup(True)

self.cal = QCalendarWidget(self)
self.cal.setMinimumDate(QDate(1980, 1, 1))
self.cal.setMaximumDate(QDate(3000, 1, 1))
self.cal.setGridVisible(True)
self.cal.setSelectedDate(QDate(2010, 1, 30))
self.cal.setHorizontalHeaderFormat(QCalendarWidget.LongDayNames)
# self.cal.setFirstDayOfWeek(Qt.Wednesday)
self.cal.setFirstDayOfWeek(Qt.Wednesday)
self.cal.move(20, 20)

self.label = QLabel('此处会显示选择日期信息')

self.cal.clicked.connect(lambda: self.showDate(self.cal))
self.dateTimeEdit.dateChanged.connect(lambda x: self.cal.setSelectedDate(x))
self.cal.clicked.connect(lambda x: self.dateTimeEdit.setDate(x))

layout.addWidget(self.dateTimeEdit)
layout.addWidget(self.cal)
layout.addWidget(self.label)
self.setLayout(layout)

def showDate(self, cal):
date = cal.selectedDate().toString("yyyy-MM-dd dddd")
month = cal.monthShown()
year = cal.yearShown()
_str = '当前选择日期: %s;\n当前选择月份: %s;\n当前选择年份: %s;' %(date, month, year)
self.label.setText(_str)


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = CalendarExample()
demo.show()
sys.exit(app.exec())

日历控件QCalendarWidget例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/19 15:54
# File_name: 01-例2.py


import sys
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6 import QtCore
from PySide6.QtCore import QDate


class CalendarExample(QWidget):
def __init__(self):
super(CalendarExample, self).__init__()
self.initUI()

def initUI(self):
# 实例化日历控件
self.cal = QCalendarWidget(self)
# 设置日历的最小日期
self.cal.setMinimumDate(QDate(1980, 1, 1))
# 设置日历的最大日期
self.cal.setMaximumDate(QDate(3000, 1, 1))
# 设置日历的网格是否可见
self.cal.setGridVisible(True)
# 控件位置移动
self.cal.move(20, 20)
# 点击绑定自定义的槽函数
self.cal.clicked[QtCore.QDate].connect(self.showDate)

# 创建标签
self.lb1 = QLabel(self)
# 设置标签的文本为日历控件所选中的日期,并转为str数据显示
date = self.cal.selectedDate()
self.lb1.setText(date.toString('yyyy-MM-dd dddd'))

# 标签移动位置
self.lb1.move(20, 300)
# 设置主窗口的位置及初始大小和标题
self.setGeometry(200, 100, 400, 350)
self.setWindowTitle('Calendar例子')

def showDate(self, date):
# 设置标签的文本值
self.lb1.setText(date.toString('yyyy-MM-dd dddd'))


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = CalendarExample()
demo.show()
sys.exit(app.exec_())

日期时间控件QDateTimeEdit

日期时间控件包括QDateTimeEdit,QDateEdit 和QTimeEdit 三个控件。

这三个控件可以显示日期时间,但更多的是用于输入日期时间,

  • QDateTimeEdit可以输入日期和时间,QDateTimeEdit是有下拉列表的日历控件用于选择日期
  • QDateEdit 只能输入日期
  • QTimeEdit 只能输人时间

用QDateTimeEdit、QDateEdit和QTimeEdit类创建实例对象的方法如下所示,其中parent是控件所在的窗体或容器控件。

QDateTimeEdit是从QAbstractSpinBox类继承而来的

QDateEdit和QTimeEdit都是从QDateTimeEdit类继承而来的。

1
2
3
4
5
6
7
8
9
10
11
12
13
from PySide6.QtWidgets import QDateTimeEdit, QTimeEdit, QDateEdit

QDateTimeEdit(d: PySide6.QtCore.QDate, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QDateTimeEdit(dt: PySide6.QtCore.QDateTime, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QDateTimeEdit(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QDateTimeEdit(t: PySide6.QtCore.QTime, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QDateTimeEdit(val: Any, parserType: PySide6.QtCore.QMetaType.Type, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

QDateEdit(date: PySide6.QtCore.QDate, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QDateEdit(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

QTimeEdit(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QTimeEdit(time: PySide6.QtCore.QTime, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

QDateTimeEdit、QDateEdit和QTimeEdit的方法

日期时间控件 QDateTimeEdit 的常用方法如表所示。

由于QDateEdit 和QTimeEdit 都继承自QDateTimeEdit,因此 QDateEdit 和 QTimeEdit 的方法与QDateTimeEdit 的大多数方法相同。

QDateTimeEdit 的主要方法介绍如下:

  • 设置时间日期
    • 用setDate(QDate),setTime(QTime)和 setDateTime(QDateTime)方法为时间和日期控件QDateEditQTimeEdit 和 QDateTimeEdit 设置日期和时间
    • 用setDateRange(QDate, QDate),setTimeRange(QTime, QTime)或 setDateTimeRange(QDateTime, QDateTime)方法设置日期和时间的最小值和最大值
  • 时间格式和获取
    • 用setDisplayFormat(format)方法可以设置QDateTimeEdit 显示日期时间的格式
    • 用displayFormat()方法获取显示格式。关于格式符号的使用,请参考日期类和时间类的内容。
  • 字符串和日期时间对象转换
    • 用dateTimeFromText(str)方法可以将字符串转换成日期时间对象
    • 用textFromDateTime(QDateTime)方法可以将日期时间转换成字符串
  • 日期时间控件的输入部分被分割成年、月、日、时、分、秒、毫秒多个部分,
    • 用setSelectedSection(QDateTimeEdit.Section)方法可以使某个部分被选中,其中QDateTimeEdit.Section可以取:
      • QDateTimeEdit.NoSection
      • QDateTimeEdit.AmPmSection AM/PM
      • QDateTimeEdit, MSecSection 毫秒
      • QDateTimeEdit.SecondSection 秒
      • QDateTimeEdit.MinuteSection 分
      • QDateTimeEdit.HourSection 时
      • QDateTimeEdit.DavSection 日
      • QDateTimeEdit.MonthSection 月
      • QDateTimeEdit.YearSection 年
    • 用sectionText(section:QDateTimeEdit.Section)方法可以获取各个部分的文本;
    • 用sectionAtindex:int)方法可以根据索引获取对应部分,例如sectionAt(0)为QDateTimeEdit.YearSection。
QDateTimeEdit的方法及参数类型 返回值的类型 说明
[slot]setTime(time: QTime) None 设置时间
time() QTime 获取时间
[slot]setDate(date: QDate) None 设置日期
date() QDate 获取日期
[slot]setDateTime(dateTime: QDateTime) None 设置日期时间
dateTime() QDateTime 获取日期时间
setDateRange(min:QDate, max: QDate) None 设置日期的范围
setTimeRange(min: QTime,max: QTime) None 设置时间的范围
setDateTimeRange(min: QDateTime, max: QDateTime) None 设置日期时间的范围
sefMaximumDate(max: QDate)
setMaximumDateTime(dt:QDateTime)
setMaximumTime(max: QTime)
None 设置显示的最大日期时间
setMinimumDate(min:QDate)
setMinimumDateTime(dt:QDateTime)
setMinimumTime(min:QTime)
None 设置显示的最小日期时间
clearMaximumDate()
clearMaximumDateTime()
clearMaximumTime()
None 清除最大日期时间限制
clearMinimumDate()
clearMinimumDateTime()
clearMinimumTime()
None 清除最小日期时间限制
setCalendarPopup(bool) None 设置是否有日历控件
calendarPopup() bool 获取是否有日历控件
setCalendarWidget(QCalendarWidget) None 设置日历控件
setDisplayFormat(format:str) None 设置显示格式
displayFormat() str 获取显示格式
dateTimeFromText(str) QDateTime 将字符串转换成日期时间对象
textFromDateTime(QDateTime) str 将日期时间对象转换成字符串
setCalendar(QCalendar) None 设置日历
setSelectedSection(QDateTimeEdit.Section) None 设置被选中的部分
sectionText(section:QDateTimeEdit.Section) Str 获取对应部分的文本
sectionCount() int 获取总共分几部分
setTimeSpec(spec: Qt.TimeSpec) None 设置时间计时参考点

QDateTimeEdit、QDateEdit和QTimeEdit的信号

日期时间控件的信号有

  • 当日期改变时发送 dateChanged(QDate)信号
  • 当日期或时间改变时发送dateTimeChanged(QDateTime)信号
  • 当时间改变时发送timeChangedQTime)信号
  • 当编辑完成按Enter 键或失去焦点时发送editingFinished()信号

QDateTime、QDate、QTime例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import sys
import time

from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *


class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QDateTime")
self.resize(500, 500)
self.move(400, 250)
self.setup_ui()

def setup_ui(self):
# QDateTime QDate QTime 这三个类之间没有继承关系

# QDateTime
# -------------创建----------------
# dt = QDateTime()
# dt = QDateTime(2021, 5, 8, 12, 30) # 创建时设置年、月、日、时、分
dt = QDateTime.currentDateTime() # 静态方法,获取当前时间
# dt = QDateTime.currentDateTimeUtc() # 静态方法,获取当前的UTC时间
print("dt:", dt)

# -------------调整日期时间------------
dt_add_year = dt.addYears(1) # 增加1年,返回一个新的QDateTime对象
print("dt_add_year:", dt_add_year)
print("dt_add_secs", dt.addSecs(600)) # 增加小时或分钟没有专门的函数,需要通过增加秒来设置
dt.setTime(QTime(12, 5, 31, 0)) # 设置时间

# -----------计算时间差-----------
print("offset from UTC", QDateTime.offsetFromUtc(QDateTime.currentDateTime())) # 本地时间与UTC时间之差(单位为s)
print(dt.secsTo(QDateTime.currentDateTime())) # 计算两个时间之差,单位s

# ----------展示时间-------
dte = QDateTimeEdit(dt, self) # 方便查看起见,展示一下dt的信息
dte.move(100, 100)

# QDate
# ---------构造----------
# qd = QDate(2020, 1, 1) # 构造时传入年月日信息
qd = QDate.currentDate()
print(QDate.currentDate()) # 获取当前日期

# --------调整日期------
# 类似QDateTime

# ---------计算时间差-----
print("dates to 2001.1.1:", QDate(2001, 1, 1).daysTo(qd))

# ---------获取时间--------
print("day of week", qd.dayOfWeek()) # 这一周的第几日
print("day of year", qd.dayOfYear()) # 这一年的第几日
print("days in month", qd.daysInMonth()) # 这一月总共多少天
print("days in year", qd.daysInYear()) # 这一年总共多少天

# QTime
# --------构造--------
my_time = QTime(12, 00)
# my_time = QTime.currentTime()

# -------调整时间-------
# 类似QDAteTime

# --------计算时间差------
print("secs to:", my_time.secsTo(QTime(12, 0)))


if __name__ == "__main__":
app = QApplication(sys.argv)

window = Window()
window.show()

sys.exit(app.exec())

"""
dt: PySide6.QtCore.QDateTime(2023, 3, 19, 16, 10, 34, 323, 0)
dt_add_year: PySide6.QtCore.QDateTime(2024, 3, 19, 16, 10, 34, 323, 0)
dt_add_secs PySide6.QtCore.QDateTime(2023, 3, 19, 16, 20, 34, 323, 0)
offset from UTC 28800
14703
PySide6.QtCore.QDate(2023, 3, 19)
dates to 2001.1.1: 8112
day of week 7
day of year 78
days in month 31
days in year 365
secs to: 0
"""

DateTimeEdit 例子

image-20230319161242142

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:03
# File_name: 04-DateTimeEdit 例子.py


import sys
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtCore import QDate, QDateTime, QTime


class DateTimeEditDemo(QWidget):
def __init__(self):
super(DateTimeEditDemo, self).__init__()
self.initUI()

def initUI(self):
self.setWindowTitle('QDateTimeEdit例子')
self.resize(300, 90)
vlayout = QVBoxLayout()
self.label = QLabel('显示日期选择信息')
vlayout.addWidget(self.label)

# QDateTimeEdit示例
dateTimeLabel = QLabel('QDateTimeEdit示例:')
dateTimeEdit = QDateTimeEdit(QDateTime.currentDateTime(), self)
dateTimeEdit01 = QDateTimeEdit(QDate.currentDate(), self)
dateTimeEdit01.setDate(QDate(2030, 12, 31))
dateTimeEdit02 = QDateTimeEdit(QTime.currentTime(), self)
vlayout.addWidget(dateTimeLabel)
vlayout.addWidget(dateTimeEdit)
vlayout.addWidget(dateTimeEdit01)
vlayout.addWidget(dateTimeEdit02)

# QDateEdit 示例
dateEdit = QDateEdit(QDate.currentDate())
dateEdit.setDateRange(QDate(2015, 1, 1), QDate(2030, 12, 31))
dateLabel = QLabel('QDateEdit示例:')
vlayout.addWidget(dateLabel)
vlayout.addWidget(dateEdit)

# QTimeEdit 示例
timeEdit = QTimeEdit(QTime.currentTime())
timeEdit.setTimeRange(QTime(9, 0, 0, 0), QTime(16, 30, 0, 0))
timeLabel = QLabel('QTimeEdit示例:')
vlayout.addWidget(timeLabel)
vlayout.addWidget(timeEdit)

# 设置日期和时间格式
meetingEdit = QDateTimeEdit(QDateTime.currentDateTime())
formatLabel = QLabel("选择日期和时间格式:")
formatComboBox = QComboBox()
formatComboBox.addItems(
["yyyy-MM-dd hh:mm:ss(zzz 'ms')", "hh:mm:ss MM/dd/yyyy", "hh:mm:ss dd/MM/yyyy", "北京时间: hh:mm:ss",
"hh:mm ap"])
formatComboBox.textActivated.connect(
lambda: self.setFormatString(formatComboBox.currentText(), meetingEdit))
vlayout.addWidget(formatLabel)
vlayout.addWidget(meetingEdit)
vlayout.addWidget(formatComboBox)

# 弹出日历小部件
dateTimeEdit_cal = QDateTimeEdit(QDateTime.currentDateTime(), self)
dateTimeEdit_cal.setCalendarPopup(True)
vlayout.addWidget(QLabel('弹出日历小部件'))
vlayout.addWidget(dateTimeEdit_cal)

# 信号与槽
dateTimeEdit.dateTimeChanged.connect(lambda: self.showDate(dateTimeEdit))
dateTimeEdit01.dateTimeChanged.connect(lambda: self.showDate(dateTimeEdit01))
dateTimeEdit02.dateTimeChanged.connect(lambda: self.showDate(dateTimeEdit02))
dateEdit.dateTimeChanged.connect(lambda: self.showDate(dateEdit))
timeEdit.dateTimeChanged.connect(lambda: self.showDate(timeEdit))
meetingEdit.dateTimeChanged.connect(lambda: self.showDate(meetingEdit))
dateTimeEdit_cal.dateTimeChanged.connect(lambda: self.showDate(dateTimeEdit_cal))

self.setLayout(vlayout)

def showDate(self, dateEdit):
# 当前日期时间
dateTime = dateEdit.dateTime().toString()
date = dateEdit.date().toString('yyyy-MM-dd')
time = dateEdit.time().toString()
# 最大最小日期时间
maxDateTime = dateEdit.maximumDateTime().toString('yyyy-MM-dd hh:mm:ss')
minDateTime = dateEdit.minimumDateTime().toString(Qt.ISODate)

# 最大最小日期
maxDate = dateEdit.maximumDate().toString(Qt.ISODate)
minDate = dateEdit.minimumDate().toString()

# 最大最小时间
maxTime = dateEdit.maximumTime().toString()
minTime = dateEdit.minimumTime().toString()

_str = '当前日期时间:{}\n当前日期:{}\n当前时间:{}\n最大日期时间:{}\n最小日期时间:{}\n最大日期:{}\n最小日期:{}\n最大时间:{}\n最小时间:{}\n'.format(
dateTime, date, time, maxDateTime, minDateTime, maxDate, minDate, maxTime, minTime)
self.label.setText(_str)

def setFormatString(self, formatString, meetingEdit):
meetingEdit.setDisplayFormat(formatString)

if meetingEdit.displayedSections() & QDateTimeEdit.DateSections_Mask:
meetingEdit.setDateRange(QDate(2004, 11, 1), QDate(2005, 11, 30))
else:
meetingEdit.setTimeRange(QTime(0, 7, 20, 0), QTime(21, 0, 0, 0))


if __name__ == '__main__':
app = QApplication(sys.argv)
demo = DateTimeEditDemo()
demo.show()
sys.exit(app.exec())

网页浏览QWebEngineView

PySide6 提供了可以浏览网页的控件 QWebEngineView 和 QWebEnginePage;可以利用它们编写网页浏览器,它们位于QtWebEngineWidgets 模块中

网页浏览器控件QWebEngineView

网页浏览器控件QWebEngineView 继承自QWidget,用于管理其内部的网页QWebEnginePage,设置内部网页的一些属性。

用QWebEngineView 创建网页浏览器控件的方法如下所示,其中parent 是网页浏览器控件所在的窗体或容器控件。

1
2
3
4
5
from PySide6.QtWebEngineWidgets import QWebEngineView

QWebEngineView(page: PySide6.QtWebEngineCore.QWebEnginePage, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QWebEngineView(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QWebEngineView(profile: PySide6.QtWebEngineCore.QWebEngineProfile, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
网页浏览器控件QWebEngineView的常用方法

网页浏览器控件 QWebEngineView 的常用方法如表所示,主要方法:

  • 用load(url: Union[QUrl,str])方法或 setUrl(url: Union[QUrl,str])方法加载网页;
  • 用url()方法获取当前网页的 QUrl 地址;
  • 根据浏览历史记录,用forward()方法向前浏览网页;用back()方法向后浏览网页;用history()方法获取览记录QWebEngineHistory
  • 用reload()方法重新加载网页,如果已经有 HTML 格式的文本,用setHtml(html:str)方法显示 HTML格式的文本内容。
  • 对于网页中需要弹出新窗日的链接,需要创建 QWebEngineView的子类,并重写 createWindow(QWebEnginePage.WebWindowType)函数,其中枚举类型参数QWebEnginePage.WebWindowType 用于判断链接的类型,可取以下值,分别对应的值是 0~3。:
    • QWebEnginePage.WebBrowserWindow(纯浏览器窗口)
    • QWebEnginePage.WebBrowserTab(浏览器切换卡)
    • QWebEnginePage.WebDialog(网页对话框)
    • QWebEnginePage.WebBrowserBackgroundTab(没有隐藏当前可见的网页浏览器控件的切换卡)
QWebEngineView的方法及参数类型 返回值的类型 说明
load(url:Union[QUrl,str]) None 加载网页
setUrl(url:Union[QUrl,str]) None 加载网页
[slot]reload() None 重新加载网页
[slot]forward() None 向前浏览网页
[slot]back() None 向后浏览网页
[slot]stop() None 停止加载网页
url() QUrl 获取网页的 url 地址
title() str 获取当前网页中用HTML 定义 的标题
createStandardContextMenu() QMenu 创建标准的快捷菜单
createWindow(QWebEnginePage.WebWindowType) QWebEngineView 创建QWebEngineView的子类,并重写 该函数,用于弹出新的窗口
findText(subString:str) None 查找网页中的文本
hasSelection() b001 获取当前页中是否有选中的内容
selectedText() str 获取当前页中选中的内容
history() QWebEngineHistory 返回浏览器中当前网页的访问记录
icon() QIcon 获取当前页的图标
iconUrl() QUrI 获取当前页的图标的 QUrI地址
print(printer:QPrinter) None 默认用A4纸打印网页
printToPdf(filePath: str) None 将网页输出成pdf文档
setHtml(html; str) None 显示HTML格式的文本
setPage(page:QWebEnginePage) None 设置网页
page() QWebEnginePage 取当前的网页
setZoomFactor(factor: float) None 设置网页的缩放比例,参数取值范围为 0.25~5.0,耿认是1.0
zoomFactor() float 获取缩放比例
[static]forPage(QWebEnginePage) QWebEngineView 返回与网页关联的网页浏览器
网页浏览器控件QWebEngineView 的信号

网页浏览器控件 QWebEngineView 的信号如表所示

主要信号 urlChanged(QUrl),当网页地址发生改变时发送该信号,开始加载网页时发送 loadStarted()信号;

加载网页元素时发送loadProgress(int)信号,参数的范数是0~100,可以用QProgressBar 布局来显示加载进度;

网页加载完成时发送 loadFinished(bool)信号,成功是 True,出现错误是False。

QWebEngineView的信号及参数类型 说明
urlChanged(QUrl) 网页地址发生改变时发送信号
iconChanged(QIcon) 网页图标发生改变时发送信号
iconUrlChanged(QUrl) 网页图标的url地址发生改变时发送信号
loadFinished(bool) 网页加载完成时发送信号,成功是True,出现错误 是 False
loadProgress(int) 加载网页元素时发送信号,参数的范数是0~100
loadStarted() 开始加载网页时发送信号
pdfPrintingFinished(filePath: str,success:bool) 打印成pdf文件结束时发送信号
printFinished(success:bool) 打印完成时发送信号
printRequested() 请求打印时发送信号
selectionChanged() 网页中选择的内容发生改变时发送信号
titleChanged(title:str) 网页标题名称发生改变时发送信号
网页浏览器控件的应用实例

下面的程序创建一个简单的浏览器,用QWebEngineView 类创建子类myWebView,并重写了createWindow()函数这样在单击 QWebEnginePage,WebBrowserTab(浏览器切换卡)类型的链接时能够显示链接的内容如果是非QWebEnginePage WebBrowserTab 类型的链接,则根据浏览记录可以向前和向后导航。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/3 12:57
# File_name: 01-网页浏览器控件的应用实例.py.py


import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QLineEdit, QHBoxLayout, QVBoxLayout, QTabWidget, QProgressBar
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtCore import QUrl, Qt
from PySide6.QtGui import QIcon


class WidgetInTab(QWidget):
# 切换卡中的控件 # 参数tab用于切换卡控件的传递
def __init__(self, parent=None, tab=None):
super().__init__(parent)
self.tab = tab
self.urlLabel = QLabel("网址(&D):")
self.urlLine = QLineEdit() # 地址栏
self.urlLabel.setBuddy(self.urlLine)

self.backBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/arrow-small-left.png")) # 后退按钮
self.forwardBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/arrow-small-right.png")) # 前进按钮
self.reloadBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/refresh.png")) # 重新加载按钮
self.homeBtn = self.homeBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/home.png")) # 主页按钮

self.webView = self.webView = QWebEngineView() # 浏览器控件
self.webPage = self.webView.page() # 浏览器内部的网页
self.history = self.webPage.history() # 网页上的历史记录
self.progressBar = QProgressBar() # 进度条控件

self.progressBar.setRange(0, 100) # 进度条
self.progressBar.setAlignment(Qt.AlignCenter)
self.progressBar.setFormat("加载中,已完成%p%")

self.homeAddress = "https://www.sohu.com" # 主页地址
self.webPage.setUrl(self.homeAddress)

H = QHBoxLayout() # 水平布局
H.addWidget(self.urlLabel)
H.addWidget(self.urlLine)
H.addWidget(self.backBtn)
H.addWidget(self.forwardBtn)
H.addWidget(self.reloadBtn)
H.addWidget(self.homeBtn)

V = QVBoxLayout(self) # 竖直布局
V.addLayout(H)
V.addWidget(self.webView)
V.addWidget(self.progressBar) # 布局添加控件

# 信号与槽函数的连接
self.urlLine.returnPressed.connect(self.urlLine_returnPressed)
self.webPage.urlChanged.connect(self.url_changed)
self.webPage.titleChanged.connect(self.title_changed)
self.webPage.iconChanged.connect(self.icon_changed)
self.webPage.newWindowRequested.connect(self.new_WindowRequested)
self.forwardBtn.clicked.connect(self.forwardBtn_clicked)
self.backBtn.clicked.connect(self.backBtn_clicked)
self.reloadBtn.clicked.connect(self.webView.reload)
self.homeBtn.clicked.connect(self.homeBtn_clicked)
self.webPage.loadProgress.connect(self.progressBar.setValue)
self.webPage.loadFinished.connect(self.load_finished)
self.webPage.loadStarted.connect(self.load_started)

def urlLine_returnPressed(self): # 输人新地址并按Enter键后的槽函数
url = QUrl.fromUserInput(self.urlLine.text())
if url.isValid():
self.webPage.load(url) # 加载网页

def url_changed(self, url): # URL地址发生变化时的槽函数
self.urlLine.setText(url.toString()) # 显示新的地址
self.backBtn.setEnabled(self.history.canGoBack())
self.forwardBtn.setEnabled(self.history.canGoForward())

def title_changed(self, title): # 网页地址发生变化时的槽函数
tab_index = self.tab.indexOf(self) # 获取当前页的索引
self.tab.setTabText(tab_index, title)

def icon_changed(self, icon): # 网页图标发生变化时的槽函数
tab_index = self.tab.indexOf(self)
self.tab.setTabIcon(tab_index, icon)

def new_WindowRequested(self, request): # 需要新网页时的槽函数
tab_index = self.tab.indexOf(self)
newWindow = WidgetInTab(parent=None, tab=self.tab) # 创建切换卡内部的控件
self.tab.insertTab(tab_index + 1, newWindow, '加载中...') # 插入新卡片
self.tab.setCurrentIndex(tab_index + 1) # 将新插入的卡片作为当前卡片
newWindow.webPage.load(request.requestedUrl()) # 加载新网页

def load_started(self): # 网页开始加载时的槽函数
self.progressBar.show()

def load_finished(self, ok): # 网页加载结束时的槽函数
self.progressBar.hide()

def backBtn_clicked(self): # 后退按钮的槽函数
self.history.back()
if not self.history.canGoBack():
self.backBtn.setEnabled(False)

def forwardBtn_clicked(self): # 前进按钮的槽函数
self.history.forward()
if not self.history.canGoForward():
self.forwardBtn.setEnabled(False)

def homeBtn_clicked(self): # 主页按钮的槽函数
self.webPage.load(self.homeAddress)


class MyWindow(QWidget): # 主窗口
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("QWebEnginePage的应用实例")
self.resize(800, 600)
self.setupUi()

def setupUi(self):
self.tab = QTabWidget() # 切换卡控件
self.tab.setTabsClosable(True)
self.tab.setElideMode(Qt.TextElideMode.ElideMiddle)
H = QHBoxLayout(self)
H.addWidget(self.tab)
firstTab = WidgetInTab(parent=None, tab=self.tab)
self.tab.addTab(firstTab, firstTab.webPage.title()) # 第一个卡片中的内容

self.tab.tabCloseRequested.connect(self.tab_closeRequested)

def tab_closeRequested(self, index):
if self.tab.count() > 1:
self.tab.removeTab(index)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

网页QWebEnginePage

网页QWebEnginePage 是指网页浏览器控件QWebEngineView中的网页内容。

  • 用QWebEngineView 的page()方法可以取QWebEnginePage,
  • 用setPage(page:QWebEnginePage)方法可以给浏览器控件设置网页。

用QWebEnginePage创建网页实例的方法如下所示,其中参数 profile 是对网页的设置、脚本、缓存地址、cookie 的保存策略等。QWebEnginePage 继承自QObject。

1
2
3
4
5
from PySide6.QtWebEngineWidgets import QWebEngineView

QWebEngineView(page: PySide6.QtWebEngineCore.QWebEnginePage, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QWebEngineView(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QWebEngineView(profile: PySide6.QtWebEngineCore.QWebEngineProfile, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
网页QWebEnginePage的常用方法

网页QWebEnginePage 的常用方法如表所示,主要方法介绍如下

  • 用setUrl(url:Union[QUrl,str])方法或 load(url:Union[QUrl,str])方法设置网页地址;用requestedUrl()方法或 url()方法获取当前网页的地址

  • 重写createWindow(QWebEnginePageWebWindowType)函数单击链接后需要产生新网页时可以创建新的网页如果不重写该函数或者返回值不是QWebEnginePage对象,将发送newWindowRequested()信号;

  • 重写acceptNavigationRequest(url:Union[QUrl;str],QWebEnginePage.NavigationType;isMainFrame:bool)函数方法可以设置导航到新地址的处理方式其中枚举值QWebEnginePageNavigationType确定导航的原因可取:

    • QWebEnginePage, NavigationTypeLinkClicked(单击链接)
    • QWebEnginePageNavigationTypeTyped(加载)
    • QWebEnginePage NavigationTypeFormSubmitted(表格提交)
    • QWebEnginePageNavigationTypeBackForward(前进或后退动作)
    • QWebEnginePageNavigationTypeReload(重新加载)
    • QWebEnginePage.avigationTypeRedirect(目录或服务器重新定位或自动重新加载)
    • QWebEnginePageNavigationTypeOther(除以上方式之外的其他方式)
  • 用findText(str,QWebEnginePage.FindFlags,function(QWebEngineFindTextResult))方法

    • 可以在网页中查找指定的文本,查找结束后会发送indTextFinished(QWebEngineFindTextResult)信号和调用function(QWebEngineFindTextResult)函数,
      • 参数QWebEngineFindTextResult 是查找后的结果对象,其有两个方法numberOfMatches()和 activeMatch(),分别获取匹配的个数和当前匹配的索引;
      • 参数QWebEnginePage.FindFlags 设置查找方向,可以取(默认向前查找和大小写不敏感。):
        • QWebEnginePage.FindBackward(向后查找)
        • QWebEnginePage.FindCaseSensitively(大小写敏感)
  • 用setFeaturePermission(securityOrigin; Union[QUrl,str], feature:QWebEnginePage,Feature,policy;QWebEnginePage.PermissionPolicy)方法可以给网页需要的一些设备进行权限设置

    • 其中参数 feature 是QWebEnginePage.Feature枚举值,可取值如表所示:

      QWebEnginePage.Feature的取值 说 明
      QWebEnginePage.Notifications 0 网站通知最终用户
      QWebEnginePage.Geolocation 1 当地硬件或服务
      QWebEnginePage.MediaAudioCapture 2 音频设备.如麦克风
      QWebEnginePage.MediaVideoCapture 3 视频设备.如摄像头
      QWebEnginePage.MediaAudioVideoCapture 4 音频和视频设备
      QWebEnginePage.MouseLock 5 将光标锁定在浏览器中.通常用于游戏中
      QWebEnginePage.DesktopVideoCapture 6 视频输出.如多人可共享桌面
      QWebEnginePage.DesktopAudioVideoCapture 7 视频和音频输出
    • policy设置权限可取:

      • QWebEnginePagePermissionUnknown(不确定是否已经用户授权)
      • QWebEnginePage.PermissionGrantedByUser(用户已经授权)
      • QWebEnginePage.PermissionDeniedByUser(用户已经拒绝)
  • 网页中有一些默认的动作,由动作构成右键快捷菜单,有关动作的内容参见动作节,网页中的动作由 action(action:QWebEnginePage.WebAction)方法获取,其中放举值QWebEnginePage.WebAction 可取值如表所示

    QWebEnginePage.WebAction的取值 QWebEnginePage.WebAction 的取值
    QWebEnginePage.NoWebAction -1 QWebEnginePage.ToggleMediaPlayPause 23
    QWebEnginePage.Back 0 QWebEnginePage.ToggleMediaMute 24
    QWebEnginePage.Forward 1 QWebEnginePage.DownloadLinkToDisk 16
    QWebEnginePage.Stop 2 QWebEnginePage.DownloadImageToDisk 19
    QWebEnginePage.Reload 3 QWebEnginePage.DownloadMediaToDisk 25
    QWebEnginePage.Cut 4 QWebEnginePage.InspectElement 26
    QWebEnginePage.Copy 5 QWebEnginePage.ExitFullScreen 27
    QWebEnginePage.Paste 6 QWebEnginePage.RequestClose 28
    QWebEnginePage.Undo 7 QWebEnginePage.Unselect 29
    QWebEnginePage.Redo 8 QWebEnginePage.SavePage 30
    QWebEnginePage.SelectAll 9 QWebEnginePage.ViewSource 32
    QWebEnginePage.ReloadAndBypassCache 10 QWebEnginePage.ToggleBold 33
    QWebEnginePage.PasteAndMatchStyle 11 QWebEnginePage.ToggleItalic 34
    QWebEnginePage.OpenLinkInThisWindow 12 QWebEnginePage.ToggleUnderline 35
    QWebEnginePage.OpenLinkInNewWindow 13 QWebEnginePage.ToggleStrikethrough 36
    QWebEnginePage.OpenLinkInNewTab 14 QWebEnginePage.AlignLeft. 37
    QWebEnginePage.CopyLinkToClipboard 15 QWebEnginePage.AlignCenter 38
    QWebEnginePage.CopylmageToClipboard 17 QWebEnginePage.AlignRight 39
    QWebEnginePage.CopyImageUrlToClipboard 18 QWebEnginePage.AlignJustified 40
    QWebEnginePage.CopyMediaUrlToClipboard 20 QWebEnginePage.Indent 41
    QWebEnginePage.ToggleMediaControls 21 QWebEnginePage, Outdent 42
    QWebEnginePage.ToggleMediaLoop 22 QWebEnginePage.InsertOrderedList 43
    QWebEnginePage.OpenLinkInNewBackgroundTab 31 QWebEnginePage.InsertUnorderedList 44
    • 用triggerAction(action;QWebEnginePage,WebAction,checked;bool=False)方法可以激发某个动作
  • 用chooseFiles(QWebEnginePage.FileSelectionMode, oldFiles: Sequence[str])方法设置网页中选择文件时(如上传文件)的文件选择模式,其中QWebEnginePage.FileSelectionMode枚举值可取以下值;oldFiles 是提供建议的文件名前半部分。

    • QWebEnginePage.FileSelectOpen(只能选择一个文件)
    • QWebEnginePage.FileSelectOpenMultiple(可选多个文件)
    • QWebEnginePage FileSelectUploadFolder(选择文件夹);
  • 用save(filePath:str,format: QWebEngineDownloadRequest, SavePageFormat)方法保存网页内容到指定文件,其中参数format设置文件格式,可取:

    • QWebEngineDownloadRequest.UnknownSaveFormat
    • QWebEngineDownloadRequest.SingleHtmlSaveFormat(保存到一个HTML文件中,有些信息如图片不保持)
    • QWebEngineDownloadRequest,CompleteHtmlSaveFormat(保存整个 HTML文件,有些信息如图片保存到文件夹中)
    • QWebEngineDownloadRequest,MimeHtmlSaveFormat(保存成MIMEHTML格式)
QWebEnginePage的方法及参数类型 返回值的类型 说明
setUrl(url: Union[QUrl,str]) None 加载指定的网页地址
load(url: Union[QUrl,str]) None 加载QUrl地址网页
load(request: QWebEngineHttpRequest) None 加载特定的网页
requestedUrl() QUrI 获取当前网页的地址
url() QUrI 获取当前网页的地址
isLoading() bool 获取网页是否在加载
createWindow(QWebEnginePage.WebWindowType) QWebEnginePage 重写该方法创建新网页
acceptNavigationRequest(url: Union[QUrl, str], QWebEnginePage.NavigationType, isMainFrame:bool) bool 重写该函数,设置导航到新地 址的处理方式
setFeaturePermission(securityOrigin:Union[QUr1,str],feature:QWebEnginePage.Feature,policy: QWebEnginePage.PermissionPolicy) None 给网页需要的设备进行权限 设置
setUrlRequestInterceptor(interceptor: QWebEngineUrlRequestInterceptor) None 设置拦截器
action(action: QWebEnginePage.WebAction) QAction 获取网页的指定动作,用于创 建右键快捷菜单
triggerAction(action: QWebEnginePage.WebAction,checked: bool=False) None 执行指定的动作
setBackgroundColor(color:Union[QColor,Qt.GlobalColor,str]) None 设置背景颜色
backgroundColor() QColor 获取网页背景颜色
contentsSize() QSizeF 获取网页内容的尺寸
setDevToolsPage(page:QWebEnginePage) None 设置开发者工具
devToolsPage() QWebEnginePage 获取开发工具网页
download(url: Union[QUrl,str].filename:str=’’) None 下载资源到文件中
findText(str:QWebEnginePage FindFlags,function(QWebEngineFindTextResult)) None 调用指定的函数查找,函数参 数是查找结果
findText(subString: str,QWebEnginePage.FindFlags=}) None 查找指定的内容
hasSelection() bool 获取是否有选中的内容
history() QWebEngineHistory 获取历史导航
icon() QIcon 获取网页的图标
iconUrl() QUrI 获取网页的地址
title() str 获取网页标题
chooseFiles(QWebEnginePage.FileSelectionMode, oldFiles: Sequence[str]) ListCstr] 设置选择文件时(如上传文 件),文件选择模式
setAudioMuted(muted: bool) None 设置网页静音状态
isAudioMuted() bool 获取是否处于静音状态
setVisible(visible:bool) None 设置网页是否可见
isVisible() bool 获取网页是否可见
printToPdf(filePath:str) None 将网页转换成 pdl 文档
profile() QWebEngineProfile 获取 QWebEngineProile
recentlyAudible() bool 获取是否播放过音频
renderProcessPid() int 获取渲染进度
replaceMisspelledWord(replacement: str) None 用指定的文本替换不能识别的 文本
runJavaScript(scriptSource: str,worldId:int= 0,function(any)) None 运行 Java 脚本
runJavaScript(seriptSource: str,function(any)) None 运行 Java 脚本
save(filePath: str,format: QWebEngineDownloadRequest SavePageFormat) None 保存网页内容到文件中
scrollPosition() QPointF 获取网页滚动的位置
selectedText() str 获取网页上选中的文本
setHtml(html: str, baseUrl: Union[QUrl, str]) None 显示HTML文档内容
setWebChannel(QWebChannel,worldId:int=0) None 设置网络通道
webChannel() QWebChannel 获取当前的网络通道
setZoomFactor(factor:float) None 设置缩放系数
zoomFactor() float 获取当前的缩放系数
settings() QWebEngineSettings 获取对网页的设置
网页QWebEnginePage 的信号

网页QWebEnginePage的信号如表所示,主要信号介绍如下

  • 当网页的QUrl地址发生改变时,发送urChanged(QUrl)信号开始加载网页内容时发送loadStarted()信号;

    • 加载过程中发送 loadProgress(int)参数的值是加载进度取值范围是0~100;
    • 加载结束时发送 loadFinished(bool)信号,如果加载成功则参数是 True。
  • 网页加载发生改变时发送 loadingChanged(QWebEngineLoadingInfo)信号;

    • 其中QWebEngineLoadingInfo记录加载过程信息,用QWebEngineLoadingInfo 的 url()方法获取加载网页的QUrl 地址;

    • 用isErrorPage()方法判断加载过程是否出错;

    • status()方法获取加载状态,返回值可能是以下值,对应的值分别是0~3:

      • QWebEngineLoadingInfoLoadStartedStatus(加载开始)
      • QWebEngineLoadingInfo.LoadStoppedStatus(加载停止)
      • QWebEngineLoadingInfo,LoadSucceededStatus(加载成功)
      • QWebEngineLoadingInfo.LoadFailedStatus(加载失败)
      • 如果加载失败,可以用errorDomain()方法获取失败类型返值可能是以下值,对应的值分别是0~6:
        • QWebEngineLoadingInfo.NoErrorDomain(出错类型未知)
        • QWebEngineLoadingInfoInternalErrorDomain(内容不能被 PySide识别)
        • QWebEngineLoadingInfoConnectionErrorDomain(网络连接出错)
        • QWebEngineLoadingInfo CertificateErrorDomain(证书出错)
        • QWebEngineLoadingInfo.HttpErrorDomain(HTTP连接出错)
        • QWebEngineLoadingInfo.FtpErrorDomain(FTE连接出错)
        • QWebEngineLoadingInfo.DnsErrorDomain(DNS 连接出错)
  • 当网页中视频播放器需要全屏显示时发送ullScreenRequested(QWebEngineFullScreenRequest)信号,信号的参数是 QWebEngineFullScreenRequest 对象

    • 可以用QWebEngineFullScreenRequest 对象的accept()方法接受全屏模式;用reject()方法放弃全屏模式;
    • 如果 toggleOn()方法的返回值是True,则表示处于全屏状态
    • 另外用origin()方法获取全屏状态时的 QUrl地址。
  • 网页上需要输人授权(用户名和密码)时发送authenticationRequired(QUrl,QAuthenticator)信号

    • 其中QUrl是需要授权的网页地址
    • QAuthenticator 用于记录用户名和密码的类
      • 可以用setUser(str)和 setPassWord(str)方法分别设置用户名和密码
      • 用user()和 password()方法获取用户名和密码
  • 需要设备授权时发送featurePermissionRequested(QUrl,QWebEnginePage Feature)信号

    • 设备使用完不再需要设备授权时发送 featurePermissionRequestCanceled(QUrl,QWebEnginePageFeature)信号。
  • 在网页上搜索文本,搜索完成时发送 findTextFinished(QWebEngineFindTextResult)信号

    • 其中QWebEngineFindTextResult 记录查询到的与目标匹配的结果的个数和当前匹配的索引。
      • 用QWebEngineFindTextResult 的 nuberOfMatches()方法获取匹配的个数用activeMatch()方法获取当前匹配的索引。
  • 调用acceptNavigationRequest()方法时发送 navigationRequested(QWebEngineNavigationRequest)信号

    • 利用QWehEngineNavigationRequest 的accept()或 reject()方法可以接受或拒绝导航到指定网页;
    • 用url()方法获取要导航到的网页地址。
  • 需要在另外一个窗口中加载新网页时发送newWindowRequested(QWebEngineNewWindowRequest)信号,如果用户重写了 createWindow()函数则不会发送该信号。

    • QWebEngineNewWindowRequest 的openIn(QWebEnginePage)方法指定在哪个网页中打开;
    • isUserInitiated()方法获取是否由用户(键盘或鼠标事件)引起requestedUrl()方法取新网页的 QUrl 地址
    • requestedGeometry()方法获取新网页的尺寸QRect;
    • destination()方法获取新网页的类型,返回值是枚举类型QWebEngineNewWindowRequest,DestinationType可取以下值,对应的值分别是0~3。:
      • QWebEngineNewWindowRequest.InNewWindow(新窗口中)
      • QWebEngineNewWindowRequest, InNewTab(同窗的切换卡中)
      • QWebEngineNewWindowRequest,InNewDialog(在没有切换卡、工具栏和 URL输人框的新窗口中)
      • QWebEngineNewWindowRequest.InNewBackgroundTab(在同一个窗口中,没有隐藏当前可见的浏览器)
  • 需要获取比应用程序分配的更大存储空间时发送quotaRequested(QWebEngineQuotaRequest)信号

    • 用QWebEngineQuotaRequest 的 accept()方法或reject()方法接受请求或拒绝请求;
    • 用requestedSize()方法获取需要的存储空间(单位是 B);
    • 用origin()方法获取发出请求的网页地址 QUrl。
  • 选择客户证书时发送 selectClientCertificate(QWebEngineClientCertificateSelection)信号

    • 用QWebEngineClientCertificateSelection 的 certificates()方法获取可选的证书列表List[QSslCertificate];
    • 用select(QSslCertificate)方法选择一个证书;
    • 用selectNone()方法不选择任何证书继续加载网页;
    • 用host()方法获取需要客户证书的服务器的地址 QUrI(主机名和端口)。
  • 渲染非正常中断时发送renderProcessTerminated(QWebEnginePage.RenderProcessTerminationStatus,exitCode:int)信号,举值QWebEnginePage.RenderProcessTerminationStatus 可取以下值,分别对应0~3:

    • QWebEnginePage NormalTerminationStatus
    • QWebEnginePage AbnormalTerminationStatus
    • QWebEnginePage.CrashedTerminationStatus
    • QWebEnginePage KilledTerminationStatus
QWebEnginePage 的信号及参数类型 说明
urlChanged(QUrl) 网页地址发生改变时发送信号
selectionChanged() 网页所选内容发生改变时发送信号
iconChanged(QIcon) 网页图标发生改变时发送信号
iconUrlChanged(QUrl) 网页图标的地址发生改变时发送信号
titleChanged(str) 网页标题发生改变时发送信号
visibleChanged(bool) 可见性发生改变时发送信号
contentsSizeChanged(QSizeF) 网页的尺寸发生改变时发送信号
geometryChangeRequested(QRect) 网页位置和尺寸发生改变时发送信号
fullScreenRequested(QWebEngineFullScreenRequest) 全屏显示时(如播放视频)发送信号
windowCloseRequested() 需要关闭窗口时发送信号
audioMutedChanged(bool) 网页静音状态发生改变时发送信号
scrollPositionChanged(QPointF) 滚动位置发生改变时发送信号
linkHovered(str) 光标移到网页中的链接时发送信号
new WindowRequested(QWebEngineNewWindowRequest) 在另一个窗口中加载新网页时发送信号
authenticationRequired(QUrl,QAuthenticator) 网页上需要输人授权(用户名和密码)时发送信号
certificateError(QWebEngineCertificateError) 证书出错时发送信号
featurePermissionRequested(QUrl; QWebEnginePage, Feature) 需要设备授权时发送信号
featurePermissionRequestCanceled(QUrl, QWebEnginePage.Feature) 不再需要设备授权时发送信号
findTextFinished(QWebEngineFindTextResult) 查找结束时发送信号
loadStarted() 开始加载网页内容时发送信号
loadProgress(int) 加载过程中发送信号,参数值的范围是0~100
loadFinished(bool) 加载结束时发送信号
loadingChanged(QWebEngineLoadingInfo) 加载发生改变时发送信号
navigationRequested(QWebEngineNavigationRequest) 调用acceptNavigationRequest()方法时发送信号
pdfPrintingFinished(filePath: str, success: bool) 转换完pdf格式文档时发送信号
proxyAuthenticationRequired(QUrl, QAuthenticator, proxyHost: str) 需要代理授权时发送信号
quotaRequested(QWebEngineQuotaRequest) 需要获取比应用程序分配的更大存储空间时发送信号
recentlyAudibleChanged(recentlyAudible:bool) 静音状态发生改变时发送信号
renderProcessPidChanged(int) 渲染过程发生改变时发送信号
renderProcessTerminated(QWebEnginePage.RenderProcessTerminationStatus, exitCode: int) 渲染非正常中断时发送信号
selectClientCertificate(QWebEngineClientCertificateSelection) 选择客户证书时发送信号
QWebEngineHistory 与 QWebEngineHistoryltem

每个网页都会有一个QWebEngineHistory 对象

  • QWebEngineHistory 对象由多个历史记录构成,每个历史记录称为QWebEngineHistoryItem(历史项),
  • QWebEngineHistorylItem 项用于记录曾经访问过的QUrl地址和访问时间。

用QWebEnginePage 或 QWebEngineView的 history()方法可以获得网页的 QWebEngineHistory 对象。

网页加载的内容是当前历史项记录的网址,如果当前历史项发生改变,则网页加载的内容也同时改变。

当前历史项将 QWebEngineHistory 中的历史项分为之前的历史项和之后的历史项。

  • 用QWebEngineHistory 的 currentItem()方法和currentItemIndex()方法可以分别获取当前的历史项和历史项的索引;
  • 用back()方法和 forward)方法可以分别将当前项之前的历史项或之后的历史项作为当前历史项,网页也同时跳转,网页也同时跳转,
  • 用goToItem(QWebEngineHistoryItem)方法可以将指定的历史项作为当前项,网页也同时跳转;
  • 用canGoBack()方法或canGoForward()方法可以判断当前项之前或之后是否有历史项,如果有,则可以后退或前进;
  • 用QWebEngineHistoryItem 的 url()方法可以获取历史项关联的网址;
  • 用lastVisited()方法获取历史项关联的网页最后访问日期和时间。

QWebEngineHistory常用方法如表所示

QWebEngineHistory的方法 返回值的类型 说明
currentItem() QWebEngineHistoryItem 获取当前的历史项
currentItemIndex() int 获取当前历史项的索引
back() None 将当前项之前的历史项作为当前项,网页也同时后退
forward() None 将当前项之后的历史项作为当前项,网页也同时前进
goToItem(QWebEngineHistoryltem) None 将指定的历史项作为当前项,网页也同时跳转
backItem() QWebEngineHistoryItem 获取当前项之前的历史项
backItems(maxItems:int) List[QWebEngineHistoryItem] 获取当前项之前的最多maxItems个历史项
forwardItem() QWebEngineHistoryItem 获取当前项之后的历史项
forwardItems(maxItems:int) List[QWebEngineHistoryItemJ 获取当前项之后的最多maxItems个历史项
canGoBack() bool 获取是否可以后退
canGoForward() bool 获取是否可以前进
itemAt(i:int) QWebEngineHistoryltem 根据索引获取历史项
items() List[QWebEngineHistoryItem] 获取所有的历史项
count() int 获取记录的历史项的个数
clear() None 清空所有记录

QWebEngineHistoryItem常用方法如表所示

QWebEngineHistoryItem的方法 返回值的类型 说明
url() QUrl 获取历史项关联的网址
title() Str 获取历史项关联的网页的标题
lastVisited() QDateTime 获取历史项关联的网页最后访问日期和时间
iconUrl() QUrI 获取历史项关联的图标的网址
isValid() bool 获取历史项是否有效
originalUrl() QUrI 获取历史项关联的初始网址

QWebEnginePage 和 QWebEngineHistory 的应用实例

下面程序建立一个复杂些的网站浏览器,将浏览器放到切换卡控件中,在需要弹出窗口时自己添加卡片;可以进行页面的前进、后退导航,可以显示加载页面的进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/3 12:56
# File_name: 02-QWebEnginePage 和 QWebEngineHistory的应用实例.py

from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QLineEdit, QHBoxLayout, QVBoxLayout
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtCore import QUrl
from PySide6.QtGui import QIcon
import sys


class myWebView(QWebEngineView): # 创建QWebEngineView的子类
def __init__(self, parent=None):
super().__init__(parent)

def createwindow(self, type): # 重写 createWindow()函数
return self


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setWindowTitle("QWebEngineView的应用实例")
self.resize(800, 600)
self.setupUi()

def setupUi(self):
self.urlLabel = QLabel("网址(&D):")
self.urlLine = QLineEdit() # 地址栏
self.urlLabel.setBuddy(self.urlLine)

self.backBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/arrow-small-left.png")) # 后退按钮
self.forwardBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/arrow-small-right.png")) # 前进按钮
self.reloadBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/refresh.png")) # 重新加载按钮
self.homeBtn = self.homeBtn = QPushButton(icon=QIcon("../../../Resources/Icons/FlatIcon-regular-rounded/home.png")) # 主页按钮

self.webEngineView = myWebView() # 用QWebEngineView的子类创建浏览器
self.homeAddress = "https://www.sohu.com" # 主页地址
self.webEngineView.setUrl(self.homeAddress)

H = QHBoxLayout()
H.addWidget(self.urlLabel)
H.addWidget(self.urlLine)
H.addWidget(self.backBtn)
H.addWidget(self.forwardBtn)
H.addWidget(self.reloadBtn)
H.addWidget(self.homeBtn)

V = QVBoxLayout(self)
V.addLayout(H)
V.addWidget(self.webEngineView)

self.urlLine.returnPressed.connect(self.urlLine_return_Pressed)
self.webEngineView.titleChanged.connect(self.setWindowTitle)
self.webEngineView.urlChanged.connect(self.urChanged)
self.webEngineView.iconChanged.connect(self.setWindowIcon)
self.forwardBtn.clicked.connect(self.webEngineView.forward)
self.backBtn.clicked.connect(self.webEngineView.back)
self.reloadBtn.clicked.connect(self.webEngineView.reload)
self.homeBtn.clicked.connect(self.homeBtn_clicked)

def urlLine_return_Pressed(self):
url = QUrl.fromUserInput(self.urlLine.text())
if url.isValid():
self.webEngineView.load(url) # 加载网页

def urChanged(self, url):
self.urlLine.setText(url.toString()) # 显示新的地址

def homeBtn_clicked(self):
self.webEngineView.load("https;//www.sohu.com")


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

音频和视频的播放与录制

PySide6 提供音频和视频的播放和录制功能,与音频、视频播放和录制功能相关的类在PySide6.QtMultimedia模块中,

用于显示视频内容的控件在 PySide6.QtMultimediaWidgets模块中。

本章主要介绍音频和视频的播放与录制及摄像头拍照方面的内容。

播放音频和视频

播放器QMediaPlayer

播放器 QMediaPlayer 可以播放音频和视频,它可以直接播放的格式有限。

要播放更多格式的音频或视频,例如 mp4 格式的视频文件,需要在本机上安装解码器。

这里推荐种解码器 K-Lite Codec Pack,它可以对绝大多数影音格式进行解码,安装它之后QMediaPlayer 可以播放绝大多数的音频和视频文件。

在搜索引警中搜索”K-Lite”就可以下载 K-Lite Codec Pack 解码器,或者到官网下载。K-Lite Codec Pack 是完全免费的下载后使用默认设置安装即可。

QMediaPlayer 继承自QObject,用QMediaPlayer 定义播放器实例对象的方法如下所示,其中 parent 是继承自QObject 类的实例对象

1
2
3
from PySide6.QtMultimedia import QMediaPlayer

QMediaPlayer(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
播放器 QMediaPlayer 的常用方法

QMediaPlayer 的常用方法如表所示,要方法介绍如下:

  • 要播放音频或视频,首先需要给 QMediaPlayer 设置媒体源。

    • 可以用setSource(source: Union[QUrl,str])方法或用setSourceDevice(device: QIODevice,sourceUrl:Union[QUrl,str]=Default(QUrl))方法设置媒体文件,其中 sourceUrl是可选参数,用于取额外的信息;
    • 用source()和 sourceDevice()分别获取媒体源QUrl和QIODevice,有关 QUrl和 QIODevice 的介绍见参数/辅助类章节的内容
  • 要显示视频,需要将 QMediaPlayer 与显示视频的控件关联

    • 可以显示视频的控件有QVideoWidget、QGraphicsVideoltem,关联方法分别是 setVideoOutput(QVideoWidget)和 setVideo(utput(QGraphicsVideoltem)
    • 要播放音频,需要用setAudioOutput(output: QAudioOutput)方法设置音频输出设备,有关QAudioOutput 的介绍见下面的内容。
  • 用play()方法开始播放音频或视频,用pause()方法暂停播放,用stop()方法停止播放并返回。

  • 若isSeekable()返回值是True

    • 可以用setPosition(position:int)方法设置当前播放的时间
    • 用position()方法获取当前播放的时间
    • 用duration()方法获取音频或视频的总时间,参数或返回值的单位是毫秒。
  • 用setPlaybackRate(rate:float)方法设置播放速率,参数为10表示正常播放;参数 rate可以为负值,表示回放速率。有些多媒体不支持回放。

  • 用setLoops(loops;int)方法设置循环播放次数参数loops 可取:

    • QMediaPlayer.Infinite(无限次)
    • QMediaPlayer.Once(一次或其他整数)
  • 用state()方法获取播放状态,QMediaPlayer.State,返回值可能是

    • QMediaPlayer.StoppedState
    • QMediaPlayer.PlayingState
    • QMediaPlayer.PausedState
  • 用playbackState()方法获取播放器的播放状态QMediaPlayer.PlaybackState,返回值可能是:

    • QMediaPlayer.StoppedState
    • QMediaPlayer.PlayingState
    • QMediaPlayer.PausedState
  • 用mediaStatus()方法获取播放器所处的状态QMediaPlayer.MediaStatus,返回值可能是:

    • QMediaPlayer.NoMedia
    • QMediaPlayer.LoadingMedia
    • QMediaPlayer.LoadedMedia
    • QMediaPlayer.StalledMedia
    • QMediaPlayer.BufferingMledia
    • QMediaPlayer.BufferedMedia
    • QMediaPlayer.EndOfMedia
    • QMediaPlayer.InvalidMedia。
  • 用error()方法获取播放器出错信息QMediaPlayer.Error,返回值可能是:

    • QMediaPlayer.NoError
    • QMediaPlayer.ResourceError
    • QMediaPlayer.FormatError
    • QMediaPlayer.NetworkError
    • QMediaPlayer.AccessDeniedError
QMediaPlayer的方法及参数类型 说 明
[slot]setSource(source:Union[QUrl,str]) 设置要播放的音频或视频源
source() 获取音频或视频地址QUrl
[slot]setSourceDevice(device:QlODevice, sourceUrl: Union[QUrl,str]=Default(QUrl)) 设置音频或视频源
sourceDevice() 获取音频或视频源QIODevice
setActiveAudioTrack(index:int) 设置当前的声道
activeAudioTrack() 获取当前的声道
setActiveVideoTrack(index:int) 设置当前的视频轨道
activeVideoTrack() 获取当前的视频轨道
setActiveSubtitleTrack(index:int) 设置当前的子标题轨道
activeSubtitleTrack() 获取当前的子标题轨道
[slot]setPlaybackRate(rate:float) 设置播放速
playbackRate() 获取播放速率
isSeekable() 获取是否可以定位到某一播放时间
[slot]setPosition(position:int) 设置播放时间(毫秒)
position() 获取当前的播放时间(毫秒)
setAudioOutput(output:QAudioOutput) 设置播放音频的设备
setVideoOutput(QVideoWidget) 设置显示视频的控件
setVideoOutput(QGraphicsVideoItem) 设置显示视频的图项
setLoops(loops:int) 设置循环播放次数
loops() 获取循环播放次数
duration() 获取音频或视频可以播放的总时间(毫秒)
isAvailable() 获取平台是否支持该播放器
playbackState() 获取播放状态QMediaPlayer.PlaybackState
mediaStatus() 获取播放器所处的状态
error() 获取出错原因 QMediaPlayer.Error
errorString() 获取出错信息
hasAudio()、hasVideo() 获取多媒体中是否有音频或视频
bufferProgress() 获取缓冲百分比,100%时才可以播放
[slot]play() 播放音频或视频
[slot]pause() 暂停播放
[slot]stop() 停止播放并返回
播放器QMediaPlayer 的信号

播放器QMediaPlayer 的信号如表所示

QMediaPlayer的信号及参数类型 说明
activeTracksChanged() 当前轨道发生改变时发送信号
audioOutputChanged() 音频输出设备发生改变时发送信号
bufferProgressChanged(float) 缓冲进度发生改变时发送信号
durationChanged(int) 播放总时间发生改变时发送信号
errorChanged() 出错信息发生改变时发送信号
errorOccurred(error:QMediaPlayer.Error,errorString:str) 播放出错时发送信号
hasAudioChanged(bool) 可播放音频的状态发生改变时发送信号
hasVideoChanged(bool) 可播放视频的状态发生改变时发送信号
loopsChanged() 播放次数发生改变时发送信号
MediaStatusChanged(QMediaPlayer.MediaStatus) 播放器所处的状态发生改变时发送信号
playbackRateChanged(float) 播放速度发生改变时发送信号
P]aybackStateChanged(QMediaPlayer.PlaybackState) 播放状态发生改变时发送信号
positionChanged(int) 播放位置发生改变时发送信号
scekableChanged(bool) 可定位播放状态发生改变时发送信号
sourceChanged(QUrl) 音频或视频源发生改变时发送信号
tracksChanged() 轨道发生改变时发送信号
videoOutputChanged() 关联的视频播放器发生改变时发送信号
音频输出和视频输出

播放器QMediaPlayer 需要关联音频输出设备和视频输出控件才能播放音频和视频音频输出.

  • 音频输出QAudioOutput:需要定义 QAudioOutput 的实例,QAudioOutput 用于连接 QMediaPlayer与音频输出设备;QAudioOutput 继承自QObject

  • 视频控件 QVideoWidget :视频输出需要用到视频控件 QVideoWidget;QVideoWidget 继承自QWidget

  • 视频图项 QGraphicsVideoItem:QGraphicsVideoItem 作为图项应用于场景中;QGraphicsVideoltem 继承自QGraphicsObject。

用QAudioOutput、QVideoWidget 和 QGraphicsVideoItem 创建实例对象的方法如下所示,其中QAudioDevice 是本机上的音频输入输出设备。

1
2
3
4
5
6
7
8
9
from PySide6.QtMultimedia import QAudioOutput
from PySide6.QtMultimediaWidgets import QVideoWidget, QGraphicsVideoItem

QAudioOutput(device: PySide6.QtMultimedia.QAudioDevice, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QAudioOutput(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

QVideoWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

QGraphicsVideoItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QAudioOutput、QVideoWidget 和 QGraphicsVideoItem 的常用方法
  • 用setAspectRatioMode(mode:Qt.AspectRatioMode)方法设置视频控件所播放视频的长宽比模式,参数 mode 可取:
    • Qt.IgnoreAspectRatio(不保持比例关系)
    • Qt.KeepAspectRatio(保持原比例关系)
    • Qt.KeepAspectRatioByExpanding(通过扩充保持原比例关系)

音频输出QAudioOutput

方法及参数类型 说明
[slot]setVolume(volume:float) 设置音量,参数取值范围为 0~1
volume() 获取音量
[slot]setMuted(muted:bool) 设置是否静音
isMuted() 获取是否静音
[slot]setDevice(device: QAudioDevice) 设置音频设备
device() 获取音频设备

视频控件 QVideoWidget

[slot]setAspectRatioMode(mode:Qt.AspectRatioMode) 设置长宽比模式
aspectRatioMode() 获取长宽比模式
[slot]setFullScreen(fullScreen:bool) 设置全屏显示
isFullScreen() 获取是否全屏显示

视频图项 QGraphicsVideoItem

boundingRect() 获取边界矩形QRectF
setAspectRatioMode(mode: Qt.AspectRatioMode) 设置长宽比模式
aspectRatioMode() 获取长宽比模式
setOffset(offset:Union[QPointF,QPoint]) 设置偏移量
offset() 获取偏移量QPointF
setSize(size: Union[QSizeF,QSize]) 设置尺寸
size() 获取尺寸 QSizeF
QAudioOutputQVideoWidget 和 QGraphicsVideoItem 的信号

QAudioOutput、QVideoWidget 和 QGraphicsVideoItem 的信号如表所示

信号及参数类型 说明
QAudioOutput deviceChanged() 音频设备发生改变时发送信号
QAudioOutput mutedChanged(muted: bool) 静音状态发生改变时发送信号
QAudioOutput volumeChanged(volume: float) 音量发生改变时发送信号
QVideoWidget aspectRatioModeChanged(mode) 长宽比模式发生改变时发送信号
QVideoWidget fullScreenChanged(fullScreen:bool) 全屏状态发生改变时发送信号
QGraphics Videoltenm nativeSizeChanged(size: QSizeF) 尺寸发生改变时发送信号
音频播放 QSoundEffect

QSoundEffect 用于播放低延迟无压缩音频文件,如wav 文件,并可呈现一些特殊效果

用QSoundEffect 创建音频播放实例对象的方法如下所示其中 parent 是继承自 QObject的实例对象,QAudioDevice 是机器上音频设备。

1
2
3
4
from PySide6.QtMultimedia import QSoundEffect

QSoundEffect(audioDevice: PySide6.QtMultimedia.QAudioDevice, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QSoundEffect(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QSoundEffect的常用方法

QSoundEffect 的常用方法如表所示,主要方法介绍如下

  • 用setSource(url:Union[QUrl,str])方法设置音频源,参数 QUrl可以是指向网络的文件,也可以是本机文件;
    • 用source()方法获取音频源 QUrl。
  • 用setLoopCount(int)方法设置播放次数,如为0或1只播放一次,如果取QSoundEffect.Infinite 则无限次播放;
    • 用lopCount()方法获取播放次数;
    • 用loopsRemaining)方法获取剩余播放次数。
  • 用play()方法开始播放
  • 用stop()方法停止播放。
    • 用status()方法获取当前的播放状态;返回值是枚举类型 QSoundEffect.Status.可取值有 :
      • QSoundEffectNull
      • QSoundEffect.Loading
      • QSoundEffect.Ready
      • QSoundEffect.Error
QSoundEflect的方法及参数类型 返回值的类型 说明
setSource(url: Union[QUrl,str]) None 设置音频源
source() QUrI 获取音频源
setAudioDevice(device:QAudioDevice) None 设置音频设备
audioDevice() QAudioDevice 获取音频设备
setLoopCount(loopCount; int) None 设置播放次数
loopCount() int 获取播放次数
loopsRemaining() int 获取剩余的播放次数
setMuted(muted:bool) None 设置静音
isMuted() bool 获取是否是静音
setVolume(,volume:float) None 设置音量
volume() float 获取音量
[slot]play() None 开始播放
isPlaying() bo0l 获取是否正在播放
[slot]stop() None 停止播放
isLoaded() bool 获取是否已经加载声源
status() QSoundEffect.Status 获取播放状态
[static]supportedMimeTypes() :List[str] 获取支持的mime类型
QSoundEffect 的信号

QSoundEffect 的信号如表所示

QSoundEffect的信号及参数类型 说明
audioDeviceChanged() 音频设备发生改变时发送信号
loadedChanged() 加载状态发生改变时发送信号
loopCountChanged() 循环次数发生改变时发送信号
loopsRemainingChanged() 剩余循环次数发生改变时发送信号
mutedChanged() 静音状态发生改变时发送信号
playingChanged() 播放状态发生改变时发送信号
sourceChanged() 音频源发生改变时发送信号
statusChanged() 状态发生改变时发送信号
volumeChanged() 音量发生改变时发送信号
动画播放 QMovie

QMovie用于播放无声音的静态动画,例如 gif文件它在 PySide6Gui模块中,需要用QLabel的 setMovie(QMovie)方法与 QLabel 相关联来播放动画。

用QMovie类创建播放动画的实例对象的方法如下,其中 parent 是继承自QObiect的实例对象

可以用文件名或指向图形动画的 QIODevice 设备来指定动画源;

format 指定动画来源的格式取值类型是QByteArray或bytes,例如 bgif’b’webp’如果不指定格式系统会自行选择合适的格式

1
2
3
4
5
from PySide6.QtGui import QMovie

QMovie(device: PySide6.QtCore.QIODevice, format: Union[PySide6.QtCore.QByteArray, bytes]= Default(QByteArray), parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QMovie(fileName: str, format: Union[PySide6.QtCore.QByteArray, bytes]= Default(QByteArray), parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QMovie(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QMovie的常用方法

QMovie 的常用方法如表所示,主要方法介绍如下

  • 用setFileName(fileName;str)或 setDevice(device:QIODevice)方法设置动画源;

    • 用isValid()方法获取动画源是否有效。
  • 用setFormat(format;Union[QByteArray,bytes])方法设置动画源的格式,例如setFormat(b’gif’)。

  • 用start()方法开始播放动画

    • 用stop()方法停止播放
    • 用pause(True)方法暂停播放;用pause(False)方法继续播放;
  • 用setSpeed(percentSpeed;int)方法设置播放速度,参数是正常播放速度的百分比值,例如 setSpeed(200)表示播放速度是原播放速度的2倍。

  • 用setCacheMode(QMovieCacheMode)方法设置播放时是否进行缓存参数可以取QMovie.CacheNone或 QMovie.CacheAll.

  • 用jumpToFrame(int)方法可以跳转到指定的帧;

    • 用jumpToNextFrame()方法跳转到下一帧;
    • 当跳转到所需要的帧后,用currentImage()方法或currentPixmap()方法可以获取帧的图像
  • 用state()方法可以获得当前的播放状态,播放状态有:

    • QMovie.NoRunning
    • QMovie,Paused
    • QMove.Running
  • 用lastErrorString()方法取最近出错的信息,该信息可读;

    • 用lastError()方法获取出错信息,返回值是QImageReader.ImageReaderError 的枚举值可取以下值,分别对应值0~4:
      • QImageReader.UnknownError
      • QlmageReader.FileNotFoundError
      • QlmageReader.DeviceError
      • QImageReader.UnsupportedFormatError
      • QImageReader.InvalidDataError
setFileName(fileName: str) 设置动画文件
fileName() 获取动画文件名
setDevice(device: QIODevice) 设置设备
device() 获取设备QIODevice
setFormat(format: Union[QByteArray,bytes]) 设置动画格式
format() 获取动画格式QByteArray
[static]supportedFormats() 获取支持的格式List[QByteArray]
setScaledSize(QSize) 设置尺寸
[slot]setSpeed(percentSpeed: int) 设置相对正常播放速度的百分比
speed() 获取正常播放速度的百分比
setCacheMode(QMovie.CacheMode) 设置缓冲模式
setBackgroundColor(Union[QColor,Qt.GlobalColor,str]) 设置背景色
backgroundColor() 获取背景色QColor
[slot]start() 开始播放动画
[slot]stop() 停止播放动画
[slot]setPaused(paused, bool) 暂停或继续播放动画
state() 获取播放状态QMovie.MovieState
currentFrameNumber() 获取当前帧
QMovie的信号

QMovie的信号如表所示

QMovie的方法及参数类型 说 明
currentImage() 获取当前帧的图像QImage
currentPixmap() 获取当前帧的图像 QPixmap
frameCount() 获取总帧数
frameRect() 获取尺寸QRect
isValid() 获取动画源是否有效
jumpToFrame(int) 跳转到指定的帧,成功则返回True
[slot]jumpToNextFrame() 跳转到下一帧,成功则返回True
lastErrorString() 获取最近的出错信息
lastError() 获取出错信息
loopCount() 获取循环播放次数
nextFrameDelay() 获取播放下一帧的等待时间(毫秒)
QMovie的应用实例

运行下面的程序,通过双击窗口,打开动画文件并播放动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/4 0:54
# File_name: 01-QMovie的应用实例.py

from PySide6.QtWidgets import QApplication, QHBoxLayout, QFileDialog, QWidget, QLabel
from PySide6.QtCore import Qt
import sys
from PySide6.QtGui import QMovie


class MyLabel(QLabel):
def __init__(self, parent=None):
super().__init__(parent)

def mouseDoubleClickEvent(self, event):
filename, fil = QFileDialog.getOpenFileName(self,
caption="选择动画文件",
dir="../../../../Resources/images",
filter="动画文件(*.gif *.webp);;所有文件(*.*)")
movie = QMovie(filename)
movie.setBackgroundColor(Qt.GlobalColor.gray)
if movie.isValid():
self.setMovie(movie)
movie.start()


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupUi()

def setupUi(self):
self.label = MyLabel()
self.label.setText("双击我,打开动画文件播放动画!")
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
H = QHBoxLayout(self)
H.addWidget(self.label)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

录制音频和视频及拍照

多媒体设备QMediaDevices

多媒体设备是指本机中的音频输入设备(如麦克风),音频输出设备(如音箱、头戴耳机)和视频输入设备(如摄像头)。

多媒体设备通过 QMediaDevices 类提供的方法来获取

  • 音频输人输出设备类QAudioDevice
  • 视频输入设备类QCameraDevice

用QMediaDevices QAudioDevice和QCameraDevice 创建设备实例的方法如下所示。

1
2
3
4
5
6
7
8
9
from PySide6.QtMultimedia import QMediaDevices, QAudioDevice, QCameraDevice

QMediaDevices(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

QAudioDevice(self) -> None
QAudioDevice(other: PySide6.QtMultimedia.QAudioDevice) -> None

QCameraDevice(self) -> None
QCameraDevice(other: PySide6.QtMultimedia.QCameraDevice) -> None
QMediaDevices QAudioDevice和QCameraDevice 的常用方法

QMediaDevices QAudioDevice和QCameraDevice 的常用方法分别如表所示

主要是先用QMediaDevices 提供的静态方法获取本机上的音频设备和视频输人设备,然后用QAudioDevice QCameraDevice 提供的方法分别获取音频设备和视频输人设备的详细信息。

多媒体设备QMediaDevices

QMediaDevices的方法 返回值的类型 说明
[static]audioInputs() List[QAudioDeviceJ 获取音频输入设备
[static]defaultAudioInput() QAudioDevice 获取默认的音频输入设备
[static]audio()utputs() ListCQAudioDevice] 获取音频输出设备
[static]defaultAudioOutput() QAudioDevice 获取默认的音频输出设备
[static]videoInputs() List[QCameraDevice] 获取视频输人设备
[static]defaultVideoInput() QCameraDevice 获取默认的视频输人设备

音频输人输出设备类QAudioDevice

QAudioDevice的方法 返回值的类型 说 明
description() Str 获取音频设备的信息
id() QByteArray 获取音频设备的识别号
isDefault() bool 获取是否是默认的音频设备
isFormatSupported(QAudioFormat) bool 获取音频设备是否支持某种音频格式
isNull() bool 获取设备是否有效
maximumChannelCount() int 获取音频设备支持的最大通道数
minimumChannelCount() int 获取音频设备支持的最小通道数
maximumSampleRate() int 获取音频设备支持的最大采样率(Hz)
minimumSampleRate() int 获取音频设备支持的最小采样率(Hz)
mode() QAudioDevice.Mode 获取音频设备是输入还是输出设备,返回值可取
QAudioDevice.Null(无效设备)
QAudioDevice.Input(输人设备)
QAudioDevice.Output(输出 设备)
preferredFormat() QAudioFormat 获取音频设备的默认音频格式
supportedSampleFormats() List[QAudioFormat.SampleFormat] 获取音频设备支持的采样格式,格式有
QAudioFormat.UInt8
QAudioFormat.Intl6
QAudioFormat.Int32
QAudioFormat.Float
QAudioFormat.Unknown

视频输入设备类QCameraDevice

QCameraDevice的方法 返回值的类型 说明
description() Str 获取视频输入设备的信息
id() QByteArray 获取视频输入设备的识别号
isDefault() bool 获取是否是默认的视频输入设备
isNull() bool 获取视频输入设备是否有效
photoResolutions() List[QSize] 获取视频输入设备的分辨率
position() QCameraDevice, Position 获取视频输入设备的位置,返回值可取 QCarmeraDevice.BackFace(后置摄像头)、QCameraDevice.FrontFace(前置摄像头)或 QCameraDevice.UnspecifiedPosition(位 置不确定)
videoFormats() List[QCameraFormat] 获取视频输入设备支持的格式
信号

QMediaDevices的信号有

信号 说明
audioInputsChanged() 当音频输入设备发生改变时发送信号。
audioOutputsChanged() 音频输出设备发生改变时发送信号。
videoInputsChanged() 视频输入设备发生改变时发送信号。
音频接口QAudioInput 和视频接口QCamera

要录制音频和视频,需要定义音频设备的接口 QAudioInput 和视频设备的接口QCamera后,才能调用音频设备和视频设备进行录制

QAudioInput 和 QCamera 相当于音频和视频输人通道。

  • QAudioInput 是机器上的音频输人,例如内置麦克风或头戴麦克风
  • QCamera 是机器上的摄像头或外接相机。

利用QAudiolnput 和 QCamera 创建音频设备和视频设备接口的方法如下所示。

1
2
3
4
5
6
7
8
from PySide6.QtMultimedia import QAudioInput, QCamera

QAudioInput(deviceInfo: PySide6.QtMultimedia.QAudioDevice, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QAudioInput(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

QCamera(cameraDevice: PySide6.QtMultimedia.QCameraDevice, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QCamera(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QCamera(position: PySide6.QtMultimedia.QCameraDevice.Position, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
音频接口QAudioInput的常用方法

音频接口 QAudioInput 的常用方法如表所示,主要方法:

  • 用setDevice(device:QAudioDevice)方法设置音频设备;
  • 用setMuted(muted:bool)方法设置静音;
  • 用setVolume(volume:float)方法设置音量,音量参数 volume 的取值范围是0~1。
QAudioInput的方法及参数类型 返回值的类型 说明
setDevice(device:QAudioDevice) None 设置音频设备
device() QAudioDevice 获取音频设备
setMuted(muted:bool) None 设置是否静音
isMuted() bool 获取是否静音
setVolume(volume: float) None 设置音量
volume() float 获取音量
音频接口QAudioInput的信号
信号 方法
deviceChanged() 当设备发生改变时发送信号。
mutedChanged(muted:bool) 静音状态发生改变时发送信号。
volumeChanged(volume: float) 音量发生改变时发送信号。
视频接口 QCamera的常用方法

视频接口 QCamera 的常用方法如表所示,主要方法介绍如下

QCamera的方法及参数类型 返回值的类型 说 明
setCameraDevice(cameraDevice: QCameraDevice) None 设置视频设备
cameraDevice() QCameraDevice 获取视频设备
[slot]start() None 开启相机
[slot]stop() None 关闭相机
[slot]setActive(active: bool) None 设置是否打开视频设备
isActive() bool 获取相机是否启用
isAveilsble() bool 获取相机是否可用
setCameraFormat(format: QCameraFormat) None 设置视频格式
cameraFormat() QCameraFormat 获取视频格式
captureSession() QMediaCaptureSession 获取与 QCamera关联的媒体捕 获器
supportedFeatures() QCamera.Features 获取支持的特征
[slot]setExposureMode(mode: QCamera.ExposureMode) None 设置曝光模式
isExposureModeSupported(mode: QCamera.ExposureMode) bool 获取是否支持某种曝光模式
[slot]setAutoExposureTime() None 打开自动计算曝光时间
exposureTime() float 获取曝光时间
[slot]setManualExposureTime(float) None 设置曝光时间(秒)
manualExposureTime() float 获取自定义曝光时间
[slot]setAutoIsoSensitivity() None 根据曝光值开启自动选择光敏感值
isoSensitivity() int 获取光敏感值
[slot]setManualIsoSensitivity(iso: int) None 设置自定义光敏感值
manualIsoSensitivity() int 获取自定义的光敏感值
[slot]setExposureCompensation(ev: float) None 设置曝光补偿(EV值)
exposureCompensation() float 获取曝光补偿
I slot]setFlashMode(QCamera.FlashMode) None 设置快闪模式
flashMode() QCamera.FlashMode 获取快闪模式
isFlashModeSupported(mode: QCamera.FlashMode) bool 获取是否支持某种快闪模式
isFlashReady() bool 获取是否可以用快闪
setFocusMode(QCamera.FocusMode) None 设置对焦模式
focusMode() QCamera.FocusMode 获取对焦模式
isFocusModeSupported(mode: QCamera.FocusMode) bo01 获取是否支持某种焦点模式
setFocusDistance(d: float) None 设置自定义焦距,0表示最近的点,1 表示无限远
focusDistance() float 获取自定义焦距
setCustomFocusPoint(point: Union[QPointF,QPoint]) None 设置自定义焦点位置
customFocusPoint() QPointF 获取自定义焦点
focusPoint() QPointF 获取焦点
[slot]setTorchMode(QCamera.TorchMode) None 设置辅助光源模式
torchMode() QCamera.TorchMode 获取辅助光源模式
isTorchModeSupported(mode: QCamera.TorehMode) boul 获取是否支持某种辅助光源模式
[slot]setWhiteBalanceMode(mode: QCamera.WhiteBalanceMode) None 设置白平衡模式
isWhiteBalanceModeSupported(QCamera.WhiteBalanceMode) bool 获取是否支持某种白平衡模式
whiteBalanceMode() QCamera.WhiteBalanceMole 获取白平衡模式
[slot]setColorTemperature(int) None 设置颜色温度(K温度)
colorTemperature() int 获取颜色温度
setZoomFactor(factor:float) None 设置缩放系数
zoomFactor() float 获取缩放系数
[slot]zoomTo(zoom:float, rate: float) None 根据速率设置缩放系数
maximumExposureTime() float 获取最大的曝光时间
minimumExposureTime() float 获取最小的曝光时间
maximumIsoSensitivity() int 获取最大的光敏感值
minimumIsoSensitivity() int 获取最小的光敏感值
maximumZoomFactor() float 获取最大的放大系数
minimumZoomFactor() float 获取最小的放大系数
errorString() str 获取出错信息
error() QCamera.Error 获取出错类型
  • 用setCameraDevice(cameraDevice:QCameraDevice)方法为视频接口设置视频设备;

  • 用start()方法或 setActive(true)方法开启视频设备;用stop()方法或setActive(false)方法停止视频设备。

  • 用supportedFeatures()方法获取相机支持的特征,返回值如表所示:

    相机的特征值 说 明
    QCamera.Feature.ColorTemperature 0x1 相机支持色温
    QCamera.Feature.ExposureCompensation 0x2 相机支持曝光补偿
    QCamera.Feature.IsoSensitivity 0x4 相机支持自定义光般感值
    QCamera.Feature.ManualExposureTime 0x8 相机支持自定义曝光时间
    QCamera.Feature,CustomFocusPoint 0x10 相机支持自定义焦点
    QCamera.Feature.FocusDistance 0x20 相机支持自定义焦距
  • 用setExposureMode(mode;QCamera.ExposureMode)方法设置相机的曝光模式参数 mode 的取值是 QCamera.ExposureMode 的枚举值,可取的值如表所示;

    QCamera.ExposureMode的枚举值 模式 QCamera.ExposureMode的枚举值 模式
    QCamera.ExposureAuto 0 自动 QCamera.ExposureNightPortrait 9 夜晚
    QCamera.ExposureManual 1 手动 QCamera.ExposureTheatre 10 剧院
    QCamera.ExposurePortrait 2 人物 QCamera.ExposureSunset 11 傍晚
    QCamera.ExposureNight 3 夜晚 QCamera.ExposureSteadyPhoto 12 固定
    QCamera.ExposureSports 4 运动 QCamera.ExposureFireworks 13 火景
    QCamera.ExposureSnow 5 雪景 QCamera.ExposureParty 14 宴会
    QCamera.ExposureBeach 6 海景 QCamera.ExposureCandlelight 15 烛光
    QCamera.ExposureAction 7 动作 QCamera.ExposureBarcode 16 条码
    QCamera.ExposureLandscape 8 风景
    • 用isExposureModeSupported(mode:QCamera,ExposureMode)方法获取是否支持某种曝光模式。
  • 用setFlashMode(mode:QCameraFlashMode)方法设置相机的快闪模式,参数mode的取值是QCamera,FlashMode 的枚举值,可取:

    • QCamera.FlashOff
    • QCamera.FlashOn
    • QCamera.FlashAuto;
    • 用isFlashModeSupported(mode:QCamera.FlashMode)方法获取是否支持某种快闪模式。
  • 用setFocusMode(mode;QCamera,FocusMode)方法设置对焦模式,参数 mode的取值是QCamera.FocusMode 的枚举值,可取的值如表所示。

    QCamera.FocusMode的枚举值 说 明
    QCamera.FocusModeAuto 0 连续自动对焦模式
    QCamera.FocusModeAutoNear 1 对近处物体连续自动对焦模式
    QCamera.FocusModeAutoFar 2 对远处物体连续自动对焦模式
    QCamera.FocusModeHyperfocal 3 对超过焦距范围的物体采用最大景深值
    QCamera.FocusModeInfinity 4 对无限远对焦模式
    QCamera.FocusModeManual 5 手动或固定对焦模式
  • 用setTorchMode(mode:QCameraTorchMode)方法设置辅助光源模式,在光线不强时可以设置该模式,并会覆盖快闪模式,参数 mode可取值为 QCamera.TorchOffQCamera,TorchOn 或QCamera,TorchAuto。

  • 用setWhiteBalanceMode(mode;QCamera.WhiteBalanceMode)方法设置白平衡模式,白平衡是描述红、绿、蓝三基色混合生成后白色精确度的一项指标。

    • 在房间里的日光灯下拍摄的影像会显得发绿
    • 在室内钨丝灯光下拍摄出来的景物会偏黄
    • 而在日光阴影处拍摄到的照片则偏蓝

    白平衡的作用是不管在任何光源下都能将白色物体还原为白色。参数 mode是 QCamera,WhiteBalanceMode 的枚举值可取的值如表所示。

    QCamera.WhiteBalanceMode的枚举值 模式 QCamera.WhiteBalanceMode的枚举值 模式
    QCamera.WhiteBalanceAuto 0 自动 QCamera.WhiteBalanceSunlight 2 阳光
    QCamera.WhiteBalanceManual 1 手动 QCamera.WhiteBalanceCloudy 3
    QCamera.WhiteBalanceShade 4 阴影 QCamera.WhiteBalanceFlash 7 快闪
    QCamera.WhiteBalanceTungsten 5 鸨灯 QCamera.WhiteBalanceSunset 8 日落
    QCamera.WhiteBalanceFluorescent 6 荧光灯
    • 在手动模式下,需要用setColorTemperature(colorTemperature:int)方法设置色温
  • 用errorString()方法取可读的出错信息,用error()方法取出错类型返回值为QCamera.NoError 或QCamera, CameraError。

视频接口 QCamera的信号

视频接口QCamera 的信号如表所示。

QCanera的信号及参数类型 说明
activeChanged(bool) 照相机启动或停止时发送信号
cameraDeviceChanged() 照相设备发生改变时发送信号
cameraFormatChanged() 格式发生改变时发送信号
colorTemperatureChanged() 色温发生改变时发送信号
customFocusPointChanged() 自定义焦点发生改变时发送信号
exposureCompensationChanged(value: float) 曝光补偿发生改变时发送信号
exposureModeChanged() 曝光模式发生改变时发送信号
exposureTimeChanged(speed:float) 曝光时间发生改变时发送信号
flashModeChanged() 快闪模式发生改变时发送信号
flashReady(ready:bool) 可以快闪时发送信号
focusDistanceChanged(float) 焦距发生改变时发送信号
focusPointChanged() 焦点发生改变时发送信号
isoSensitivityChanged(value:int) 光敏感值发生改变时发送信号
manualExposureTimeChanged(speed:float) 自定义曝光时间发生改变时发送信号
manualIsoSensitivityChanged(int) 自定义光敏感值发生改变时发送信号
maximumZoomFactorChanged(float) 最大缩放系数发生改变时发送信号
minimumZoomFactorChanged(float) 最小缩放系数发生改变时发送信号
supportedFeaturesChanged() 所支持的特征发生改变时发送信号
torchModeChanged() 辅助光源模式发生改变时发送信号
whiteBalanceModeChanged() 白平衡发生改变时发送信号
zoomFactorChanged(float) 缩放系数发生改变时发送信号
errorChanged() 错误状态发生改变时发送信号
errorOccurred(error:QCamera.Error,errorString: str) 出现错误时发送信号
媒体捕获器 QMediaCaptureSession

媒体捕获器 QMediaCaptureSession 是音频数据和视频数据的集散地它接收从QAudioInput 和 QCamera 传递过来的音频和视频

  • 然后将音频转发给 QAudioOutput 播放音频
  • 将视频转发给 QVideoWidegt 或 QGraphicsVideoltem 播放视频
  • 将音频和视频转发给 QMdiaRecorder 录制音频和视频,转发给 QImageCapture 实现拍照功能。

用QMediaCaptureSession 创建实例对象的方法如下所示。

1
2
3
from PySide6.QtMultimedia import QMediaCaptureSession

QMediaCaptureSession(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
媒体捕获器QMediaCaptureSession 的常用方法

媒体捕获器QMediaCaptureSession 的常用方法如表所示

  • 用setAudioInput(input;QAudioInput)方法和 setCamera(camera:QCamera)方法分别设晋音频输入和视频输入;
  • 用setAudioOutput(output;QAudioOutput)方法和 setVideoOutput(output:QObject)方法分别设置音频输出设备和视频输出控件以便播放音频和视频;
  • 用setRecorder(recorder: QMediaRecorder)方法设置媒体记录器,以便录制音频和视频;
  • 用setImageCapture(imageCapture:QImageCapture)方法设置图像捕获器以便实现拍照功能。
QMediaCaptureSession的方法及参数类型 返回值的类型 说明
setAudioInput(input: QAudioInput) None 设置音频输入
audioInput() QAudioInput 获取音频输人
setAudioOutput(output: QAudioOutput) None 设置音频输出
audioOutput() QAudioOutput 获取音频输出
setCamera(camera:QCamera) None 设置视频接口
camera() QCamera 获取视频接口
setImageCapture(imageCapture:QImageCapture) None 设置图像捕获器
imageCapture() QImageCapture 获取图像捕获器
setRecorder(recorder:QMediaRecorder) None 设置媒体记录器
recorder() QMediaRecorder 获取媒体记录器
setVideoOutput(output: QObject) None 设置视频输出
videoOutput() QObject 获取视频输出
setVideoSink(sink:QVideoSink) None 设置视频接收器
videoSink() QVideoSink 获取视频接收器
媒体捕获器QMediaCaptureSessio 的信号

媒体捕获器 QMediaCaptureSession 的信号如表所示

QMediaCaptureSession 的信号 说 明
audioInputChanged() 当音频输人发生改变时发送信号
audioOutputChanged() 当音频输出发生改变时发送信号
cameraChanged() 当视频输人发生改变时发送信号
videoOutputChanged() 当视频输出发生改变时发送信号
imageCaptureChanged() 当图像捕获器发生改变时发送信号
recorderChanged() 当记录器发生改变时发送信号
媒体捕获器 QMediaCaptureSession 的应用实例

下面的程序用摄像头实时捕捉画面,并呈现捕捉到的画面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:03
# File_name: demo.py

import sys
from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QHBoxLayout
from PySide6.QtMultimedia import QMediaDevices, QCamera, QMediaCaptureSession
from PySide6.QtMultimediaWidgets import QVideoWidget


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupUi()

def setupUi(self):
self.videoWidget = QVideoWidget() # 显示视频的控件
self.btn_start = QPushButton("启动摄像头") # 打开摄像头按钮
self.btn_stop = QPushButton("停止摄像头") # 停止摄像头按钮

h = QHBoxLayout() # 按钮水平布局
h.addWidget(self.btn_start)
h.addWidget(self.btn_stop)

v = QVBoxLayout(self)
v.addWidget(self.videoWidget)
v.addLayout(h)

self.mediaDevice = QMediaDevices(self) # 媒体设备
self.cameraDevice = self.mediaDevice.defaultVideoInput() # 获取默认的视频输人设备

self.camera = QCamera(self.cameraDevice) # 根据视频输人设备定义视频接口
self.mediaCaptureSession = QMediaCaptureSession(self) # 媒体捕获器
self.mediaCaptureSession.setCamera(self.camera) # 设置媒体捕获器的视频接口
self.mediaCaptureSession.setVideoOutput(self.videoWidget) # 设置捕获器的视频输出控件

self.btn_start.clicked.connect(self.camera.start) # 信号与槽连接
self.btn_stop.clicked.connect(self.camera.stop) # 信号与槽连接


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

媒体格式QMediaFormat

在进行音频和视频的录制时,需要指定音频和视频的记录格式,以及媒体文件的存储格式,这些格式通过QMediaFormat 类来定义。

用QMediaFormat 类创建媒体格式实例的方法如下所示。

1
2
3
4
from PySide6.QtMultimedia import QMediaFormat

QMediaFormat(format: PySide6.QtMultimedia.QMediaFormat.FileFormat = Instance(PySide6.QtMultimedia.QMediaFormat.FileFormat.UnspecifiedFormat)) -> None
QMediaFormat(other: Union[PySide6.QtMultimedia.QMediaFormat, PySide6.QtMultimedia.QMediaFormat.FileFormat]) -> None

媒体格式 QMediaFormat 的常用方法

主要方法介绍如下

  • 分别用setFileFormat(f;QMediaFormat, FileFormat)方法setAudioCodec(codec:QMediaFormat;AudioCodec)方法和 setVideoCodec(codec: QMediaFormat.VideoCodec)方法设置保存媒体的文件格式音频编码格式和视频编码格式

    • 可选的文件格式、音频编码格式和视频编码格式如表所示。

      文件格式 音频编码格式 视频编码格式
      QMediaFormat.WMA QMediaFormat.AudioCodec.WMA QMediaFormat.VideoCodec.VP8
      QMediaFormat.AAC QMediaFormat.AudioCodec.AC3 QMediaFormat.VideoCodec.MPEG2
      QMediaFornat.Matroska QMediaFormat.AudioCodec.AAC QMediaFormat.VideoCodec.MPEG1
      QMediaFormat.WMV QMediaFormat.AudioCodec.ALAC QMediaFormat.VideoCodec.WMV
      QMediaFormat.MP3 QMediaFormat.AudioCodec.DolbyTrueHD QMediaFormat.VideoCodec.H265
      QMediaFormat.Wave QMediaFormat.AudioCodec.EAC3 QMediaFormat.VideoCodec.H264
      QMediaFormat.Ogg QMediaFormat.AudioCodec.MP3 QMediaFormat.VideoCodec.MPEG4
      QMediaFormat.MPEG4 QMediaFormat.AudioCodec.Wave QMediaFormat.VideoCodec.AV1
      QMediaFormat.AVI QMediaFormat.AudioCodec.Vorbis QMediaFormat.VideoCodec.MotionJPEG
      QMediaFormat.QuickTime QMediaFormat.AudioCodec.FLAC QMediaFormat.VideoCodec.VP9
      QMediaFormat.WebM QMediaFormat.AudioCodec.Opus QMediaFormat.VideoCodec.Theora
      QMediaFormat.Mpeg4Audio QMediaFormat.AudioCodec.Unspecified QMediaFormat.VideoCodec.Unspecified
      QMediaFormat.FLAC
  • 支持编码格式获取

    • supportedFileFormats(QMediaFormat, ConversionMode) 获取编码或解码时支持的文件格式列表
    • supportedAudioCodecs(QMediaFormat.ConversionMode) 获取编码或解码时支持的频编码格式列表
    • supportedVideoCodecs(QMediaFormatConversionMode) 获取编码或解码时支持的视频编码格式列表

    参数 QMediaFormat ConyersionMode可取

    • QMediaFormat.Encode
    • QMediaFormat.Decode
QMediaFormat的方法及参数类型 返回值的类型 说明
setFileFormat(f: QMediaFormat.FileFormat) None 设置文件格式
fileFormat() QMediaFormat.FileFormat 获取文件格式
setAudioCodec(codec: QMediaFormat.AudioCodec) None 设置音频编码格式
audioCodec() QMediaFormat.AudioCodec 获取音频编码格式
setVideoCodec(codec:QMediaFormat.VideoCodec) None 设置视频编码格式
videoCodec() QMediaFormat.VideoCodec 获取视频编码格式
supportedFileFormats(QMediaFormat.ConversionMode) List[QMediaFormat.FileFormat] 获取支持的文件格式 列表
supportedAudioCodecs(QMediaFormat.ConversionMode) List[QMediaFormat.AudioCodec] 获取支持的音频编码格 式列表
supportedVideoCodecs(QMediaFormat.ConversionMode) List[QMediaFormat.VideoCodec] 获取支持的视频编码格 式列表
isSupported(mode: QMediaFormat.ConversionMode) bool 获取是否可以对某种格 式编码或解码
[static]fileFormatDescription(QMediaFormat.FileFormat) str 获取文件格式信息
[static]fileFormatName(QMediaFormat.FileFormat) str 获取文件格式名称
[static]audioCodecDescription(QMediaFormat.AudioCodec) str 获取音频格式信息
[static]audioCodecName(QMediaFormat.AudioCodec) str 获取音频格式名称
[static]videoCodecDescription(QMediaFormat.VideoCodec) str 获取视频格式信息
[static]videoCodecName(QMediaFormat.VideoCodec) str 获取视频格式名称
媒体录制QMediaRecorder

QMediaRecorder 可以录制从 QMediaCaptureSession 获取的音频和视频,并对音频和视频进行编码,需要用QMediaCaptureSession 的 setRecorder(recorder:QMediaRecorder)方法设置关联的捕获器。

用QMediaRecorder创建实例的方法如下所示

1
2
3
from PySide6.QtMultimedia import QMediaRecorder

QMediaRecorder(self, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
媒体录制 QMediaRecorder 的常用方法

QMediaRecorder 的常用方法如表所示,主要方法介绍如下

  • 当 QMediaRecorder 准备就绪可以录制时isAvailable()的返回值是 True;

  • 用record()方法开始录制,用stop()方法停止录制,用pause()方法暂停录制,

  • 用duration()方法获取录制的时间,单位是毫秒。

  • 用recorderState()方法获取录制状态,返回值是QMediaRecorder.RecorderState 的枚举值,可取:

    • QMediaRecorder,StoppedState
    • QMediaRecorder.RecordingState
    • QMediaRecorder.PausedState
  • 录制过程中如果出错可以用error()方法获取出错内容,返回值是QMediaRecorder.Error 的枚举值,可取以下值,用errorString()方法获取具体的出错信息。:

    • QMediaRecorder.NoError
    • QMediaRecorder.ResourceError(设备没有准备好)
    • QMediaRecorder,ForatError(不支持该格式)
    • QMediaRecorder.OutOfSpaceError(存储空间不足)
    • QMediaRecorder.LocationNotWritable(输出位置不可写)
  • 用setEncodingMode(QMediaRecorder.EncodingMode)方法设置编码模式,参数是QMediaRecorder, EncodingMode 的枚举值可取:

    • QMediaRecorder.ConstantQualityEncoding(常质量编码)
    • QMediaRecorder ConstantBitRateEncoding(常比特率编码)
    • QMediaRecorder,AverageBitRateEncoding(平均比特率编码)
    • QMediaRecorderTwoPassEncoding(二次编码)
  • 用setQuality(quality:QMediaRecorder.Quality)方法设置录制质量,参数是QMediaRecorder.Quality 的举值,可取:

    • QMediaRecorder.VeryLowQuality
    • QMediaRecorder.LowQuality
    • QMediaRecorder.NormalQuality
    • QMediaRecorder.HighQuality
    • QMediaRecorder.VeryHighQuality。
  • 用setMediaFormat(format: Union[QMediaFormat,QMediaFormat, FileFormat])方法设置媒体格式。

QMediaRecorder 的方法及参数类型 返回值的类型 说明
isAvailable() bool 获取是否可以录制
[slot]record() None 开始录制
[slot]stop() None 停止录制
[slot]pause() None 暂停录制
duraticn() int 获取录制的时间
error() QMediaRecorder.Error 获取出错内容
errorString() str 获取出错信息
recorderState() QMediaRecorder.RecorderState 获取录制状态
captureSession() QMediaCaptureSession 获取关联的捕获器
setAudioBitRate(bitRate:int) None 设置音频比特率
audioBitRate() int 获取音频比特率
setAudioChannelCount(channels:int) None 设置音频通道数量
audioChannelCount() int 获取音频通道数量
setAudioSampleRate(sampleRate: int) None 设置音频采样率
audioSampleRate() int 获取音频采样率
setEncodingMode(QMediaRecorder.EncodingMode) None 设置编码模式
setMediaFormat(Union[QMediaFormat, QMediaFormat.FileFormat]) None 际最好海谢部含部 设置媒体格式
mediaFormat() QMediaFormat 获取媒体格式
setMetaData(QMediaMetaData) None 设置媒体元数据
metaData() QMediaMetaData 获取媒体元数据
addMetaData(QMediaMetaData) None 添加媒体元数据
setOutputLocation(Union[QUrl,str]) None 设置媒体输出位置
outputLocation() QUrI 获取输出位置
actualLocation() QUrI 获取实际的输出位置
setQuality(QMediaRecorder.Quality) None 设置录制质量
quality() QMediaRecorder.Quality 获取录制质量
setVideoBitRate(bitRate:int) None 设置视频比特率
videoBitRate() int 获取视频比特率
setVideoFrameRate(frameRate: float) None 设置视频帧速
videoFrameRate() float 获取视频帧速
setVideoResolution(QSize) None 设置视频分辨率
setVideoResolution(width: int, height: int) None 设置视频分辨率
videoResolution() QSize 获取视频分辨率
媒体录制QMediaRecorder 的信号

媒体录制QMediaRecorder 的信号如表所示

QMediaRecorder的信号及参数类型 说明
actualLocationChanged(location:QUrl) 存储位置发生改变时发送信号
durationChanged(duration:int) 录制时间发生改变时发送信号
errorChanged() 错误状态发生改变时发送信号
errorOccurred(error: QMediaRecorder.Error,errorString:str) 出现错误时发送信号
mediaFormatChanged() 格式发生改变时发送信号
metaDataChanged() 元数据发生改变时发送信号
recorderStateChanged(state:QMediaRecorder.RecorderState) 录制状态发生改变时发送信号
图像捕获QImageCapture

用媒体捕获器QMediaCaptureSession的 setImageCapture(imageCapture:QImageCapture)方法将 QImageCapture 与 QMediaCatureSession 关联,可以捕获图像,实现拍照功能。

用QImageCapture类定义图像捕的方法如下所示

1
2
3
from PySide6.QtMultimedia import QImageCapture

QImageCapture(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
图像捕获 QImageCapture 的常用方法

图像捕获 QImageCapture 的常用方法如表所示,主要方法介绍如下

  • 当isReadyForCapture()的返回值是 True 时,可以进行拍照;

  • 用capture()方法进行拍照,返回值是拍照的识别号ID

    • 同时会发送imageCaptured(id;int,preview:QImage)信号和 imageExposed(id:int)信号,可以获取拍摄的图像;
  • 用captureToFile(location:str=)方法直接将拍摄的图像保存到文件中,

    • 同时发送imageCaptured(id;int,preview; QImage)信号、imageExposed(id;int)信号和imageSaved(id;int,fileName:str)信号
    • 如果没有给出保存的文件名和路径则使用默认的路径和文件名,如果只给出文件名,则保存到默认路径下
    • 完整路径可以通过imageSaved(id:int,fileName:str)信号的参数获取。
  • 用error()方法获取拍照时的出错状态返回值是QImageCapture.Error 举值可取以下值,对应值分别是0~5,用errorString()方法获取出错信息。:

    • QImageCapture.NoError
    • QImageCapture.NotReadyError(设备没准备好)
    • QImageCapture.ResourceError(设备没准备好或不可用)
    • QImageCapture.OutOfSpaceError(存储空间不够)
    • QImageCapture,NotSupportedFeatureError(设备不支持拍照)
    • QImageCapture.FormatError(格式出错)
  • 用setFileFormat(format: QImageCapture,FileFormat)方法设置拍照的格式,参数是QImageCapture,FileFormat 的枚举值,可取:

    • QImageCapture.FileFormat.JPEG
    • QImageCapture.FileFormat.PNG
    • QImageCapture.FileFormat.Tiff
    • QImageCapture.FileFormat.WebP
    • QImageCapture.FileFormat.UnspecifiedFormat
    • QImageCapture.FileFormat.LastFileFormat
  • 用setQuality(quality: QImageCapture.Quality)方法设置图像质量,参数是QImageCapture.Quality 的举值,可取以下值,,=对应值分别是0~4:

    • QImageCapture.VeryLowQuality
    • QImageCapture.LowQuality
    • QImageCapture.NormalQuality
    • QImageCapture.HighQuality
    • QImageCapture.VeryHighQuality
QImageCapture的方法及参数类型 返回值的类型 说明
isReadyForCapture() bool 获取是否可以拍照
[slot]capture() int 进行拍照
[slot]captureToFile(location:str=’’) int 拍照到文件中
captureSession() QMediaCaptureSession 获取关联的捕捉器
error() QImageCapture.Error 获取出错状态
errorString() str 获取出错信息
setFileFormat(QImageCapture.FileFormat) None 设置文件格式
setMetaData(metaData:QMediaMetaData) None 设置元数据
metaData() QMediaMetaData 获取元数据
addMetaData(metaData:QMediaMetaData) None 添加元数据
setQuality(quality:QImageCapture.Quality) None 设置图像质量
quality() QImageCapture.Quality 获取图像质量
setResolution(QSize) None 设置分辨率
setResolution(width:int,height:int) None
resolution() QSize 获取分辨率
[static]fileFormatDescription(QImageCapture.FileFormat) Str 获取格式的信息
[static]fileFormatName(QImageCapture.FileFormat) str 获取格式的名称
[static]supportedFormats() List[QlmageCapture.FileFormat] 获取支持的格式
图像捕获QImageCapture 的信号

图像捕获 QImageCapture 的信号如表所示

其中imageAvailable(id:int,frame:QVideoFrame)信号的参数 QVideoFrame是视频,利用QVideoFrame 的 toImage()方法可以得到 QImage。

QImageCapture的信号及参数类型 说 明
readyForCaptureChanged(ready:bool) 准备状态发生改变时发送信号
imageCaptured(id: int,preview: QImage) 捕捉到图像时发送信号
imageExposed(id:int) 图像曝光时发送信号
imageSaved(id: int,fileName: str) 保存图像时发送信号
imageAvailable(id: int,frame: QVideoFrame) 可以获取图像时发送信号
metaDataChanged() 元数据发生改变时发送信号
qualityChanged() 图像质量发生改变时发送信号
errorOccurred(id:int,error: QImageCapture.Error,errorString:str) 出现错误时发送信号
errorChanged() 错误状态发生改变时发送信号
fileFormatChanged() 文件格式发生改变时发送信号
媒体元数据 QMediaMetaData

用QMediaRecorder或 QImageCapture 的 setMetaData(metaData: QMediaMetaData)方法可以为所录制的音频和视频或拍摄的照片添加媒体元数据,用metaData()方法获取媒体元数据。

媒体元数据 QMediaMetaData 的常用方法
  • 需要通过字典形式来定义媒体元数据的值,已经定义的字典关键字可以用keys()方法获取
  • 用insert(k:QMediaMetaData.Key,value:Any)方法定义关键字的值。
QMediaMetaData的方法及参数类型 返回值的类型 说 明
insert(k: QMediaMetaData.Key,value:Any) None 插人关键字及值
keys() List 获取关键字列表
remove(k:QMediaMetaData.Key) None 移除关键字
isEmpty() bool 获取是否为空
clear() None 清空所有关键字
stringValue(k:QMediaMetaData.Key) str 获取关键字对应的文本
value(k:QMediaMetaData.Key) Any 获取关键字对应的值
[static]metaDataKeyToString(k: QMediaMetaData.Key) str 获取关键字对应的文本
媒体元数据QMediaMetaData的可选关键字
关键字 值的类型 关键字 值的类型 关键字 值的类型
Title str Url Qurl AlbumTitle Str
Author List[str] MediaType str AlbumArtist Str
Comment Str FileFormat QMediaFormat.FileFormat ContributingArtist List[str]
Description Str AudioCodec QMediaFormat.AudioCodec TrackNumber int
Genre List[str] VideoCodec QMediaFormat.VideoCodec Composer List[str]
Date QDate Duration int LeadPerformer List[str]
Language QLocale.Language AudioBitRate int ThumbnailImage QImage
Publisher str VideoFrameRate float CoverArtImage QImage
Copyright str VideoBitRate| int Resolution QSize

QSS 主题与编辑器

QSS 全称 Qt Style Sheets(Qt样式表),用于美化 Qt 程序界面,类似于 CSS,但不如 CSS 强大,选择器和属性较少。

本文介绍在 PySide6 中使用QSS,但同样适用于 PyQt6、PyQt5、PySide2 等。

本文主要介绍 QSS 的加载使用以及分享,QSS 本身的语法详解请参考官方文档和其他教程。

官方文档

Customizing Qt Widgets Using Style Sheets

Qt Style Sheets Reference

官方参考文档才是最官方全面的文档,有时间最好仔细阅读一下。

主要包括:

  • 可应用样式表的控件列表
  • 属性列表
  • 图标列表
  • 属性值列表
  • 伪类选择器列表
  • 子控件控制列表

内容非常多,在此就不展开了。

窗口风格QStyle

PySide6是一个跨平台的类库,相同的窗口和界面在不同的平台上显示的样式不一样,可以根据需要在不同的平台上设置界面不同的外观风格。

QStyle是封装GUI外观的抽象类。PySide6定义了QStyle类的一些子类,应用于不同的操作系统中。

可以用窗口、控件或应用程序的setStyle(QStyle)方法给窗口、控件或整个应用程序设置风格,用style()方法获取风格。

一个平台支持的风格名称可以用QStyleFactory.keys()方法获取,返回平台支持的风格列表,例如[‘windowsvista’,Windows’,’Fusion’],用QStyleFactory.create(str)方法根据风格名称创建风格,并返回QStyle。

下面的程序是为整个应用程序设置风格的例子。从QComboBox列表中选择不同的界面风格,整个程序的界面风格也随之改变。

image-20230225180129472

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QStyleFactory, QPushButton, QComboBox, QSpinBox


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupJi()

def setupJi(self):
v=QVBoxLayout(self)
self.comb=QComboBox()
self.spinBox=QSpinBox()

self.pushButton=QPushButton("Close")

v.addWidget(self.comb)
v.addWidget(self.spinBox)
v.addWidget(self.pushButton)

self.comb.addItems(QStyleFactory.keys()) # 将风格名称添加到下拉列表中

self.pushButton.clicked.connect(self.close)


class MyApplication(QApplication):
def __init__(self, argv):
super().__init__(argv)

window=MyWindow() # 创建窗口
style=QStyleFactory.create(window.comb.currentText()) # 创建风格

self.setStyle(style) # 设置初始风格
window.comb.currentTextChanged.connect(self.reSetStyle) # 信号与槽的连接
window.show()

sys.exit(self.exec())

def reSetStyle(self, new_style): # 槽函数
style=QStyleFactory.create(new_style) # 创建新风格
self.setStyle(style) # 设置新风格
print("当前风格是:", new_style) # 输出当前的风格


if __name__=='__main__':
app=MyApplication(sys.argv)

样式表

为了美化窗口或控件的外观,可以通过窗口或控件的调色板给窗口或控件按照角色和分组设置颜色,还可以对窗口或控件的每个部分进行更细致的控制,这涉及窗口或控件的样式表(Qt style sheets,QSS),它是从 HTML 的层叠样式表(cascading style sheets,CSS)演化而来的。

  • 样式表由固定格式的文本构成,用窗口或控件的 setStyleSheet(styleSheet:str)方法设置样式,其中参数 styleSheet 是样式格式符。

    例如一个窗体上有多个继承自QPushButton 的按钮,用窗口的setStyleSheet方法可以将窗体上所有QPushButton类型的按钮定义成字体大小是20个像素、字体名称是宋体、字体颜色是红色,背景色是灰黑色的样式。

    1
    2
    3
    4
    5
    6
    7
    self.setStyleSheet("""
    QPushButton{
    font: 20pt'宋体';
    color:rgb(255,0,0);
    background-color: rgb(100,100,100)
    }
    """)
  • 也可以单独给某个按钮定义样式,例如有个 objectName 名称是btn_open 按钮,则用以下方法设置该按钮的字体大小是30个像素、宇体名称是黑体、字体颜色是白色,背景色是黑色的样式。

    1
    2
    3
    4
    5
    6
    btn_open.setStyleSheet("""
    font:30pt 黑体;
    color: rgb(255,255.255);
    background-color: rgb(0,0,0)
    """)
    # 三对引号是为了方便观看,实际使用单对引号
  • 可以看出定义样式表的一般规则:

    • 样式属性:值的形式定义样式属性的值
    • 多个样式的样式属性:值对之间用分号;隔开
    • 如果是对某一类控件进行设置,需要先说明控件的类,然后后面跟一对大括号{},把样式属性:值放到{}中。

下面详细介绍样式表的格式。

选择器

样式表除了类名、对象名和属性名外,一般不区分大小写。

样式表由选择器(selector)和声明(declaration)两部分构成,选择器用于选择某种类型或多个类型的控件,声明是要设置的属性和属性的值,例如以下 QPushButton 和 QLineEdit 就是选择器,用于选择继承自QPushButton 和 QLineEdit 的所有控件和子控件。

1
"QPushButton,QLineEdit {font: 20pt 宋体;color: rgb(255,0,0);background-color: rgb(100,100,100))"

选择器的使用方法如表所示:

选择器 示 例 说 明
全局选择器 * 选择所有的控件
类型选择器 QWidget 选择QWidget及其子类
属性选择器 QPushButton[flat=”false”] 只选择属性 flat的值是 False的 QPushButton 控件
类选择器 QPushButton 选择QPushButton但不选择其子类
ID选择器 QPushButton#btn_open 选择名称是 btn_open(用setObjectName(“btn_ open”)方法设置)的所有 QPushButton
后代选择器 QWidget QPushButton 选择QWidget后代中所有的QPushButton
子对象选择器 QWidget>QPushButton 选择直接从属于QWidget的QPushButton

子控件

一些复合型控件,例如 QComboBox,由 QLineEdit 和向下的箭头构成,向下的箭头可以称为子控件。

对子控件的引用是在控件和子控件之间用两个连续的冒号::隔开,例如"QComboBox::drop-down(image: url(:/image/down.png))"在资源文件中设置具有向下箭头的图片。

控件的子控件名称如表所示。

子控件的名称 说 明
groove QSlider的凹槽
handle QScrollBar、QSplitter、QSlider 的手柄或滑块
corner QAbstractScrollArea中两个滚动条之间的角落
add-line QScrollBar增加行的按钮,即按下该按钮滚动条增加一行
add-page QScrollBar在手柄(滑块)和增加行之间的区域
sub-line QScrollBar 减少行的按钮,即按下该按钮滚动条减少一行
sub-page QScrollBar 在手柄(滑块)和减少行之间的区域
down-arrow QComboBox、QHeaderView(排序指示器)、QScrollBar、QSpinBox的向下箭头
down-button QScrollBar或QSpinBox的向下按钮
up-arrow QHeaderView(排序指示器)、QScrollBar、QSpinBox的向上箭头
up-button QSpinBox的向上按钮
left-arrow QScrollBar 的左箭头
right-arrow QMenu或QScrolBar的右箭头
branch QTreeView的分支指示符
section QHeardeView的段
text QAbstractltemView的文本
chunk QProgressBar的进度块
drop-down QComboBox的下拉按钮
indicator QAbstractltemView、QCheckBox、QRadioButton、QMenu(可被选中的)、QGroupBox(可被选中的)的指示器
pane QTabWidget的面板(边框)
right-corner QTabWidget的右角落,可用于控件QTabWidget中右角落控件的位置
left-corner QTabWidget的左角落,可用于控件QTabWidget中左角落控件的位置
tab-bar QTabWidget的选项卡栏,仅用于控制 QTabBar 在 QTabWidget 中的位置
1ab QTabBar或QToolBox的选项卡
tear QTabBar的可分离指示器
close-button QTabBar选项卡或QDockWidget上的关闭按钮
float-button QDockWidget 的浮动按钮
title QDockWidget 或 QGroupBox的标题
scroller QMenu或QTabBar的滚动条
separator QMenu或 QMainWindow 中的分隔符
tearoff QMenu的可分离指示器
item 8AbstrscttemView.QMenuBar.QMenu.QStatusBar 中的个项
icon QAbstractItemView 或QMenu的图标
menu-arrow 带有菜单的QToolButton的箭头
menu-button QToolButton的菜单按钮
menu-indicator QPushButton的菜单指示器

状态选择

一个控件有多种状态,例如活跃(active)激活(enabled)失效(disabled)、鼠标悬停(hover)、选中(checked)、未选中(unchecked)和可编辑(editable)等

根据控件所处的状态可以给控件设置不同的外观。

  • 样式表的格式字符串中,控件与状态之间用冒号:隔开,例如QPushButton:active(...)设置激活时的外观
  • 可以同时对多个状态进行设置,例如QPushButton:active: hoverl...
  • 设置激活或者光标悬停时的外观;可以在状态前加!表示相反的状态。

控件的常用状态如表所示。

控件的状态 说 明
active 控件处于激活状态
focus 该项具有输入焦点
default 该项是默认值
disabled 控件已失效
enabled 该控件已启用
hover 光标悬停在该控件上
pressed 使用鼠标按下该控件
no-frame 该控件没有边框,例如无边框的 QLineEdit等
flat 该控件是平的(flat),例如,一个平的 QPushButton
checked 该控件被选中
unchecked 该控件未被选中
off 适用于处于关闭状态的控件
on 适用于处于开启状态的控件
editable QComboBox是可编辑的
read-only 该控件为只读,例如只读的 QLineEdit
indeterminate 该控件具有不确定状态,例如,三态的QCheckBox
exclusive 该控件是排他项目组的一部分
non-exclusive 该控件是非排他项目组的一部分
bottom 该控件位于底部
top 该控件位于顶部
left 该控件位于左侧,例如QTabBar的选项卡位于左侧
right 该控件位于右侧,例如QTabBar的选项卡位于右侧
middle 该控件位于中间,例如不在QTabBar 开头或结尾的选项卡
first 该控件是第一个,例如 QTabBar 中的第一个选项卡
last 该控件是最后一个,例如 QTabBar中的最后一个选项卡
horizontal 该控件具有水平方向
vertical 该控件具有垂直方向
maximized 该控件是最大化的,例如最大化的QMdiSubWindow
minimized 该控件是最小化的,例如最小化的QMdiSubWindow
floatable 该控件是可浮动的
movable 该控件可移动,例如,可移动的QDockWidget
only-one 该控件是唯一的,例如只有一个选项卡的QTabBar
next-selected 下一控件被选择
previous-selected 上一控件被选择
selected 该控件被选择
window 控件是一个窗口,即顶级控件
closable 该控件可被关闭,例如可关闭的QDockWidget
closed 该控件处于关闭状态,例如QTreeView中的非展开控件
open 该控件处于打开状态,例如QTreeView中的展开控件,或带有打开菜单的 QComboBox或 QPushButton控件
has-children 该控件具有孩子,例如 QTreeView中具有子控件的控件
has-siblings 该控件具有兄弟姐妹(即同级的控件)
alternate 当QAbstractltemView.alternatingRowColors()被设置为true时,为每个交替行设 置此状态,以绘制QAbstractItemView的行

样式的属性

颜色属性的设置

控件有背景色、前景色及选中状态时的背景色和前景色,可以对这些颜色分别进行设置,这些颜色的属性名称如表所示

例:

1
"QPushButton(background: gray url(d:/s.png); background-repeat: repeat-x; background-position: left)"

设置 QPushButton 类的颜色为灰色,设置背景图片为 d:/s.png,沿着 x 方向从左侧重复显示图片。

颜色属性名称 类型 说 明
background Background 设置背景的简写方法,相当于指定 background-color、 background-image, background-repeat, background-position
background-color Brush 控件的背景色
background-image Url 设置控件的背景图像
background-repeat Repeat 如何使用背景图像填充背景区域background-origin,若未 指定此属性,则在两个方向重复背景图像
background-position Alignment 好通楼a语内的皮 为 topleft
background-attachment Attachment 中度合条的法用门心中防m免 于视口滚动还是固定,默认值为cr
background-clip Origin 格件能制有来的形,所属性指庭kecodn 时强程架起Te的数的矩形。此属桂获认值为通(即边框矩形)
background-origin Origin 整件背景的原点矩形,通常与Dekehmdpom和 bekgroundimage一起使用,默认为piedang(即边程醒 形)
color Brush 渲染文本的颜色,所有遵守 QWiaget.palete的控件都支 持此属性
selection-background-color Brush 所选文本或项的背景色,默认为调色板的QPalete.Highlight 角色的值
selection-color Brush 所选文本或项的前景色,默认为调色板的 QPalete.HighlightedText角色的值

盒子的模型

大多数控件都是长方形的,一个长方形控件由 Content、Padding、Border、Margin 4部分构成,每个部分都是矩形。

Content 矩形是除掉边距、边框和填充之后的部分,默认情况下,边距、边框和填充的距离都为 0,因此这 4 个矩形是重合的,如图所示。

image-20230225185359062

可以用样式表分别设置这四个矩形之间的距离、边框的颜色。

  • Content 是输人内容的区域,可以设置 Content 区域宽度和高度的最大值和最小值,属性名称分别为 maxwidth、maxheight、min-width 和 min-height

    • “QSpinBox(min-height: 30px; max-height: 40px; min-width: 100px; max-width: 150px)”
  • 对于 Padding 区域,用padding 属性可以分别设置 Padding 与 Content 在上、右、下和左方向的距离,也可用padding-top、padding-right、padding-bottom 和 paddingleft 属性分别设置距离

    • “QSpinBox(padding: 10px 20px 25px 30px)”等价于”QSpinBox(padding-top: 10px; padding-right: 20px; padding-bottom: 25px;padding-left:30px)”
  • Border 区域可以设置的属性比较多,如表所示

    属性名称 类 型 说明
    border Border 设置边框的简写方法,相当于指定 border-color、 border-style、border-width
    border-top Border 设置控件顶部边框的简写方法,相当于指定 border- top-color、border-top-style、border-top-width
    border-right Border 设置控件右边框的简写方法,相当于指定border-right- color,border-right-style,border-right-width
    border-bottom Border 设置控件底部边框的简写方法,相当于指定 border-bottom-color、border-bottom-style、border-bottom-width
    border-left Border 设置控件左边框的简写方法,相当于指定 border-leftr- color、border-left-style、border-left-width
    border-color gh04 Box Colors 边框边界线的颜色,相当于指定 border toprcolor、 border-bottom-color、border-left-color、border-right-color,默认值为 color(即控件的前景色)
    border-top-color Brush 边框顶部边界线的颜色
    border-right-color Brush 边框右边界线的颜色
    border-bottom-color Brush 边框底部边界线的颜色
    border-left-color Brush 边框左边界线的颜色
    border-radius Radius 边框角落的半径,等效于指定 border-top-left-radius、 border-top-right-radius、 border-bottom-left-radius、 border-bottom-right-radius.默认为0
    border-top-left-radius Radius 边框左上角的半径
    border-top-right-radius Radius 边框右上角的半径
    border-bottom-right-radius Radius 边框右下角的半径
    order-bottom-left-radius Radius 边框左下角的半径
    border-style Border Style 边框边界线的样式(虚线、实线、点划线等),歌认 为 None
    border-top-style Border Style 边框顶部边界线的样式
    border-right-style Border Style 边框右侧边界线的样式
    border-bottom-style Border Style 边框底部边界线的样式
    border-left-style Border Style 边框左侧边界线的样式
    border-width Border Lengths 边框的宽度,等效于指定 border-top-width 、border-bottom-width、borde-left-width、border-right-width
    border-top-width L ength 边框顶部边界线的宽度
    border-right-width Length 边框右侧边界线的宽度
    border-bottom-width Length 边框底部边界线的宽度
    border-left-width Length 边框左侧边界线的宽度
    border-image Border Image 填充边框的图像,该图像皱分割成9个部分,并在必要时适当地拉伸
  • 对于 Margin 区域可以设置页边距。

    • margin 属性设篮控件的边距,等效于指定margin-top、margin-right、margin-bottom、margin-left,默认为0,margin-top、margin-right、margin-bottom、margin-left 分别设置控件的上、右、下和左侧的边距

与位置有关的属性

对于子控件,可以设置其在父控件中的位置,与此有关的属性名称如表所示

属性名称 类型 说 明
subcontrol-origin Onigin 子控件的矩形原点,默认为 padding
subcontrol-position Alignment 子控件在subcontrolorigin 属性指定的矩形内的对齐方式,殿记 值取决于子控件
position Relative Absolute 使用left、right top、bottom 属性的偏移是相对坐标还是绝对星 标,默认为 relative
spacing Length 控件的内部间距(比如复选按钮和文本之间的距离),默认值 决于当前风格
top、right、bottom、left Length 以 bottom 属性为例,若 position属性是relative(默认值),则将 子控件向上移动;若 position 是 absolute(绝对的),则 botom 属 性是指与子控件的下边缘的距离,该距离与subcontrol-origin 属 性有关,默认为0
height width Length 子控件的高度/宽度,默认值取决于当前样式。注意:除非另有 规定,否则在控件上设置此属性无效。若想要控件有一个固定 的高度,应将 min-height 和 max-height的值设置为相同,宽度 类似
max-height Length 控件或子控件的最大高度
max-width Length 控件或子控件的最大宽度
min-height Length 控件或子控件的最小高度,默认值依赖于控件的内容和风格
min-width Length 控件或子控件的最小宽度,默认值依赖于控件的内容和风格

由于样式表是字符串,因此对于比较复杂的样式表,可以将其保存到文本文件或二进制文件中,需要用时再读人进来。

基本语法

类似 CSS,QSS 每一条都是由一个选择器和一组声明构成:

选择器选出要对哪种控件进行样式修改,

每个声明都是键值对,键为属性,值为属性值

QSS语法

使用方式

为降低耦合,往往把 QSS 写在一个单独的style.qss文件中,然后在 main.pyQApplicationQMainWindow 中加载样式

编写QSS

新建一个扩展名为.qss的文件,如style.qss,编辑内容。(本文后面有完整的样式主题、QSS 编辑器推荐)

把写好的 .qss 添加到 qrc

加载QSS

创建一个加载QSS样式表的公共类:

1
2
3
4
5
6
7
8
class QSSLoader:
def __init__(self):
pass

@staticmethod
def read_qss_file(qss_file_name):
with open(qss_file_name, 'r', encoding='UTF-8') as file:
return file.read()

在代码中加载qss样式表:

1
2
3
4
5
6
7
8
9
app = QApplication(sys.argv)
window = MainWindow()

style_file = './style.qss'
style_sheet = QSSLoader.read_qss_file(style_file)
window.setStyleSheet(style_sheet)

window.show()
sys.exit(app.exec_())

用第三方包设置样式

第三方包 qt-material提供了一些样式主题,在使用qt-material之前,需要用命令”pipinstall qt-material”安装 gt-material。

  • 用gt-material的 list_themes()方法可获得主题名称列表
  • 用apply_stylesheet(parent,theme)方法可以应用样式主题。

QSS 样式分享

Qt 官方例子

Qt Style Sheets Examples

Qt官方给出的一些小例子,不一定好看但有很强的学习参考性

Qt-Material

UN-GCPDS/qt-material

This is another stylesheet for PySide6, PySide2 and PyQt5, which looks like Material Design(close enough).

“一个仿Material的样式,适用于PySide6, PySide2以及PyQt5”

浅色主题演示

深色主题演示

使用这套样式表也非常简单,作者已经打包发布到了pypi,所以我们只需要

1
pip install qt-material

安装,并在代码中import即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用例子
import sys
# from PySide6 import QtWidgets
# from PySide2 import QtWidgets
from PyQt5 import QtWidgets
from qt_material import apply_stylesheet

# create the application and the main window
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()

# setup stylesheet
apply_stylesheet(app, theme='dark_teal.xml')

# run
window.show()
app.exec_()

更多详细内容请查阅该项目的README

qtmodern

GitHub 首页

qtmodern

该库也已经添加至 PyPI,可以通过 pip 安装使用:

1
pip install qtmodern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import qtmodern.styles
import qtmodern.windows

...

app = QApplication()
win = YourWindow()

qtmodern.styles.dark(app)
mw = qtmodern.windows.ModernWindow(win)
mw.show()

...

PyDracula

GitHub 首页

YouTube 演示与教程

注意此项目对应 PySide6 / PyQt6 ,而不是 PyQt5

PyDracula 深色主题

PyDracula 浅色主题

一个现代化的 GUI ,对高 DPI 有更好支持:

Qt Widgets 是一项老技术,对高 DPI 设置没有很好的支持,当您的系统应用DPI 高于 100% 时,这些图像看起来会失真。 通过在 Qt 模块导入正下方的”main.py”中应用以下代码,您可以使用一种变通方法来最小化此问题。

1
2
3
4
5
# ADJUST QT FONT DPI FOR HIGHT SCALE
# ////////////////////////////////////
from modules import *
from widgets import *
os.environ["QT_FONT_DPI"]= "96"

PyOneDark

GitHub 首页

YouTube 展示视频

和上面的 PyDracula 是同一作者

同样是对应 PySide6

PyOneDark

该作者还有一个Simple_PySide_Base 的仓库,对 PySide2 或 PyQt5 初学者如何创建一个美观的 GUI 程序是不错的参考

PyQtDarkTheme

GitHub 首页

  • 扁平风格的深色/浅色主题
  • 支持 PySide 与 PyQt
  • 支持 PyInstaller
  • 解决了 Qt 版本间的风格差异
  • 深色和浅色主题的 QPalette

PyQtDarkTheme-深色主题

PyQtDarkTheme-浅色主题

此主题的详细使用方法请参考文档

飞扬青云-QSS

在飞扬青云的QWidgetDemo 项目中的styledemo 子项目包含了3套很好看的QSS样式

PS黑色

浅蓝色

扁平化白色

QSS目录链接

QDarkStyleSheet

The most complete dark/light style sheet for Qt applications

“最完整的深色/浅色Qt主题”

-文档

-GitHub

containers_no_tabs_buttons

containers_no_tabs_buttons1

containers_tabs_displays

widgets_inputs_fields1

也可以通过pip直接安装使用

1
pip install qdarkstyle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# PyQt5 使用例子
import sys
import qdarkstyle
from PyQt5 import QtWidgets

# create the application and the main window
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()

# setup stylesheet
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
# or in new API
app.setStyleSheet(qdarkstyle.load_stylesheet(qt_api='pyqt5'))

# run
window.show()
app.exec_()

GTRONICK-QSS

GTRONICK/QSS: QT Style Sheets templates

一组QSS样式

Ubuntu

MaterialDark

ElegantDark

Aqua

AMOLED

PyQt 图标库QtAwesome

GitHub 主页

QtAwesome enables iconic fonts such as Font Awesome and Elusive Icons in PyQt and PySide applications.

It started as a Python port of theQtAwesome C++ library by Rick Blommers.

可以通过 conda 或者 pip 安装

1
conda install qtawesome
1
pip install qtawesome

QtAwesome 截图

QtAwesome 还附带一个图标浏览器,可以显示所有可用的图标。你可以使用它来搜索适合需求的图标,然后复制应该用于创建该图标的名称到代码中以应用图标

QtAwesome 图标浏览器

QSS 编辑器

如果对上面推荐的这几个主题还不满意,你可以设计自己的QSS,下面推荐一些专用编辑器

QssStylesheetEditor

GitHub首页

中文README

QssStylesheetEditor 是一个功能强大的 Qt 样式表(QSS)编辑器,支持实时预览,自动提示,自定义变量, 支持预览自定义ui代码,引用QPalette等功能。

程序主界面

自动补全功能

这个软件有如下特点:

  • Qss代码高亮,代码折叠
  • Qss代码自动提示,自动补全
  • 实时预览 Qss 样式效果,可以预览几乎所有的 qtwidget 控件效果
  • 支持预览自定义界面代码
  • 支持在 Qss 中自定义变量
  • 自定义变量可以在颜色对话框中拾取变量的颜色
  • 支持通过颜色对话框改变QPalette,并在Qss中引用
  • 支持相对路径引用图片,以及引用资源文件中的图片
  • 支持切换不同的系统 theme,如 xp 主题,vista 主题等(不同 theme 下 qss 效果会略有差异)
  • 能够在 windows,linux,unix 上运行
  • 支持多国语言(目前已有中文,英文,俄文翻译)

还有许多强大而实用的功能,可以在README中查看

QSS Editor

🎨 Cross-platform application to edit and preview Qt style sheets(QSS).

跨平台的QSS编辑/预览应用

GitHub主页

GitHub realeases

下载地址2

qsseditor-1

qsseditor-2

Pycharm、VScode 插件

在Pycharm中可以安装Qt Style Sheet Highlighter 插件,提供对QSS的代码高亮功能

Qt Style Sheet Highlighter

Qt Style Sheet Highlighter 演示

在VScode里可以安装Qt for Python 插件,该插件不仅支持qss文件的代码高亮,还支持qml、qrc、pro等代码的高亮

Qt for Python

基于项和模型的控件

人们在工作中经常会处理大量数据,数据类型多种多样,数据的表现形式也很多,如列表结构树结构(层级关系)和二维表格结构数据。

PySide6 有专门的显示数据的控件和存储数据的模型可以显示和存储不同形式的数据,本章详细介绍显示数据的控件和存储数据的模型。

显示数据的控件分为两类,一类是基于项(item).的控件,另一类是基于模型model)的控件

  • 基于项的控件是基于模型的控件的简便类。基于项的控件把读取到的数据存储到项中
  • 基于模型的控件把数据存储到模型中,或通过模型提供读取数据的接口,然后通过控件把数据模型中的数据或关联的数据显示出来。

基于项的控件

基于项的控件有

  • 列表控件 QListWidget
  • 表格控件 QTaleWidget
  • 树结构控件 QTreeWidget

它们是从基于模型的控件继承而来的,基于模型的控件有 QListViewQTableView和QTreeView,这些控件之间的继承关系如图所示

image-20230304151535133

列表控件QListWidget及其项QListWidgetltem

列表控件QListWidget 由一列多行构成,每行称为一个项(item),每个项是一个QListWidgetItem对象。

可以继承 QListWidgetItem 创建用户自定义的项;也可以先创建QWidget实例,在其上添加一些控件,然后把QWidget 放到 QListWidgetItem 的位置形成复杂的列表控件。

列表控件QListWidget是从QListView 类继承而来的用QListWidget 类创建列表控件的方法如下所示,其中parent是QListWidget列表控件所在的父窗口或控件。

用QListWidgetItem创建列表项的方法如下所示其中type可取QListWidgetItemType(值为0)或QListWidgetItem.UserType(值为1000),前者是默认值,后者是用户自定义类型的最小值。可以用QListWidgetItem类创建子类定义新的类型。

1
2
3
4
5
6
7
8
from PySide6.QtWidgets import QListWidget, QListWidgetItem

QListWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

QListWidgetItem(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, listview: Union[PySide6.QtWidgets.QListWidget, NoneType]= None, type: int = < ItemType.Type: 0 >) -> None
QListWidgetItem(listview: Union[PySide6.QtWidgets.QListWidget, NoneType]= None, type: int = < ItemType.Type: 0 >) -> None
QListWidgetItem(other: PySide6.QtWidgets.QListWidgetItem) -> None
QListWidgetItem(text: str, listview: Union[PySide6.QtWidgets.QListWidget, NoneType]= None, type: int = < ItemType.Type: 0 >) -> None
列表控件QListWidget 的常用方法

列表控件QListWidget的常用方法如表所示主要方法介绍如下

  • 插入、新增、统计项

    • 用addItem(item: QListWidgetItem)方法可以在列表控件的末尾添加已经存在的项;

    • 用addItem(label: str)方法可以用文本创建一个新项,并添加到列表控件的末尾;

    • 用addItems(labels;Sequence[str])方法可以用文本列表添加多个项;

    • 用insertItem(row: int,item: QListWidgetItem)方法insertItem(row: int,label: str)方法和insertItems(row: int, labels:Sequence[str])方法可以在指定的行插人项;

    • 用count()方法可以获得项的数量,包括隐藏的项。

  • 设置项、获取项

    • 用setCurrentItem(QListWidgetItem)方法可以把指定的项设置成当前的项,

    • 用setCurrentRow(int)方法将指定行的项设置成当前项;

    • 用currentItem()方法获取当前的项;

    • 用currentRow()方法获取当前项所在的行;

    • 用rowQListWidgetItem)方法获取项所在的行号。

  • 获取项信息

    • 用item(row:int)方法可以获取指定行上的项(行的编号从0开始);
    • 用itemAt(QPoint)方法或itemAt(x:int,y:int)方法可以获取指定位置的项
    • 用visualItemRect(QListWidgetItem)方法可以获取项所占据的区域 QRect。
  • 移除项

    • 用takeItem(row:int)方法从列表中移除指定行上的项,并返回该项;
    • 用clear()方法清空所有的项.
  • 项排序

    • 用setSortingEnabled(bool)方法设置是否可以进行排序;
    • 用sortItems(order=Qt.AscendingOrder)方法设置排序方法,其中 order 可取 Qt.AscendingOrder(升序)或Qt.DescendingOrder(降序)。
  • 项放置到控件

    • 用setItemWidget(QListWidgetItem,QWidget)方法可以把一个控件放到项的位置,例如在一个 QWidget 上放置控件布局,然后把QWidget 对象放到项的位置形成复杂的项;
    • 用removeItemWidget(QListWidgetItem)方法可以移除项上的控件用itemWidget(QListWidgetItem)方法可以获取项的控件。
  • 查找项

    • 用findItems(text;str,flags;Qt.MatchFlags)方法可以查找满足匹配规则的项List[QListWidgetItem],其中参数flags 可取:
      • Qt.MatchExactly
      • Qt.MatchFixedString
      • Qt.MatchContains
      • Qt.MatchStartsWith
      • Qt.MatchEndsWith
      • Qt.MatchCaseSensitive
      • Qt.MatchRegularExpression
      • Qt.MatchWildcard
      • Qt.MatchWrap
      • Qt.MatchRecursive
  • 用setModel(model: QAbstractItemModel) 方法和 setSelectionModel(QItemSelectionModel)方法可分别设置数据模型和选择模型关于数据模型和选择模型见后续内容。

  • 用supportedDropActions()方法获取支持的拖放动作QtDropAction,其中Qt.DropAction 可以取:

    • Qt.CopyAction(复制)
    • Qt.MoveAction(移动)
    • Qt.LinkAction(链接)
    • Qt.IgnoreAction(什么都不做)
    • Qt.TargetMoveAction(目标对象接管)
QListWidget的方法及参数类型 说明
addItem(item: QListWidgetItem) 在列表控件中添加项
addItem(label: str) 用文本创建项并添加项
addItems(labels: Sequence[str]) 用文本列表添加多个项
insertItem(row: int,item: QListWidgetItem) 在列表中插人项
insertItem(row:int,label: str) 用文本创建项并插人项
insertItems(row: int, labels: Sequence[str]) 用文本列表创建项并插入多个项
setCurrentItem(QListWidgetItem) 设置当前项
currentItem() 获取当前项QListWidgetItem
count() 获取列表控件中项的数量
takeItem(row:int) 移除指定索引值的项,并返回该项
[slot]clear() 清空所有项
openPersistentEditor(QListWidgetItem) 打开指定项的编辑框,用于编辑文本
isPersistentEditorOpen(QListWidgetltem) 获取编辑框是否已打开
closePersistentEditor(QListWidgetltem) 关闭编辑框
currentRow() 获取当前行的索引号
item(row:int) 获取指定行的项
itemAt(QPoint) 获取指定位置处的项
itemAt(x;int,y:int) 获取指定位置处的项
itemFromIndex(QModelIndex) 获取指定模型索引QModelIndex的项
indexFromItem(QListWidgetItem) 获取指定项的模型索引QModelIndex
setItemWidget(QListWidgetItem,QWidget) 把某控件显示在指定项的位置处
removeItemWidget(QListWidgetItem) 移除指定项上的控件
itemWidget(QListWidgetItem) 获取指定项的位置处的控件
findItems(text: str,flags: Qt.MatchFlags) 查找满足匹配规则的项List[QListWidgetItem]
[slot]scrollToItem(QListWidgetItem) 滚动到指定的项,使其可见
selectedItems() 获取选中项的列表 List[QListWidgetItem]
setCurrentRow(int) 指定行的项为当前项
row(QListWidgetItem) 获取指定项所在的行号
visualItemRect(item: QListWidgetItem) 获取项所占据的区域QRect
setSortingEnabled(bool) 设置是否可以进行排序
isSortingEnabled() 获取是否可以排序
sortItems(order=Qt.AscendingOrder) 按照排序方式进行项的排序
supportedDropActions() 获取支持的拖放动作 Qt.DropAction
setModel(model:QAbstractItemModel) 设置数据模型
setSelectionModel(QItemSelectionModel) 设置选择模型
clearSelection() 清除选择
setAlternatingRowColors(enable:bool) 设置交替色
mimeData(items:Sequence[QListWidgetItem]) 获取多个项的 mime数据 QMimeData
mimeTypes() 获取mime数据的类型List[str]
列表项QListWidgetItem的常用方法

列表项QListWidgetItem的常用方法如表所示,主要方法介绍如下

  • 用setText(str)方法和 setIcon(QIcon)方法可以分别设置项的文字和图标;用text()方法和 icon()方法可以分别获取项的文字和图标。

  • 用setForeground(QColor)方法和 setBackground(QColor)方法可以设置前景色和背景色,其中参数 QColor 可以取:

    • QBrush
    • Qt.BrushStyle
    • Qt.GlobalColor
    • QGradientQImage
    • QPixmap
  • 用setSelected(bool)方法可以设置项是否处于选中状态,用isSelected()方法可以获取项是否处于选中状态。

  • 用setCheckState(Qt.CheckState)方法设置项是否处于勾选状态,其中参数 QCheckState 可以取以下值,用checkState()方法获取项的选状态。:

    • Qt.Unchecked(未勾选)
    • Qt.PartiallyChecked(部分勾选如果有子项)
    • QtChecked(勾选);
  • 用setFlags(Qt.ItemFlags)方法设置项的标识其中参数 QtItemFlags可取的值如表所示。

    例如setFlags(Qt.ItemIsEnabled Qt.ItemIsEditable)将使项处于可编辑状态,双击该项可以编辑项的文字。

    Qt.ItemFlags 的取值 说明 Qt.ItemFlags的取值 说明
    Qt.NoItemFlags 没有标识符 Qt.ItemIsUserCheckable 项可以勾选
    Qt.ItemIsSelectable 项可选 Qt.ItemIsEnabled 项被激活
    Qt.ItemIsEditable 项可编辑 Qt.ItemIsAutoTristate 如有子项,则有第3种状态
    Qt.ItemIsDragEnabled 项可以拖拽 Qt.ItemNeverHasChildren 项没有子项
    Qt.ItemIsDropEnabled 项可以拖放 Qt.ItemlsUserTristate 可在3种状态之间循环切换
  • 用setData(role:int,value:Any)方法可以设置项的某种角色的值,用data(role:int)方法可以获取某种角色的值

  • 用write(QDataStream)方法可以把项对象写人到数据流 QDataStream 中,用read(QDataStream)方法从数据流中读取项,数据流可以直接保存到文件中。有关数据流的内容见流数据章节

QListWidgetItem的方法 说明
setText(str) 设置文字
text() 获取文字
setIcon(QIcon) 设置图标
set TextAlignment(Qt.Alignment) 设置文字的对齐 方式
setForeground(QColor) 设置前景色
setBackground(QColor) 设置背景色
setCheckState(Qt.CheckState) 设置勾选状态
checkState() 获取勾选状态
setFlags(Qt.ItemFlags) 设置标识
setFont(QFont) 设置字体
setHidden(bool) 设置是否隐藏
isHidden() 获取是否隐藏
setSelected(bool) 设置是否被选中
isSelected() 获取是否被选中
icon() 获取图标
setStatusTip(str) 设置状态提示信息, 需激活 mouseTracking 属性
setToolTip(str) 设置提示信息
setWhatsThis(str) 设置按 Shift+F1 键的提示信息
write(QDataStream) 将项写人数据流
read(QDataStream) 从数据流中读取项
setData(role: int,value: Any) 设置某角色的数据
data(role:int) 获取某角色的数据
clone() 克隆出新的项
listWidget() 获取所在的列表 控件
列表控件QListWidget 的信号

列表控件QListWidget 的信号如表所示

QListWidget的信号及参数类型 说明
currentItemChanged(currentItem,previousltem) 当前项发生改变时发送信号
currentRowChanged(currentRow) 当前行发生改变时发送信号
currentTextChanged(currentText) 当前项的文本发生改变时发送信号
itemActivated(QListWidgetItem) 单击或双击项,使其变成活跃项时发送信号
itemChanged(QListWidgetltem) 项的数据发生改变时发送信号
itemClicked(QListWidgetItem) 单击某个项时发送信号
itemDoubleClicked(QListWidgetItem) 双击某个项时发送信号
item Entered(QListWidgetItem) 光标进人某个项时发送信号
itemPressed(QListWidgetltem) 当鼠标在某个项上按下按键时发送信号
itemSelectionChanged() 项的选择状态发生改变时发送信号
列表控件QListWidget的应用实例

下面的程序建立一个自定义对话框,通过菜单显示对话框。

对话框中放置两个列表控件第1个列表控件中放置可选科目,对每个项根据其所在的行把行号定义成项的角色值单击其中的项,将会移到第2个列表控件中,且按照角色值顺序插入,

同样,单击第2个列表控件中的项,也是按照角色值顺序插入到第1个列表控件中,单击对话框中的”确定”按钮,会把第2个列表控件中的内容输出到主界面上。

image-20230304170628555

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/4 15:43
# File_name: 01-列表控件QListWidget的应用实例.py

import sys
from PySide6.QtWidgets import(QApplication, QDialog, QWidget, QPushButton, QMenuBar, QLabel, QGridLayout, QListWidget, QTextBrowser, QVBoxLayout, QHBoxLayout, QFileDialog)
from PySide6.QtCore import Qt


class MyDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)

self.setupui()

def setupui(self):
label1 = QLabel("选修课科目")
label2 = QLabel("已选科目")

self.listWidget_available = QListWidget() # 列表控件
self.listWidget_selected = QListWidget() # 列表控件

btn_ok = QPushButton("确定")
btn_cancel = QPushButton("取消")

h = QHBoxLayout()
h.addStretch(1)
h.addWidget(btn_ok)
h.addWidget(btn_cancel)

grid = QGridLayout(self) # 标签、列表框采用格棚布局
grid.addWidget(label1, 0, 0)
grid.addWidget(label2, 0, 1)
grid.addWidget(self.listWidget_available, 1, 0)
grid.addWidget(self.listWidget_selected, 1, 1)
grid.addLayout(h, 2, 0, 1, 2)

class_available =["语文0", "数学1", "物理2", "化学3", "地理4", "历史5", "生物6", "哲学7", "测量8"]
self.listWidget_available.addItems(class_available) # 添加项

for i in range(self.listWidget_available.count()): # 用角色数据记录项的初始位置
item = self.listWidget_available.item(i) # 获取项
item.setData(Qt.UserRole, i) # 设置项的角色值,值为行号

self.listWidget_available.itemClicked.connect(self.listWidget_available_clicked)
self.listWidget_selected.itemClicked.connect(self.listWidget_selected_clicked)
btn_ok.clicked.connect(self.btn_ok_clicked)
btn_cancel.clicked.connect(self.btn_cancel_clicked)
# "确定"按钮的单击#"取消"按钮的单击

def listWidget_available_clicked(self, item): # 列表控件的单击槽函数
row = self.listWidget_available.row(item) # 获取项的行号
self.listWidget_available.takeItem(row) # 移除项
i = item.data(Qt.UserRole) # 移除项的角色值
for j in range(self.listWidget_selected.count()):
if i < self.listWidget_selected.item(j).data(Qt.UserRole):
self.listWidget_selected.insertItem(j, item) # 根据角色值插人到列表中

self.listWidget_selected.addItem(item)

def listWidget_selected_clicked(self, item): # 列表控件的单击槽函数
row = self.listWidget_selected.row(item)
self.listWidget_selected.takeItem(row)
i = item.data(Qt.UserRole)

for j in range(self.listWidget_selected.count()):
if i < self.listWidget_available.item(j).data(Qt.UserRole):
self.listWidget_available.insertItem(j, item) # 根据角色值插人到列表中

self.listWidget_available.addItem(item)

def btn_ok_clicked(self): # "确定"按钮的槽函数
self.setResult(QDialog.Accepted)

self.setVisible(False)

def btn_cancel_clicked(self): # "取消"按钮的槽函数
self.setResult(QDialog.Rejected)
self.setVisible(False)


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.widget_setupUi()

def widget_setupUi(self): # 建立主程序界面
menuBar = QMenuBar(self) # 定义菜单栏

file_menu = menuBar.addMenu("文件(E)") # 定义菜单
# 添加动作
action_selection = file_menu.addAction("选修课(&C)")
action_save = file_menu.addAction("保存(&S")
file_menu.addSeparator()
action_exit = file_menu.addAction("退出(&E)")

self.textBrowser = QTextBrowser(self) # 显示数据控件#主程序界面的布局
v = QVBoxLayout(self)
v.addWidget(menuBar)
v.addWidget(self.textBrowser)
action_selection.triggered.connect(self.action_selection_triggered)
action_save.triggered.connect(self.action_save_triggered) # 信号与槽的连接
action_exit.triggered.connect(self.close) # 退出动作的信号与窗口关闭的连接

def action_selection_triggered(self): # 自定义槽函数
dialog = MyDialog(self) # 自定义对话框实例
if dialog.exec(): # 模式显示对话框
n = dialog.listWidget_selected.count()
text = "你选择的选修课是:"
if n > 0:
for i in range(n):
text = text + " " + dialog.listWidget_selected.item(i).text()
self.textBrowser.append(text)

else:
self.textBrowser.append("你没有选择任何选修课!")

def action_save_triggered(self): # 自定义槽函数
string = self.textBrowser.toPlainText()
if len(string) > 0:
filename, filter = QFileDialog.getSaveFileName(self, "保存文件", ".", "文本文件(*.txt)")
if len(filename) > 0:
fp = open(filename, "a+", encoding="UTE -8")
fp.writelines(string)
fp.close()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

表格控件QTableWidget及其项QTableWidgetltem

表格控件QTableWidget 是从QTableView 类继承而来的,由多行多列构成,并且含有行表头和列表头

表格控件的每个单元格称为一个项(item),每个项是一个QTableWidgetItem 对象,可以设置每个项的文本图标颜色前景色和背景色等属性用QTableWidget

类创建表格控件的方法如下所示,其中parent 是表格控件QTableWidget所在的父窗口或控件,rows 和 columns 分别指定表格对象的行和列的数量。

1
2
3
4
from PySide6.QtWidgets import QTableWidget

QTableWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QTableWidget(rows: int, columns: int, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

用QIableWidgetItem 创建表格项的方法如下所示其中type可取QTableWidgetItemType值为0)或QTableWidgetItem,UserType(值为1000),前者是默认值,后者是用户自定义

1
2
3
4
5
6
from PySide6.QtWidgets import QTableWidgetItem

QTableWidgetItem(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str, type: int = < ItemType.Type: 0 >) -> None
QTableWidgetItem(other: PySide6.QtWidgets.QTableWidgetItem) -> None
QTableWidgetItem(text: str, type: int = < ItemType.Type: 0 >) -> None
QTableWidgetItem(type: int = < ItemType.Type: 0 >) -> None
表格控件QTableWidget 的常用方法

表格控件 QTableWidget 的常用方法如表所示,主要方法介绍如下

  • 用setRowCount(rows;int)方法和setColumnCount(columns;int)方法分别设置表格控件的行数和列数,行数和列数不含表头;
    • 用rowCount()方法和columnCount()方法可以获取表格控件的行数和列数。
  • 用insertRow(row:int)方法和insertColumn(column;int)方法可以插入行和插人列;
    • 用removeRow(row;int)方法和 removeColumn(column:int)方法可以分别删除指定的行和列;
    • 用clear()方法可以清空包含表头在内的所有内容;
    • 用clearContents()方法可以清空不含表头的内容。
  • 用setItem(row:int;column:int,QTableWidgetItem)方法可以在指定的行和列处设置表格项;
  • 用takeItem(row;int,column:int)方法可以从表格控件中移除表格项,并返回此表格项。
  • 用setCurrentCell(row:int,column:int)方法可以将指定的行列单元设为当前单元格,
  • 用setCurrentItem(QTableWidgetItem)方法将指定的表格项设置成当前项,
  • 项信息获取
    • 用currentItem()方法获取当前的表格项。
    • 用item(row:int,column;int)方法获取指定行和列处的表格项;
    • 用itemAt(QPoint)或itemAt(x:int,y;int)方法获取指定位置处的表格项,如果没有,则返回 None。
    • 用row(QTableWidgetItem)方法和 column(QTableWidgetItem)方法获取表格项所在的行号和列号。
  • 用setSortingEnabled(bool)方法设置表格控件是否可排序,
    • 用sortItems(column:int,order= Qt.AscendingOrder)方法对指定的列进行升序或降序排列。
  • 用setHorizontalHeaderItem(column; int,QTableWidgetItem)和 setVerticalHeaderItem(row;int,QTableWidgetItem)方法设置水平和竖直表头;
    • 用setHorizontalHeaderLabels(labels; Sequence[str])和 setVerticalHeaderLabels(labels;Sequence[str])方法用宇符串序列定义水平和竖直表头;
    • 用horizontalHeaderItem(column:int)和verticalHeaderItem(row:int)方法取水平和垂直表头的表格项;
    • 用takeHorizontalHeaderItern(column; int)和 takeVerticalHeaderItem(row; int)方法可以移除表头,并返回被移除的表格项
QTableWidget 的方法及参数类型 说 明
setRowCount(rows; int) 设置行数
setColumnCount(columns:int) 设置列数
[slot]insertRow(row:int) 在指定位置插入行
[slot]insertColumn(column:int) 在指定位置插人列
rowCount() 获取行数
columnCount() 获取列数
[slot]removeRow(row:int) 移除指定的行
[slot]removeColumn(column:int) 移除指定的列
setItem(row:int,column:int,QTableWidgetItem) 在指定行和列处设置表格项
takeItem(row:int,column: int) 移除并返回表格项
setCurrentCell(row:int,column:int) 设置当前的单元格
setCurrentItem(QTableWidgetltem) 设置当前的表格项
currentItem() 获取当前的表格项
row(QTableWidgetItem) 获取表格项所在的行
column(QTableWidgetItem) 获取表格项所在的列
currentRow() 获取当前行
currentColumn() 获取当前列
setHorizontalHeaderItem(column:int,QTableWidgetItem) 设置水平表头
setHorizontalHeaderLabels(labels:Sequence[str]). 用字符串序列设置水平表头
horizontalHeaderItem(column:int) 获取水平表头的表格项
takeHorizontalHeaderItem(column: int) 移除水平表头的表格项,并返回表格项
setVerticalHeaderItem(row:int,QTableWidgetItem) 设置竖直表头
setVerticalHeaderLabels(labels:Sequence[str]) 用字符串序列设置竖直表头
verticalHeaderItem(row:int) 获取竖直表头的表格项
takeVerticalHeaderItem(row: int) 移除竖直表头的表格项,并返回表格项
[slot]clear() 清空表格项和表头的内容
[slot]clearContents() 清空表格项的内容
editItem(QTableWidgetItem) 开始编辑表格项
findItems(text: str,flags: Qt.MatchFlags) 获取满足条件的表格项列表
item(row:int,column:int) 获取指定行和列处的表格项
itemAt(QPoint) 获取指定位置的表格项
itemAt(x:int,y:int) 获取指定位置的表格项
openPersistentEditor(QTableWidgetItem) 打开编辑框
isPersistentEditorOpen(QTableWidgetItem) 获取编辑框是否已经打开
closePersistentEditor(QTableWidgetItem) 关闭编辑框
[slot]scrollToItem(QTableWidgetItem) 滚动表格使表格项可见
selectedItems() 获取选中的表格项列表
setCellWidget(row:int,column:int,QWidget) 设置单元格的控件
cellWidget(row:int,column; int) 获取单元格的控件QWidget
removeCellWidget(row:int,column:int) 移除单元格上的控件
setSortingEnabled(bool) 设置是否可以排序
isSortingEnabled() 获取是否可以排序
sortItems(column: int,order=Qt.AscendingOrder) 按列排序
supportedDropActions() 获取支持的拖放动作 Qt.DropAction
表格项QTableWidgetltem的常用方法

表格项QTableWidgetItem 的常用方法如表所示,其方法与列表项的方法基本

QTableWidgetItem 的方法及参数类型 说明
setText(str) 设置文本
text() 获取文本
setIcon(QIcon) 设置图标
setTextAlignment(Qt.Alignment) 设置文字的对齐方式
setForeground(QColor) 设置前景色
setBackground(QColor) 设置背景色
setCheckState(Qt.CheckState) 设置勾选状态
checkState() 获取勾选状态
setFlags(Qt.ItemFlag) 设置标识
setFont(QFont) 设置字体
Tow() 获取所在的行
column 获取所在的列.
setSelected(bool) 设置是否被选中
isSelected() 获取是否被选中
icon() 获取图标
setStatusTip(str) 设置状态提示信息,需 激活列表控件的 mouseTracking 属性
setToolTip(str) 设置提示信息
setWhatsThis(str) 设置按Shift十Fl键的 提示信息
write(QDataStream) 将项写人数据流
read(QDataStream) 从数据流中读取项
setData(role: int,Any) 设置某种角色的数据
data(role:int) 获取某种角色的数据
clone() 复制出新的项
tableWidget() 获取所在的表格控件
表格控件QTableWidget的信号

表格控件QTableWidget的信号如表所示

QTableWidget的信号及参数类型 说明
cellActivated(row:int,column:int) 单元格活跃时发送信号
cellChanged(row:int, column:int) 单元格的数据变化时发送信号
cellClicked(row:int,column:int) 单击单元格时发送信号
cellDoubleClicked(row: int,column:int) 双击单元格时发送信号
cellEntered(row:int,column: int) 光标进人单元格时发送信号
cellPressed(row: int,column: int) 光标在单元格上按下按键时发送信号
currentCellChanged(currentRow: int,currentColumn:int, previousRow: int, previousColumn: int) 当前单元格发生改变时发送信号
currentItemChanged(currentItem,previousltem) 当前表格项发生改变时发送信号
itemActivated(QTableWidgetltem) 表格项活跃时发送信号
itemChanged(QTableWidgetltem) 表格项的数据发生改变时发送信号
itemClicked(QTableWidgetItem) 单击表格项时发送信号
itemDoubleCIicked(QTableWidgetItem) 双击表格项时发送信号
itemEntered(QTableWidgetltem) 光标进入表格项时发送信号
itemPressed(QTableWidgetItem) 光标在表格项上按下按键时发送信号
itemSelectionChanged() 选择的表格项发生改变时发送信号
表格控件QTableWidget的应用实例

下面的程序从Excel文档studentxlsx中读取数据用表格控件显示读取的数据可以统计总成绩和平均成绩,并可以把数据保存到新的 Excel 文档中。

image-20230304212312654

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/4 17:42
# File_name: 02-表格控件QTableWidget的应用实例.py

import sys, os
from PySide6.QtWidgets import(QApplication, QWidget, QMenuBar, QVBoxLayout, QFileDialog, QTableWidget, QTableWidgetItem)
from openpyxl import load_workbook, Workbook


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUi()

def setupUi(self):
menuBar = QMenuBar(self)
fileMenu = menuBar.addMenu("文件")
self.action_open = fileMenu.addAction("打开")
self.action_saveAs = fileMenu.addAction("另存")
fileMenu.addSeparator()
self.action_exit = fileMenu.addAction("退出")
statisticMenu = menuBar.addMenu("统计")
self.action_total = statisticMenu.addAction("插人总成绩")
self.action_average = statisticMenu.addAction("插人平均分")

self.action_saveAs.setEnabled(False)
self.action_total.setEnabled(False)
self.action_average.setEnabled(False)

self.tableWidget = QTableWidget(self)
v = QVBoxLayout(self)
v.addWidget(menuBar)
v.addWidget(self.tableWidget)

self.action_open.triggered.connect(self.action_open_triggered) # 信号与槽连接
self.action_saveAs.triggered.connect(self.action_saveAs_triggered) # 信号与槽连接
self.action_exit.triggered.connect(self.close) # 信号与槽连接
self.action_total.triggered.connect(self.action_total_triggered) # 信号与槽连接
self.action_average.triggered.connect(self.action_average_triggered) # 信号与槽连接

def action_open_triggered(self): # 打开Excel文件#读取数据后,保存数据的列表
fileName, file = QFileDialog.getOpenFileName(self, "打开文件", ".", "Excel文件(*.xlsx *.xls)")
score = list() # 读取数据后,保存数据的列表

if os.path.exists(fileName):
wbook = load_workbook(fileName)
wsheet = wbook.active
cell_range = wsheet[wsheet.dimensions] # 按行排列的单元格对象元组

for i in cell_range: # i是Excel行单元格元组
temp = list() # 临时列表
for j in i: # j是单元格对象
temp.append(str(j.value))
score.append(temp)

row_count = len(score) - 1 # 行数,不包含表头
column_count = len(score[0]) # 列数

self.tableWidget.setRowCount(row_count)
self.tableWidget.setColumnCount(column_count)
self.tableWidget.setHorizontalHeaderLabels(score[0])
for i in range(row_count):
for j in range(column_count):
cell = QTableWidgetItem()
cell.setText(score[i + 1][j])
self.tableWidget.setItem(i, j, cell)

self.action_saveAs.setEnabled(True)
self.action_total.setEnabled(True)
self.action_average.setEnabled(True)

def action_saveAs_triggered(self): # 另存
score = list()

filename, fil = QFileDialog.getOpenFileName(self, "打开文件", ".", "excel文件(*.xlsx)")

if filename != "":
temp = list()
for j in range(self.tableWidget.columnCount()):
temp.append(self.tableWidget.horizontalHeaderItem(j).text())

score.append(temp)

for i in range(self.tableWidget.rowCount()):
temp = list()
for j in range(self.tableWidget.columnCount()):
temp.append(self.tableWidget.item(i, j).text())
score.append(temp)

wbook = Workbook()
wsheet = wbook.create_sheet("学生成绩", 0)
for i in score:
wsheet.append(i)
wbook.save(filename)

def action_total_triggered(self):
column = self.tableWidget.columnCount()
self.tableWidget.insertColumn(column)
item = QTableWidgetItem("总成绩")
self.tableWidget.setHorizontalHeaderItem(column, item)
for i in range(self.tableWidget.rowCount()): # 计算总成绩
total = 0
for j in range(2, 6):
total = total + int(self.tableWidget.item(i, j).text())
item = QTableWidgetItem(str(total))
self.tableWidget.setItem(i, column, item)

def action_average_triggered(self): # 计算平均成绩
column = self.tableWidget.columnCount()
self.tableWidget.insertColumn(column)
item = QTableWidgetItem("平均成绩")
self.tableWidget.setHorizontalHeaderItem(column, item)
for i in range(self.tableWidget.rowCount()):
total = 0
for j in range(2, 6):
total = total + int(self.tableWidget.item(i, j).text())
item = QTableWidgetItem(str(total / 4))
self.tableWidget.setItem(i, column, item)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

树结构控件QTreeWidget 及其项QTreeWidgetltem

树结构控件QTreeWidget 继承自QTreeView类它是QTreeView 的便利类。

树结构控件由 1列或多列构成,没有行的概念。

树结构控件有 1个或多个顶层项,顶层项下面有任意多个子项,子项下面还可以有子项,顶层项没有父项。

顶层项和子项都是QTreeWidgetItem,每个QTreeWidgetItem 可以定义在每列显示的文字和图标,一般应在第1列中定义文字或图标,其他列中是否设置文字和图标,需要用户视情况而定。

可以把每个项理解成树结构控件的一行,只不过行之间有层级关系,可以折叠和展开。

用QTreeWidget 类创建树结构控件的方法如下。其中parent是QTreeWidget 树结构控件所在的父窗口或控件

1
2
3
from PySide6.QtWidgets import QTreeWidget

QTreeWidget(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

用QTreeWidgetItem类创建树结构项的方法如下。其中Sequence[str]表示字符串序列,是各列上的文字。

  • 第1个参数是QTreeWidget 时表示项追加到树结构控件中,这时新创建的项是顶层项;
  • 第1个参数是QTreeWidgetItem表示父项,这时新创建的项作为子项追加到父项下面;
  • 第2个参数是QTreeWidgetItem 时表示新创建的项插人到该项
1
2
3
4
5
6
7
8
9
10
11
from PySide6.QtWidgets import QTreeWidgetItem

QTreeWidgetItem(other: PySide6.QtWidgets.QTreeWidgetItem) -> None
QTreeWidgetItem(parent: PySide6.QtWidgets.QTreeWidgetItem, after: PySide6.QtWidgets.QTreeWidgetItem, type: int = < ItemType.Type: 0 >) -> None
QTreeWidgetItem(parent: PySide6.QtWidgets.QTreeWidgetItem, strings: Sequence[str], type: int = < ItemType.Type: 0 >) -> None
QTreeWidgetItem(parent: PySide6.QtWidgets.QTreeWidgetItem, type: int = < ItemType.Type: 0 >) -> None
QTreeWidgetItem(strings: Sequence[str], type: int = < ItemType.Type: 0 >) -> None
QTreeWidgetItem(treeview: PySide6.QtWidgets.QTreeWidget, after: PySide6.QtWidgets.QTreeWidgetItem, type: int = < ItemType.Type: 0 >) -> None
QTreeWidgetItem(treeview: PySide6.QtWidgets.QTreeWidget, strings: Sequence[str], type: int = < ItemType.Type: 0 >) -> None
QTreeWidgetItem(treeview: PySide6.QtWidgets.QTreeWidget, type: int = < ItemType.Type: 0 >) -> None
QTreeWidgetItem(type: int = < ItemType.Type: 0 >) -> None
树结构控件 QTreeWidget 的常用方法

树结构控件 QTreeWidget 的常用方法如表所示主要方法介绍如下

树结构控件的列的数量由 setColumnCount(columns:int)方法定义,可以为项的每个列定义文字、图标、背景色和前景色、控件和角色值。

树结构控件可以添加顶层项,往项中添加子项需要用项的方法。

  • 用addTopLevelItem(QTreeWidgetItem)方法和 addTopLevelItems(Sequence[QTreeWidgetItem])方法添加顶层项;
    • 用insertTopLevelItem(index: int,QTreeWidgetItem)方法和 insertTopLevelItems(index; int, Sequence[QTreeWidgetItem])方法可以插人顶层;
  • 用takeTopLevelItem(index:int)方法可以移除顶层项,并返回该项;
  • 用topLevelItemCount()方法可以获取顶层项的数量;
  • 用topLevelItem(index;int)方法可以获取索引值是index 的顶层项。
  • 用setCurrentItem(QTreeWidgetItem)方法设置当前项,
  • 用setCurrentItem(QTreeWidgetItem,column:int)方法设置当前项和当前列,用currentItem()方法获取当前项。
  • 用setHeaderItem(QTreeWidgetItem)方法可以设置表头项,
    • 用setHeaderLabel(label:str)方法和 setHeaderLabels(labels;Sequence[str])方法设置表头文字。
  • 用collapseItem(QTreeWidgetItem)方法可以折叠指定的项
    • 用collapseAlI()方法可以折叠所有的项,
  • 用expandItem(QTreeWidgetItem)方法可以展开指定的项
    • 用expandAl1()方法可以展开所有的项。
QTreeWidget的方法及参数类型 说明
setColumnCount(columns: int) 设置列数
columnCount() 获取列数
currentColumn() 获取当前列
setColumnWidth(column:int,width:int) 设置列的宽度
setColumnHidden(column:int,hide:bool) 设置列是否隐藏
addTopLevelltem(QTreeWidgetItem) 添加顶层项
addTopLevelItems(Sequence[QTreeWidgetItem]) 添加多个顶层项
insertTopLevelltem(index: int,QTreeWidgetItem) 插人顶层项
insertTopLeveltems(index: int,Sequence[QTreeWidgetltem]) 插入多个顶层项
takeTopLevelltem(index: int) 移除顶层项,并返回移除的项
1opLevelItem(index:int) 获取索引值是int的顶层项
topLevelItemCount() 获取顶层项的数量
setCurrentItem(QTreeWidgetltem) 把指定的项设置成当前项
setCurrentItem(QTreeWidgetItem,column:int) 设置当前项和当前列
currentItem() 获取当前项
editItem(QTreeWidgetItem,column:int=0) 开始编辑项
findItems(str,Qt.MatchFlag,column:int=0) 搜索项,返回项的列表
setHeaderItem(QTreeWidgetItem) 设置表头
setHeaderLabel(label:str) 设置表头第1列文字
setHeaderLabels(labels: Sequence[str]) 设置表头文字
headerItem() :0830109293319 获取表头项
indexOfTopLevelItem(QTreeWidgetltem) 获取顶层项的索引值
invisibleRo0tItem() 获取不可见的根项
itemAbove(QTreeWidgetltem) 获取指定项之前的项
itemBelow(QTreeWidgetItem) 获取指定项之后的项
itemAr(QPoint) 获取指定位置的项
itemAt(x:int,y:int) 获取指定位置的项
openPersistentEditor(QTreeWidgetItem,column=0) 打开编辑框
isPersistentEditorOpen(QTreeWidgetItem,column=0) 获取编辑框是否已经打开
closePersistentEditor(QTreeWidgetItem,column=0) 关闭编辑框
[slot]scrolToItem(QTreeWidgetItem) 滚动树结构,使指定的项可见
selectedItems() 获取选中的项列表
setFirstItemColumnSpanned(QTreeWidgetItem,bool) 只显示指定项的第1列的值
isFirstItemColumnSpanned(QTreeWidgetItem) 获取是否只显示第1列的值
setItemWidget(QTreeWidgetItem,column: int,QWidget) 在指定项的指定列设置控件
itemWidget(QTreeWidgetItem,column:int) 获取项上的控件
removeItem Widget(QTreeWidgetItem,column:int) 移除项上的控件
[slot]collapseItem(QTreeWidgetItem) 折叠项
collapseA1() 折叠所有的项
[slot]expandItem(QTreeWidgetItem) 展开项
expandAII() 展开所有的项
[slot]clear() 清空所有项
树结构项QTreeWidgetItem 的常用方法

树结构项QTreeWidgetItem 的常用方法如表所示,主要方法介绍如下

  • 用addChild(QIreeWidgetItem)方法或addChildren(Sequence[QTreeWidgetItem])方法可以为项添加子项

    • 用insertChild(index;int,QTreeWidgetItem)方法或insertChildren(index:int,Sequence[QTreeWidgetItem])方法可以在项的子项中插人子项,
    • 用childCount()方法可以获取子项的数量,
    • 用child(index:int)方法可以获取指定索引号的子项。
  • 用takeChild(int)方法移除指定索引号的项,并返回该项;

    • 用removeChild(QTreeWidgetItem)方法移除指定的子项;
    • 用takeChildren()方法移除所有的子项,并返回子项列表。
  • 用setText(index:int,str)方法设置项的第int 列的文字,

    • 用setIcon(index:int;QIcon)方法设置项的第int列的图标,
    • 用setFont(index;int,QFont)方法设置项的第int列的字体,
    • 用setBackground(index:int,QColor)方法设置项第int列的背景色,
    • 用setForeground(index:int,QColor)方法设置项第int列的前景色
  • 用setCheckState(column:int,Qt.CheckState)方法设置项的第 int 列的选状态,其中Qt.CheckState可以取以下值;用checkState(column;int)方法获取项的勾选状态。

    • Qt.Unchecked(未勾选)
    • QtPartiallyChecked(部分勾选,如果有子项)
    • Qt.Checked(勾选)
  • 用setExpanded(True)方法展开项

    • 用setExpanded(False)方法折叠项
  • 用setChildIndicatorPolicy(QTreeWidgetItem,ChildIndicatorPolicy)方法设置展开折叠标识的显示策略,其中QTreeWidgetItem.ChildIndicatorPolicy 可以取:

    • QTreeWidgetItem.ShowIndicator(不论有没有子项,都显示标识)
    • QTreeWidgetItem.DontShowIndicator(即便有子项,也不显示标识)
    • QTreeWidgetItem.DontShowIndicatorWhenChildless(当没有子项时不显示标识)
QTreeWidgetItem 的方法及参数类型 说 明
addChild(QTreeWidgetItem) 添加子项
addChildren(Sequence[QTreeWidgetItem]) 添加多个子项
insertChild(int.QTreeWidgetItem) 插人子项
insertChildren(int,Sequence[QTreeWidgetItem]) 插人多个子项
child(int) 获取子项
childCount() 获取子项数量
takeChild(index:int) 移除子项,并返回子项
takeChildren() 移除所有子项,返回子项列表
removeChild(QTreeWidgetItem) 移除子项
setCheckState(column:int,Qt.CheckState) 设置勾选状态
checkState(column:int) 获取勾选状态
setText(column:int,text: str) 设置列的文本
text(column:int) 获取列的文本
setTextAlignment(column: int,alignment: int) 设置列的文本对齐方式
setIcon(column:int,QIcon) 设置列的图标
setFont(column:int,QFont) 设置列的字体
{ont(column:int) 获取列的字体
setData(column:int.role: int,Any) 设置列的角色值
data(column:int,role:int) 获取列的角色值
setBackground(column:int,QColor) 设置背景色
setForeground(column:int,QColor) 设置前景色
columnCount() 获取列的数量
indexOfChild(QTreeWidgetItem) 获取子项的索引
setChildIndicatorPolicy(QTreeWidgetItem.ChildIndicatorPolicy) 设置展开/折叠标识的显示策略
childIndicatorPolicy() 获取展开策略
setDisabled(bool) 设置是否激活
isDisabled() 获取是否激活
setExpanded(bool) 设置是否展开
isExpanded() 获取是否已经展开
setFirstColunnSpanned(bool) 设置只显示第1列的内容
setFlags(Qt.ItemFlag) 设置标识
setHidden(bool) 设置是否隐藏
setSelected(bool) 设置是否选中
setStatusTip(column; int,str) 设置状态信息
setToolTip(column:int,str) 设置提示信息
setWhatsThis(column:int,str) 设置按Shift十F1键显示的信息
sortChildren(column;int,Qt.SortOrder) 对子项进行排序
parent() 欢取项的父项
treeWidget() 获取项所在的树结构控件
树结构控件QTreeWidget 的信号

树结构控件QTreeWidget 的信号如表所示

QTreeWidget的信号及参数类型 说明
currentItemChanged(currentltem,previousItem) 当前项发生改变时发送信号
itemActivated(item,column) 项变成活跃项时发送信号
itemChanged(item,column) 项发生改变时发送信号
itemClicked(item,column) 单击项时发送信号
itemDoubleClicked(item,column) 双击项时发送信号
itemEntered(item,column) 光标进人项时发送信号
itemPressed(item,column) 在项上按下鼠标按键时发送信号
itemExpanded(item) 展开项时发送信号
itemCollapsed(item) 折叠项时发送信号
itemSelectionChanged() 选择的项发生改变时发送信号
树结构控件QTreeWidget 的应用实例

下面的程序建立一个树结构控件,单击树结构控件的子项,可以把子项上的内容输出程序运行界面如图所示。

image-20230304234931384

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/4 21:42
# File_name: 03-树结构控件QTreeWidget的应用实例.py

from PySide6.QtWidgets import QApplication, QWidget, QSplitter, QTextBrowser, QHBoxLayout, QTreeWidget, QTreeWidgetItem
from PySide6.QtCore import Qt
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(900, 600)

self.widget_setupUi()
self.treeWidget_setUp()

def widget_setupUi(self): # 建立主程序界面
h = QHBoxLayout(self)
splitter = QSplitter(Qt.Horizontal, self)
h.addWidget(splitter)
self.treeWidget = QTreeWidget()
self.textBrowser = QTextBrowser()
splitter.addWidget(self.treeWidget)
splitter.addWidget(self.textBrowser)

def treeWidget_setUp(self): # 建立树结构控件
self.treeWidget.setColumnCount(2) # 设置列数
header = QTreeWidgetItem() # 表头项
header.setText(0, "噪声源")
header.setText(1, "噪声值")
header.setTextAlignment(0, Qt.AlignCenter)
header.setTextAlignment(1, Qt.AlignCenter)
self.treeWidget.setHeaderItem(header)

self.topItem_1 = QTreeWidgetItem(self.treeWidget) # 顶层项
self.topItem_1.setText(0, "高铁")

child_1 = QTreeWidgetItem(self.topItem_1,["结构噪声", "70"])
child_2 = QTreeWidgetItem(self.topItem_1,["电机噪", "60"])
child_3 = QTreeWidgetItem(self.topItem_1,["空调噪声", "44"])
child_4 = QTreeWidgetItem(self.topItem_1,["气动噪声"])
child_5 = QTreeWidgetItem(child_4,["受电弓噪声", "66"])
child_6 = QTreeWidgetItem(child_4,["外壳气流噪声", "66"])

self.topItem_2 = QTreeWidgetItem(self.treeWidget)
self.topItem_2.setText(0, "地铁")
child_7 = QTreeWidgetItem(self.topItem_2,["结构噪声", "60"])
child_8 = QTreeWidgetItem(self.topItem_2,["电机噪声", "50"])
child_9 = QTreeWidgetItem(self.topItem_2,["空调噪声", "44"])
child_10 = QTreeWidgetItem(self.topItem_2,["气动噪声"])
child_11 = QTreeWidgetItem(child_10,["受电弓噪声", "56"])
child_12 = QTreeWidgetItem(child_10,["外壳气流噪声", "56"])

self.treeWidget.itemClicked.connect(self.treeWidget_clicked) # 信号与槽的连接
self.treeWidget.expandAll()

def treeWidget_clicked(self, item, column):
if item.text(1) != "":
self.textBrowser.append("噪声源:%s 噪声值:%s" %(item.text(0), item.text(1)))


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

Qt 中的 Model/View 结构

Qt 官方文档-Model/View编程

Qt Model/View 编程思想

简介

源数据由模型(Model) 读取,然后在视图(View) 组件上显示和编辑,在界面上编辑修改的数据又通过模型保存到源数据。

Model/View 结构将数据模型和用户界面分离开来,分别用不同的实现,是一种显示和编辑数据的有效结构,在处理大型数据时尤其明显。

Model/View基本结构

  • Data(源数据)是原始数据,如数据库的一个数据表或SQL查询结果、内存中的一个字符串列表或磁盘文件结构等
  • Model(模型/数据模型)与源数据通信,并为视图组件提供数据接口。它从源数据提取需要的数据,用于视图组件进行显示和编辑
  • View(视图/视图组件)是界面控件,视图从数据模型中根据一定条件(如行号、列号等)获得模型索引(一个指向数据项的引用),然后显示在界面上
  • Delegate(代理)在视图与模型之间交互操作时提供临时编辑组件的功能

由于通过 Model/View 结构将原始数据与显示/编辑界面分离开来,可以将一个数据模型在不同的视图中显示,也可以在不修改数据模型的情况下,设计特殊的视图组件

通信机制

模型、视图、代理之间使用信号与槽通信。

  • 当源数据发生变化时,数据模型发射信号通知视图组件

  • 当用户在界面上操作数据时,视图组件发射信号表示这些操作信息

  • 在编辑数据时,代理会发射信号告知数据模型和视图组件编辑器的状态

数据模型基本结构

数据模型的3种表现形式

model index 模型索引

QModelIndex是表示模型索引的类。通过数据模型存取的每个数据都有一个模型索引,视图组件和代理都通过索引来获取数据。这样保证了数据的表示与数据存取方式的分离。

模型索引提供数据存取的一个临时指针,用于通过数据模型提取或修改数据。

模型内部组织数据的结构可能随时改变,所以模型索引是临时的。例如,对于一个QTreeView组件,如果获取一个节点的模型索引后又修改了模型数据,则先前获得的模型索引或不再指向原节点。

行号和列号

数据模型的基本形式是用行和列定义的表格数据,但这并不意味着底层的数据是用二维数组存储的,”行”与”列”的概念只是为了组件之间交互方便而做的人为规定。

一个模型索引只包含行号和列号。通过行号、列号、父项的模型索引三个参数来获得需要的模型索引。

父项

当数据模型是列表或表格模型时,所有数据项的父项就是顶层项

对于树状模型,一个节点(项)有父节点,也可以是其他节点的父节点。故在构建数据项的模型索引时,必须指定正确的行号、列号和父节点

item role 项的角色

为数据模型的一个项设置数据时,可以为项设置不同角色的数据。

一个项可以有不同角色的数据,对应不同的用途。

数据角色定义在Qt.ItemDataRole枚举中,主要包括以下枚举值

一般角色
Qt.ItemDataRole 描述
Qt.DisplayRole 0 以文本形式呈现的键数据
Qt.DecorationRole 1 数据被渲染为图标等装饰(数据为QColor/ QIcon/ QPixmap)
Qt.EditRole 2 编辑器中正在编辑的数据
Qt.ToolTipRole 3 工具提示中显示的数据
Qt.StatusTipRole 4 状态栏中显示的数据
Qt.WhatsThisRole 5 “What’s This?”模式下显示的数据
Qt.SizeHintRole 13 将会应用到视图的数据项的大小提示
描述外观和元数据的角色
Qt.ItemDataRole 描述
Qt.FontRole 6 在默认代理中呈现数据时使用的字体(QFont)
Qt.TextAlignmentRole 7 数据项对齐方式,当设置了数据项的对齐格式时有效(Qt.ALignment)
Qt.CheckStateRole 10 获取项目的选中状态(Qt.CheckState)

下图是几种常用数据角色的示意图:

model/view-roles

Delegate 代理

代理在视图与模型之间交互操作时提供临时编辑组件的功能。模型向视图提供数据是单向的,一般仅用于显示。当需要在视图上编辑数据时,代理功能会为编辑数据提供一个编辑器,这个编辑器获取模型的数据、接受用户编辑的数据后又提交给模型。

例如在QTableView组件上双击一个单元格编辑数据时,在单元格里就会出现一个QLineEdit组件,这个编辑框就是代理提供的临时编辑器。代理的主要任务就是为视图组件提供代理编辑器。

对于一些特殊的数据编辑需求,例如只允许输入整型数,使用一个QSpinBox作为代理组件更合适;

从列表中选择一个数据,使用一个QComboBox作为代理组件更好。这时就需要从QStyledItemDelegate继承创建自定义代理类。

自定义代理

Qt_Delegate 代理类的继承关系

不管从QStyledItemDelegate还是QItemDelegate继承设计自定义代理,都必须实现下面的4个方法

  • createEditor() 创建用于编辑模型数据的widget组件,如一个QSpinBox或一个QComboBox组件
  • setEditorData() 从模型获得数据,供widget组件进行编辑
  • setModelData() 将widget上的数据更新到数据模型
  • updateEditorGeometry() 用于给widget组件设置合适的大小

Qt model 类

Model类的继承关系

QFileSystemModel

为本机的文件系统提供一个数据模型,可用于访问本机的文件系统。

比如和QTreeView视图组件结合使用,可以用目录树的形式显示本机上的文件系统,类似Windows的文件资源管理器。

使用QFileSystemModel提供的接口函数,可以创建目录、删除目录、重命名目录,可以获得文件名称、目录名称、文件大小等参数,可以获得文件的详细信息

QStringListModel

用于处理字符串列表的数据模型,可以作为QListView的数据模型,在界面上显示和编辑字符串列表。

QStandardItemModel

以项数据(item data)为基础的标准数据结构模型类,通常与QTableView配合使用,实现通用的二维数据的管理

Qt view 类

View类的继承关系

可以参考 QAbstractItemView、QListView、QTableView、QTreeView

  • QListView:用于显示单列的列表数据,适用于一维数据的操作
  • QTreeView:用于显示树状结构数据,适用于树状结构数据的操作
  • QTableView:用于显示表格状数据,适用于二维表格型数据的操作
  • QColumnView:用多个QListView显示树状层次结构,树状结构的一层用一个QListView显示
  • QHeaderView:提供行表头或列表头的视图组件,如QTableView的行表头和列表头

MVC

Model、View、Controller,即模型、视图、控制器

MVC

MVC由三种对象组成。模型Model是应用程序对象,视图View是其屏幕表示,控制器Controller定义用户界面对用户输入的反应方式。在MVC之前,用户界面设计倾向于将这些对象组合在一起。MVC将它们解耦以增加灵活性和重用性。

MVC

数据模型基础

Model/View 机制

对于存储在本机上的数据,可以采用另外一种机制将其显示出来。

可以先把数据读取到一个能保存数据的类中,或者类不直接读取数据,但能提供读取数据的接口,然后用能显示数据的控件把数据从模型中读取并显示出来,显示数据的控件并不存储数据,显示的数据只是数据的一个映射。

像这种能保存数据或者能提供数据接口的类称为数据模型(model),

把数据模型中的数据显示出来的控件称为视图(view)控件。

要修改或增删视图控件中显示的数据,一种方法是在后台的数据模型中直接修改或增删数据,数据模型中的数据改变了,视图控件中显示的数据也会同时改变,视图控件不直接编辑数据,视图控件显示的数据只是对数据模型中数据的一种映射,是单向的;

另一种方法是调用可以编辑数据的控件,在编辑控件中修改数据,例如编辑文本数据时调用QLineEdit 控件,文本数据在QLineEdit 中修改,编辑整数和点数数据时可以调用QSpiBox 控件和QDoubleSpinBox 控件,修改完成后,通过信号通知数据模型和视图控件,数据模型中的数据和视图控件显示的数据也同时发生改变,像这种用于编辑数据的控件称为代理控件。

下面的程序先建立一个数据模型QStringListModel(),并添加数据然后建立两个QListView 视图控件,并设置相同的数据模型,双击任意一个视图控件中的文字,修改其值后,另一个视图控件同时发生变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/5 0:03
# File_name: 01-数据模型基础.py

import sys
from PySide6.QtWidgets import QApplication, QWidget, QListView, QHBoxLayout
from PySide6.QtCore import QStringListModel


class Mywindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUi()

def setupUi(self):
self.listMode1 = QStringListModel(self) # 数据模型
self.listMode1.setStringList(["语文", "数学", "物理", "化学"]) # 数据模型中添加数据

self.listView1 = QListView() # 视图控件
self.listView2 = QListView() # 视图控件

self.listView1.setModel(self.listMode1) # 为视图控件设置数据模型
self.listView2.setModel(self.listMode1) # 为视图控件设置数据模型

h = QHBoxLayout(self) # 水平布局
h.addWidget(self.listView1)
h.addWidget(self.listView2)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = Mywindow()

win.show()
sys.exit(app.exec())

数据模型的类型

根据用途不同,数据模型分为多种类型,它们的继承关系如图所示

数据模型的3种表现形式

QAbstractItemModel是所有数据模型的类,继承自QAbstractItemModel 的类有

  • StandardItemModel
  • QFileSystemModel
  • CHelpContentModel
  • QAbstractListModel
  • QAbstractTableMode
  • QAbstractProxyModel

其中 QAbstractListModel、QAbstractTableModel 和 QAbstractProxyModel有不同的派生类。

本章主要对 QStringListModel、QFileSystemModel 和 QStandardItemModel 进行讲解

数据模型存储数据的3种常见结构形式如图所示主要有

  • 列表模型(list model)列表模型中的数据没有层级关系,由一列多行数据构成;
  • 表格模型(table model)表格模型由多行多列数据构成;
  • 树结构模型(tree model)。树结构模型的数据是有层级关系的,每层数据下面还有子层数据。

不管数据的存储形式如何,每个数据都称为数据项(data item)数据项存储不同角色不同用途的数据,每个数据项都有一个索引(modelindex),通过数据索引可以获取数据项上存储的数据。

数据模型的3种表现形式

数据项的索引QModellndex

数据模型中存放着数据,要获取或写入数据,需要知道数据所在的行和列。行和列单独构成一个类称为数据项索引QModelIndex,通过数据项索引可以定位到对应的数据。

由于数据模型可能是一个列表、表格、树或更复杂的结构,所以数据模型的数据索引也会比较复杂。通常用QModelIndex()表示指向数据模型根部的索引这个索引不指向任何数据表示最高层索引。

用数据模型的 index(row,column,parent)表示索引parent(类型是QModelIndex)下的第 row 行第 column 列的数据项索引

  • 例如index_l=index(2,1,QModelIndex())表示根目录下的第 row=2行第 column=1列数据的索引
  • 如果在该数据项下还有子数据项,则index_2=index(1,3,index_1)表示在 index_1下的第row=1行第column=3列数据项的索引,其他情况类推

数据项索引的常用方法如表所示。

  • 用parent()方法可以获得父数据项的索引;
  • 用sibling(row,column)方法,siblingAtColumn(column)方法和 siblingAtRow(row)方法可以获取同级别的 row行 column 列的数据项的索引,
  • 用isValid()方法可以判断索引是否有效;
  • 用row()方法和 column)方法可以获取数据索引所指向的行值和列值;
  • 用flags()方法获取数据项的状态,返回值是 Qt.ItemFlag 的枚举值可能是:
    • Qt.NoltemFlags(没有任何属性)
    • Qt.ItemIsSelectable(可选择)
    • Qt.ItemIsEditable(可编辑)
    • Qt.ItemIsDragEnabled(可拖拽)
    • Qt.ItemIsDropEnabled(可拖放)
    • Qt.ItemIsUserCheckable(可选)
    • Qt.ItemIsEnabled(可激活)
    • Qt.ItemIsAutoTristate(由子项的状态决定)
    • Qt.ItemNeverHasChildren禁止有子项)
    • Qt.ItemIsUserTristate(用户可以在3种状态间切换)
QModellndex的方法及参数类型 返回值的类型 说明
model() QAhstractItemModel 获取数据模型
parent() QModelIndex 获取父索引
sibling(row:int,column:int) QModelIndex 获取同级别的索引
siblingAtColumn(column:int) QModelIndex 按列获取同级别的索引
siblingAtRow(row;int) QModelIndex 按行获取同级别的索引
row() int 获取索引所指向的行值
column() int 获取索引所指向的列值
data(role: int=Qt.ItemDataRole) Any 获取数据项指定角色的数据
flags() Qt.ItemFlag 获取标识
isValid() bool 获取索引是否有效

抽象模型OAbstractltemModel

抽象模型QAbstractItemModel的方法

抽象模型QAbstractItemModel提供数据模型与视图控件的数据接口不能直接使用该类需要用其子类定义数据模型。QAbstractItemModel的方法会被其子类继承,因此有必要介绍QAbstractItemModel提供的方法。

抽象模型QAbstractItemModel 的方法如表所示,主要方法介绍如下。

QAbstractItemModel的方法及参数类型 说 明
index(row: int, column: int, parent: QModelIndex) 获取父索引下的指定行和列的数据项索引
parent(QModelIndex) 获取父数据项的索引
sibling(row:int,column:int,QModelIndex) 获取同级别的指定行和列的数据索引
flags(QModelIndex) 获取指定数据项的标识Qt.temFlag
hasChildren(parent=QModelIndex()) 获取是否有子数据项
hasIndex(row: int, column; int, parent = QModelIndex()) 获取是否能创建数据项索引
insertColumn(column:int,parent=QModelIndex()) 插入列,成功则返回True
insertColumns(column: int,count;int,parent= QModelIndex()) 插人多列,成功则返回 True
insertRow(row:int,parent=QModelIndex()) 插入行,成功则返回True
inseriRows(row: int, count; int, parent = QModelIndex()) 插人多行,成功则返回True
setData(QModelIndex, Any,role =,Qt.ItemDataRole) 设置数据项的角色值,成功则返回True
data(QModellndex, role=Qt.ItemDataRole) 获取角色值
setltemData(QModelIndex, roles: Dict[int, Any]) 用字典设置数据项的角色值,成功则返回True
itemData(QModelIndex) 获取数据项的角色值 Dict[int,Any]
moveColumn(sourceParent: QModelIndex, sourceColumn: int,destinationParent: QModelIndex, destinationChild:int) 将目标数据项索引的指定列移动到目标数据项索引 的指定列处,成功则返回True
moveColumns(sourceParent: QModelIndex, sourceColumn: int,count:int,destinationParent: QModelIndex,destinationChild:int) 移动多列到目标索引的指定列处,成功则返回True
moveRow(QModelIndex,int,QModelIndex,int) 移动单行,成功则返回True
moveRows(QModelIndex,int, int,QModelIndex, int) 移动多行,成功则返回 True
removeColumn(column: int,parent: QModelIndex) 移除单列,成功则返回 True
removeColumns(column:int,count:int,parent: QModelIndex) : 移除多列,成功则返回True
removeRow(row:int,parent:QModelIndex) 移除单行,成功则返回True
removeRows(row:int, count: int, parent: QModelIndex) 移除多行,成功则返回True
rowCount(parent:QModelIndex) 获取行数
columnCount(parent: QModelIndex) 获取列数
setHeaderData(section: int, orientation: Qt.Orientation,value:Any,role:int=Qt.EditRole) 设置表头数据,成功则返回True
headerData(section: int, orientation: Qt.Orientation,role: int=Qt.DisplayRole) 获取表头数据
supportedDragActions() 获取支持的拖放动作Qt.DropActions
[slot]submit() 提交缓存信息到永久存储中
[slot]revert() 放弃提交缓存信息到永久存储中
sort(column:int,order:=Qt.AscendingOrder) 对指定列进行排序
  • 用index(row;int,column;int,parent;QModelIndex)方法可以获取某数据项的子项的索引

    • 用parent(QModelIndex)方法可以获取父项的索引
    • 用sibling(row:int;column;int,QModelIndex)方法可以获取同级别的数据项的索引。
  • 用setData(QModelIndex,Any,role=Qt.ItemDataRole)方法可以设置数据项的某角色值,

    • 用setItemData(QModelIndex;roles;Dict[int,Any])方法可以用字典方式设置某数据项的多个角色值,
  • 用data(QModelIndex,role= Qt.ItemDataRole)和itemData(QModelIndex)方法取角色值,其中参数 QtItemDataRole 的取值如表所示。

    Qt.ltemDataRole 的取值 对应的数据类型 说明
    Qt.DisplayRole 0 str 视图控件显示的文本
    QL.DecorationRole 1 QIcon、QPixmap 图标
    Qt.EditRole 2 str 视图控件中编辑时显示的文本
    Qt.ToolTipRole 3 sLr 提示信息
    Q1.StatusTipRole 4 str 状态提示信息
    Qt.WhatsThisRole 5 str 按下Shilt+F1键时显示的数据
    Qt.SizeHitRole 13 QSize 尺寸提示
    Qt.FontRole 6 QFont 默认代理控件的字体
    Qt.TextAlignmentRole 7 Qt.AlignmentFlag 默认代理控件的对齐方式
    Qt.BackgroundRole 8 QBrush、 QColor、 Qt.GlobalColor 默认代理控件的背景色
    Qt.ForegroundRole 9 默认代理控件的前景色
    Qt.CheckStateRole 10 Qt.CheckState 勾选状态
    Qt.InitialSortOrderRole 14 Qt.SortOrder 初始排序
    Qt.AccessibleTextRole 11 Str 用于可访问插件扩展的文本
    Qt.AccessibleDescriptionRole 12 Str 用于可访问功能的描述
    Qt.UserRole Ox0100 any(数据类型不限) 自定义角色,可使用多个自定义角色,第 1个为 Qt.UserRole,第 2 个为 Qt) UserRole+1,依次类推
  • 用setHeaderData(section: int, orientation: Qt.Orientation, value: Any,role; int一 Qt.EditRole)方法设置表头某角色的值

    • 当 orientation 取 Qt.Horizontal时,section是指列;
    • orientation 取Qt.Vertical时,section 是指行。
  • 用rowCount(parent;QModelIndex)方法可获取行的数量,

    • 用columnCount(parent;QModelIndex)方法可获取列的数量。
  • 可以用多个方法对列和行进行插入、移动和移除等操作。

抽象模型QAbstractItemModel的信号

抽象模型QAbstractItemModel 提供的信号也会被其子类继承,抽象模型QAbstractItemModel 的信号如表所示。

QAbstracttemModel的信号及参数类型 说 明
columnsAboutToBeInserted(parent: QModelIndex; first:int,last:int) 插入列之前发送信号,其中parent是目标的父 索引,first 和 last分别是目标的起始和终止列
columnsInserted(parent:QModelIndex,first: int,last: int) 插人列之后发送信号
columnsAboutToBeMoved(sourceParent:QModelIndex, sourceStart; int.sourceEnd; int, destinationParent: QModelIndex,destinationColumn;int) 移动列之前发送信号
columnsMoved(parent; QModelIndex, start; int,end; int,destination: QModelIndex,column;int) 移动列之后发送信号
columnsAboutToBeRemoved(parent; QModelIndex, first;int,last:int) 移除列之前发送信号
columnsRenoved(parent; QModelIndex,first; int, last: int) 11L 移除列之后发送信号
rowsAboutToBeInserted(parent;QModelIndex,first: int,last: int) 插人行之前发送信号
rowslnserted(parent;QModellndex, first: int,last; int) 捅入行之后发送信号
rowsAboutToBeMoved(sourceParent: QModelIndex, sourceStart: int,sourceEnd: int, destinationParent: QModelIndex,destinationRow:int) 移动行之前发送信号
rowsMoved(parent: QModelIndex,start: int,end: int,destination: QModelIndex,row:int) 移动行之后发送信号
rowsAboutToBeRemoved(parent: QModelIndex, first: int,last:int) 移除行之前发送信号·
rowsRemoved(parent:QModelIndex, first:int, last: int) 移除行之后发送信号
dataChanged(topLeft: QModelIndex, bottomRight: QModelIndex, roles: List[int]) 数据发生改变时发送信号
headerDataChanged(orientation:Qt.Orientation,first: int,last:int) 标题数据发生改变时发送信号
modelAboutToBeReset() 重置数据模型前发送信号
modelReset() 重置数据模型后发送信号

常用数据模型和视图控件

文本列表模型QStringListModel

文本列表模型QStringListModel通常用于存储一维文本列表它由一列多行文本数据构成。用于显示QStringListModel模型中文本数据的控件是QListView 控件。

用QStringListModel类创建文本列表模型实例的方法如下:

  • parent 是继承自QObject的实例对象;
  • strings 是字符串型列表或元组用于确定文本列表模型中显示角色和编辑角色的数据
1
2
3
4
from PySide6.QtCore import QStringListModel

QStringListModel(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QStringListModel(strings: Sequence[str], parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

文本列表模型QStringListModel的常用方法如表所示,主要方法介绍如下

  • 用setStringList(strings;Sequence[str])方法设置文本列表模型的显示角色和编辑角色的数据,

    • 用stringList()方法获取文本列表。
  • 用setData(QModelIndex,Any,role:int=Qt.EditRole)方法设置单个角色的值

  • 用setItemData(QModelIndex,Dict[int,Any])方法按照宇典形式设置角色值,关键字是角色,

  • 用data(QModelIndex,role;int= Qt.DisplayRole)方法和 itemData(QModelIndex)方法可获得数据,数据的角色可参考下表。

    Qt.ltemDataRole 的取值 对应的数据类型 说明
    Qt.DisplayRole 0 str 视图控件显示的文本
    Qt.DecorationRole 1 QIcon、QPixmap 图标
    Qt.EditRole 2 str 视图控件中编辑时显示的文本
    Qt.ToolTipRole 3 sLr 提示信息
    Qt.StatusTipRole 4 str 状态提示信息
    Qt.WhatsThisRole 5 str 按下Shilt+F1键时显示的数据
    Qt.SizeHitRole 13 QSize 尺寸提示
    Qt.FontRole 6 QFont 默认代理控件的字体
    Qt.TextAlignmentRole 7 Qt.AlignmentFlag 默认代理控件的对齐方式
    Qt.BackgroundRole 8 QBrush、 QColor、 Qt.GlobalColor 默认代理控件的背景色
    Qt.ForegroundRole 9 默认代理控件的前景色
    Qt.CheckStateRole 10 Qt.CheckState 勾选状态
    Qt.InitialSortOrderRole 14 Qt.SortOrder 初始排序
    Qt.AccessibleTextRole 11 Str 用于可访问插件扩展的文本
    Qt.AccessibleDescriptionRole 12 Str 用于可访问功能的描述
    Qt.UserRole Ox0100 any(数据类型不限) 自定义角色,可使用多个自定义角色,第 1个为 Qt.UserRole,第 2 个为 Qt) UserRole+1,依次类推
  • 用index(row;int,column=0,parent=QModelIndex())方法获得某行的模型数据索引

    • 用sibling(row;int,column:int,idx;QModelIndex)方法获得同级别的数据项的索引。
  • 用insertRows(row:int,count;int,parent=QModelIndex)方法可以插人多行

    • 用moveRows(sourceParent: QModelIndex, sourceRow: int, count: int,destinationParent:QModelIndex,destinationChild: int)方法可以移动多行到目标行,
    • 用removeRows(row:int,count:int,parent=QModelIndex)方法可以移除多行。
QStringListModel的方法及参数类型 说1 明
setStringList(strings:Sequence[str]) 设置列表模型显示和编辑角色的文本数据
stringList() 获取文本列表 List[str]
rowCount(parent=QModelIndex()) 获取行的数量
parent() 获取模型所在的父对象QObject
parent(child:QModelIndex) 获取父索引QModelIndex
index(row: int,column=0,parent:QModelIndex) 获取row行的模型数据索引
sibling(row: int,column: int.idx: QModelIndex) 获取同级别的模型数据索引
setData(QModelIndex,Any,role: int=Qt.EditRole) 按角色设置数据
data(QModelIndex,role:int=Qt.DisplayRole) 获取角色的值
setItemData(QModelIndex,Dict[int,Any]) 用字典设置角色值
itemData(QModelIndex) 获取字典角色值
flags(QModelIndex) 获取数据的标识 Qt.ItemFlag
insertRows(row: int, count: int, parent = QModelIndex) 插入多行,成功则返回True
moveRows(sourceParent:QModelIndex.sourceRow: int.count: int, destinationParent: QModelIndex, destinationChild:int) 移动多行,成功则返回True
removeRows(int,int,parent=QModelIndex()) 移除多行,成功则返回True
clearItemData(index: QModelIndex) 清空角色数据,成功则返回 True
sort(column:int.order=Qt.AscendingOrder) 对列进行排序

列表视图控件QListView

列表视图控件QListView 用于显示文本列表模型 QStringListModel 中的文本数据

用QListView创建列表视图控件的方法如下,其中 parent 是继承自QWidget 的窗口或容器控件。

1
2
3
from PySide6.QtWidgets import QListView

QListView(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
列表视图控件QListView 的常用方法

列表视图控件 QListView 用于显示数据模型中某数据项下的所有子数据项的显示角色的文本。

列表视图控件没有表头,可以把数据显示成一列,也可以显示成一行。列表视图控件不仅可以显示文本列表模型中的数据,也可显示其他模型中的数据。

列表视图控件的常用方法如表 所示,主要方法介绍如下。

QListView的方法及参数类型 说 明
setModel(QAbstractItemModel) 设置数据模型
setSelectionModel(QItemSelectionModel) 设置选择模型
selectionModel() 获取选择模型 QItemSelectionModel
setSelection(rect: QRect,command: QItemSelectionModel.SelectionFlags) 选择指定范围内的数据项
indexAt(QPoint) 获取指定位置处数据项的模型数据 索引
selectedIndexes() 获取选中的数据项的索引列表List Cint]
clearSelection() 取消选择
clearPropertyFlags() 清空属性标志
contentsSize() 获取包含的内容所占据的尺寸QSize
resizeContents(width:int,height: int) 重新设置尺寸
scrollTo(QModelIndex) 使数据项可见
setModelColumn(int) 设置数据模型中要显示的列
modelColumn() 获取模型中显示的列
setFlow(QListView.Flow) 设置显示的方向
setGridSize(QSize) 设置数据项的尺寸
setItemAlignment(Qt.Alignment) 设置对齐方式
setLayoutMode(QListView.LayoutMode) 设置数据的显示方式
setBatchSize(int) 设置批量显示的数量,默认为100
setMovement(QListView.Movement) 设置数据项的移动方式
setResizeMode(QListView.ResizeMode) 设置尺寸调整模式
setRootIndex(QModelIndex) 设置根目录的数据项索引
setRowHidden(int,bool) 设置是否隐藏
setSpacing(int) 设置数据项之间的间距
setUniformItemSizes(bool) 设置数据项是否统一尺寸
setViewMode(QListView.ViewMode) 设置显示模式
setWordWrap(bool) 设置单词是否可以写到两行上
setWrapping(bool) 设置文本是否可以写到两行
setAlternatingRowColors() 设置是否用交替颜色
setSelectionMode(QAbstractItemView.SelectionMode) 设置选择模式
setSelectionModel(QItemSelectionModel) 设置选择模型
selectionModel() 获取选择模型
setPositionForIndex(position:QPoint,index:QModelIndex) 将指定索引的项放到指定位置处
  • 用setModel(QAbstractItemModel)方法可以给列表视图控件设置关联的数据模型,

    • 用setRootIndex(QModelIndex)方法设置列表视图控件
    • 需要显示的数据索引下的子数据项如果数据项由多列构成则用setModelColumn(int)方法设置数据模型中要显示的列。
  • 用selectedIndexes()方法取选中的数据项的行索引 List[int];

    • 用setCurrentIndex(QModelIndex)方法设置当前的模型数据索引;
    • 用currentIndex()方法获取当前项的模型数据索引;用
    • indexAt(QPoint)方法获取指定位置处的数据项的模型数据索引。
  • 用setFlow(QListView.Flow)方法设置数据项的排列方向,其中 QListView.Flow可以取:

    • QListView,LeftToRight(值是0)
    • QListView.TopToBottom(值是1)。
  • 用setLayoutMode(QListView.LayoutMode)方法设置数据的显示方式,其中QListView.LayoutMode 可取:

    • QListView.SinglePass(值是0,全部显示)
    • QListView,Batched(值是1,分批显示);
    • 用setBatchSize(int)方法设置分批显示的个数。
  • 用setMovement(QListView.Movement)方法设置数据项的拖拽方式,其中QListView.Movement 可取:

    • QListView.Static(不能移动)
    • QListView.Free(可以自由移动)
    • QListView.Snap(捕捉到数据项的位置)。
  • 用setViewMode(QListView.ViewMode)方法设置显示模式,参数 QListViewViewMode

    • 如果取QListView.ListMode,则采用QListView.TopToBottom 排列小尺寸和QListView.Static不能移动方式;
    • 如果取 QListView.IconMode,则采用QListView.LeftToRight 排列、大尺寸和QListView.Free自由移动方式。
  • 用setResizeMode(QListView.ResizeMode)方法设置尺调整模式,参数可取QListView.Fixed或QListView.Adjust。

  • 用setSelectionMode(QAbstractItemView.SelectionMode)方法可以设置选择模式其中参数QAbstractItemView.SelectionMode 的取值如表所示

    QAbstractItemView.SelectionMode的取值 说 明
    QAbstractItemView.NoSelection 0 禁止选择
    QAbstractItemView.SingleSelection 1 单选,当选择一个数据项时,其他任何已经选中的数 据项都变成未选中项
    QAbstractItemView.MultiSelection 2 多选,当单击一个数据项时,将改变选中状态,其他还 未单击的数据项状态不变
    QAbstractItemView.ExtendedSelection 3 当单击某数据项时,清除已选择的数据项;当按住 Ctrl键选择时,会改变被单击数据项的选中状态;当 按住 Shift 键选择两个数据项时,这两个数据项之间 的数据项的选中状态发生改变
    QAbstractItemView.ContiguousSelection 4 当单击一个数据项时,清除已经选择的项;当按住 Shift 键或Ctrl键选择两个数据项时,这两个数据项 之间的选择状态发生改变
列表视图控件QListView的信号

列表视图控件QListView的信号如表所示

QListView的信号及参数类型 说明
activated(QModelIndex) 数据项活跃时发送信号
clicked(QModelIndex) 单击数据项时发送信号
doubleClicked(QModelIndex) 双击数据项时发送信号
entered(QModelIndex) 光标进入数据项时发送信号
iconSizeChanged(QSize) 图标尺寸发生变化时发送信号
indexesMoved(List[QModelIndex]) 数据索引发生移动时发送信号
pressed(QModelIndex) 按下鼠标按键时发送信号
viewportEntered() 光标进人视图时发送信号
文本列表模型OStringListModel和列表视图控件QListView 的应用实例

下面的程序建立两个QListView 控件,并分别关联两个 QStringListModel。

程序初始从Excel文件”学生 IDxlsx”中的ID工作页中读取学生名单,在学生名单中选择学生姓名后,单击”添加”按钮,数据会从学生名单中删除,并移到三好学生中;

单击”删除”按钮,数据会从三好学生中移到学生名单中,并插人到原来的位置。左侧选择1个或多个学生姓名,右侧只有 1个选中时,可以使用”插人”按钮。

程序运行界面如图所示

image-20230306012136571

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/6 0:22
# File_name: 02-文本列表模型OStringListModel和列表视图控件QListView 的应用实例.py


import sys, os
from PySide6.QtWidgets import QApplication, QWidget, QListView, QHBoxLayout, QLabel, QPushButton, QVBoxLayout
from PySide6.QtCore import QStringListModel, QModelIndex, Qt
from openpyxl import load_workbook


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.fileName = "./学生ID.xlsx"
self.reference_Model = QStringListModel(self) # 从 Excel中读数据存储数据的模型
self.selection_Model = QStringListModel(self) # 选择数据后,存储选择数据的模型

self.setup_Ui() # 建立界面
self.data_import() # 从Excel中读取数据
self.view_clicked() # 单击视图控件,判断按钮是否激活或失效

def setup_Ui(self):
label1 = QLabel("学生名单")
self.listView_1 = QListView() # 列表视图控件,显示Exce1 中的数据的控件
v1 = QVBoxLayout()
v1.addWidget(label1)
v1.addWidget(self.listView_1)

label2 = QLabel("三好学生")
self.listView_2 = QListView() # 列表视图控件,显示选中的数据
self.btn_add = QPushButton("添加")
self.btn_insert = QPushButton("插人")
self.btn_delete = QPushButton("删除")
h1 = QHBoxLayout()
h1.addWidget(self.btn_add)
h1.addWidget(self.btn_insert)
h1.addWidget(self.btn_delete)
v2 = QVBoxLayout()
v2.addWidget(label2)
v2.addWidget(self.listView_2)
v2.addLayout(h1)
h2 = QHBoxLayout(self)
h2.addLayout(v1)
h2.addLayout(v2)

self.listView_1.setModel(self.reference_Model) # 设置模型
self.listView_2.setModel(self.selection_Model) # 设置模型
self.listView_1.setSelectionMode(QListView.SelectionMode.ExtendedSelection) # 设置选择模式
self.listView_2.setSelectionMode(QListView.SelectionMode.ExtendedSelection) # 设置选择模式

self.btn_add.clicked.connect(self.btn_add_clicked)
self.btn_insert.clicked.connect(self.btn_insert_clicked)
self.btn_delete.clicked.connect(self.btn_delete_clicked)
self.listView_1.clicked.connect(self.view_clicked)
self.listView_2.clicked.connect(self.view_clicked)

def data_import(self):
if os.path.exists(self.fileName):
wbook = load_workbook(self.fileName)
if "ID" in wbook.sheetnames:
wsheet = wbook["ID"]
cell_range = wsheet[wsheet.dimensions] # 取 Excel中数据存储范围

student = list()
for cell_row in cell_range:
string = ""
for cell in cell_row: # cell_row.Excel行单元格元组
string = string + str(cell.value) + " " # 取Excel单元格中数据

student.append(string.strip())
self.reference_Model.setStringList(student) # 在模型中添加数据列表

def btn_add_clicked(self): # 添加按钮的槽函数
while len(self.listView_1.selectedIndexes()):
selectedIndexes = self.listView_1.selectedIndexes()
index = selectedIndexes[0]
string = self.reference_Model.data(index, Qt.DisplayRole) # 获取数据
self.reference_Model.removeRow(index.row(), QModelIndex())
count = self.selection_Model.rowCount() # 获取行的数量
self.selection_Model.insertRow(count) # 在末尾插人数据
last_index = self.selection_Model.index(count, 0, QModelIndex()) # 获取末尾索引
self.selection_Model.setData(last_index, string, Qt.DisplayRole) # 设置末尾的数据
self.view_clicked() # 控制按钮的激活与失效

def btn_insert_clicked(self):
while len(self.listView_1.selectedIndexes()):
selectedIndexs_1 = self.listView_1.selectedIndexes() # 获取选中数据项的索引
selectedIndex_2 = self.listView_2.selectedIndexes() # 获取选中数据项的索引

index = selectedIndexs_1[0]
string = self.reference_Model.data(index, Qt.DisplayRole)
self.reference_Model.removeRow(index.row(), QModelIndex())
row = selectedIndex_2[0].row()
self.selection_Model.insertRow(row)
index = self.selection_Model.index(row)
self.selection_Model.setData(index, string, Qt.DisplayRole)

self.view_clicked() # 控制按钮的激活与失效

def btn_delete_clicked(self): # 删除按钮的槽函数
while len(self.listView_2.selectedIndexes()):
selectedIndexes = self.listView_2.selectedIndexes()
index = selectedIndexes[0]
string = self.selection_Model.data(index, Qt.DisplayRole)
self.selection_Model.removeRow(index.row(), QModelIndex())
count = self.reference_Model.rowCount()
self.reference_Model.insertRow(count)
last_index = self.reference_Model.index(count, 0, QModelIndex()) # 获取末尾索引
self.reference_Model.setData(last_index, string, Qt.DisplayRole)

self.view_clicked()
self.reference_Model.sort(0) # 排序

def view_clicked(self):
n1 = len(self.listView_1.selectedIndexes()) # 获取选中数据项的数量
n2 = len(self.listView_2.selectedIndexes()) # 获取选中数据项的数量
self.btn_add.setEnabled(n1)
self.btn_insert.setEnabled(n1 and n2 == 1)
self.btn_delete.setEnabled(n2)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

文件系统模型QFileSystemModel

利用文件系统模型 QFileSystemModel 可以访问本机的文件系统,可以获得文件目录文件名称和文件大小等信息,可以新建目录删除目录和文件、移动目录和文件及重命名目录和文件。

用QFileSystemModel类定义文件系统模型的方法如下所示其中parent 是继承自QObject的实例。

1
2
3
from PySide6.QtWidgets import QFileSystemModel

QFileSystemModel(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
文件系统模型QFileSystemModel的常用方法

文件系统模型QFileSystemModel的常用方法如表所示,主要方法介绍如下

  • 用setRootPath(path:str)方法设置模型的根目录,并返回指向该目录的模型数据索引。
    • 改变根目录时,发送rootPathChanged(newPath)信号。
    • 用rootPath()方法获取根目录。
  • 用fileName(QModelIndex)方法获取文件名;
    • 用filePath(QModelIndex)方法获取文件名和路径;
    • 用fileInfo(QModelIndex)方法获取文件信息;
    • 用lastModified(QModelIndex)方法获取文件最后修改日期。
  • 用mkdir(QModelIndex,str)方法创建目录,并返回指向该目录的模型数据索引。
  • 用rmdir(QModelIndex)方法除目录成功则返回True否则返回 False,删除后不可恢复。
  • 用setOption(QFileSystemModelOptionon=True)方法设置文件系统模型的参数,其中QFileSystemModel Option 可取:
    • QFileSystemModel, DontWatchForChanges(不使用监控器)
    • QFileSystemModel, DontResolveSymlinks(不解析链接)
    • QFileSystemModel.DontUseCustomDirectoryIcons(不使用客户图标),
    • 默认都是关闭的用setNameFilters(filters; Sequence[str])方法设置名称过滤器;
  • 用setFilter(filters;QDir.Filter)方法设置路径过滤器,其中filters 可取:
    • QDir.DirsQDir.AllDirs
    • QDir.Files
    • QDir.Drives
    • QDir.NoSymLinks
    • QDir.NoDotAndDotDot
    • QDir.NoDot
    • QDir.NoDotDot
    • QDir.AllEntries
    • QDir, Readable
    • QDir.Writable
    • QDir.Executable
    • QDir.Modified
    • QDir.Hidden
    • QDir.System
    • QDir.CaseSensitive。
    • 设置路径过滤器时一定要包括QDir.AllDirs,否则无法识别路径的结构。
QFileSystemModel的方法及参数类型 返回值的类型 说明
setRootPath(path;str) QModelIndex 设置模型的根目录,并返回指向该目录的 模型数据索引
setData(QModelIndex,Any, role = Qt.EditRole) bool 设置角色数据,成功则返回True
data(index: QModelIndex, role: int=Qt.DisplayRole) Any 获取角色数据
setFilter(filters:QDir.Filter) None 设置路径过滤器
setNameFilters(filters:Sequence[str]) None 设置名称过滤器
nameFilters() List[str] 获取名称过滤器
setNameFilterDisables(enable:bool) None 设置名称过滤器是否激活
nameFilterDisables() bool 获取名称过滤器是否激活
setOption(QFileSystemModel.Option, on=True) None 设置文件系统模型的参数
setReadOnly(enable: bool) None 设置是否是只读的
isReadOnly() bool 获取是否有只读属性
fileIcon(QModelIndex) QIcon 获取文件的图标
fileInfo(QModelIndex) QFileInfo 获取文件信息
fileName(QModelIndex) str 获取文件名
filePath(QModelIndex) Str 获取路径和文件名
headerData(int, Qt.Orientation,role=Qt.DisplayRole) Any 获取表头数据
index(row: int,column: int, parent:QModelIndex) QModelIndex 获取索引
index(path:str,column:int=0) QModelIndex 获取索引
hasChildren(parent:QModelIndex) bool 获取是否有子目录或文件
isDir(QModelIndex) bool 获取是否是路径
lastModified(QModelIndex) QDateTime 获取最后修改时间
mkdir(QModelIndex,str) QModelIndex 创建目录,并返回指向该目录的模型数据 索引
myComputer(role=Qt.DisplayRole) Any 获取myComputer下的数据
parent(child: QModelIndex) QModelIndex 获取父模型数据索引
remove(QModelIndex) bool 删除文件或目录,成功则返回True
rmdir(QModelIndex) bool 删除目录,成功则返回True
rootDirectory() QDir 返回根目录QDir
rootPath() Str 返回根目录文本
rowCount(parent; QModelIndex) int 返回目录下的文件数量
sibling(row: int, column; int, idx: QModelIndex) QModelIndex 获取同级别的模型数据索引
type(index: QModelIndex) Str 返回路径或文件类型,例如”Directory” “JPEG file”
size(QModelIndex) int 获取文件的大小
columnCount(parent:QModelIndex) int 获取父索引下的列数
文件系统模型 QFileSystemModel的信号

文件系统模型 QFileSystemModel 的信号如表所示

QFileSystemModel的信号及参数类型 说 明
directoryLoaded(path:str) 当加载路径时发送信号
rootPathChanged(newPath:str) 根路径发生改变时发送信号
fileRenamed(path: str,oldName: str,newName: str) 更改文件名时发送信号

树视图控件QTreeView

树视图控件 QTreeView 以树列表的形式显示文件系统模型关联的本机文件系统,显示出本机的目录、文件名、文件大小等信息,也可以以层级结构形式显示其他类型的数据模型。

用QTreeView类创建树视图控件的方法如下,其中parent是继承自QWidget 的窗口或容器控件。

1
2
3
from PySide6.QtWidgets import QTreeView

QTreeView(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
树视图控件QTreeView的方法

树视图控件QTreeView 的常用方法如表所示,主要方法介绍如下

  • 用setModel(QAbstractItemModel)方法可以给树视图控件设置关联的数据模型
  • 用setRootIndex(QModelIndex)方法可以设置树视图控件根部指向的模型数据位置。
  • 用setItemsExpandable(bool)方法设置是否可以展开节点;
    • 用setExpanded(QModelIndex;bool)方法设置展开或折叠某节点;
    • 用expand(QModelIndex)方法展开某节点;用expandAll()方法展开所有节点;
    • 用collapse(QModelIndex)方法折叠某节点;
    • 用collapseAl1()方法折叠所有节点;
    • 用setExpandsOnDoubleClick(bool)方法设置双击节点时是否展开节点。
      • 展开或折叠节点时,将会发送expanded(QModelIndex)信号或 collapsed(QModelIndex)信号。
    • 用setColumnHidden(column;int,hide:bool)方法可以设置隐藏或显示某列,
      • 用showColumn(column;int)方法和hideColumn(column:int)方法可以显示和隐藏指定的列。
      • 用setColumnWidth(int,int)方法设置列的宽度,用setUniformRowHeights(bool)方法设置行是否有统一的高度。”
QTreeView的方法及参数类型 说 明
setModel(QAbstractItemModel) 设置数据模型
setSelectionModel(QItemSelectionModel) 设置选择模型
selectionModel() 获取选择模型 QItemSelectionModel
ctSelection(reet: QRect,command: QItemSelectionModel.SelectionFlags) 选择指定范图内的数据项
setRootIndex(QModellndex) 设置根部的索引
setRootIsDecorated(bool) 设置根部是否有折叠或展开标识
rootlsDecorated() 获取根部是否有折叠或展开标识
[slot]collapse(QModellndex) 折叠节点
[slot]collapseAII() 折叠所有节点
[slot]expand(QModellndex) 展开节点
isExpanded(QModelIndex) 获取节点是否已经展开
[slot]expandAII() 股开所有节点
[slot]expandRecursively(QModelIndex,depth=-1) 逐级展开,腰开探度是 depth。一1表示展开所有节点,0表示只展开本层
[slot]expandToDepth(depth:int) 展开到指定的深度
[slot]hideColumn(column:int) 隐藏列
[slot]showColumn(column:int) 显示列
indexAbove(QModelIndex) 获取某索引之前的索引
indexAt(QPoint) 获取某个点处的索引
indexBelow(QModelIndex) 获取某索引之后的索引
selectAII() 全部选择
selectedIndexes() 获取选中的项的行列表 List[int]
setAnimated(bool) 设置展开或折叠时是否比较连贯
isAnimated() 获取展开或折叠时是否比较连贯
setColumnHidden(column:int,hide: bool) 设置是否隐藏列
isColumnHidden(column:int) 获取列是否隐藏
setRowHidden(row: int, parent: QModelIndex, hide:bool) 设置相对于QModelIndex的第int行是否隐藏
isRowHidden(row: int,parent: QModelIndex) 获取行是否隐藏
setColumnWidth(column: int,width: int) 设置列的宽度
columnWidth(column:int) 获取列的宽度
rowHeight(index: QModelIndex) 获取行的高度
setItemsExpandable(enable:bool) 设置是否可以展开节点
itemsExpandable() 获取节点是否可以展开
setExpanded(QModelIndex,bool) 设置是否展开某节点
setExpandsOnDoubleClick(bool) 设置双击时是否展开节点
setFirstColumnSpanned(row: int, parent: QModelIndex,span:bool) 设置某行的第1列的内容是否占据所有列
isFirstColumnSpanned(int,QModelIndex) 获取某行的第1列的内容是否占据所有列
setHeader(QHeaderView) 设置表头
header() 获取表头
setHeaderHidden(bool) 设置是否隐藏表头
setIndentation(int) 设置缩进量
indentation() 获取缩进量
resetIndentation() 重置缩进量
setAutoExpandDelay(delay:int) 拖放操作中设置项打开的延迟时间(毫秒)
autoExpandDelay() 获取项打开的延迟时间,如为负则不能打开
setAllColumnsShowFocus(enable:bool) 设置所有列是否显示键盘焦点,否则只有一列显示 焦点
allColumnsShowFocus() 获取所有列是否显示键盘焦点
setItemsExpandable(bool) 设置是否可以展开节点
setUniformRowHeights(uniform:bool) 设置项是否有相同的高度
uniformRowHeights() 获取项是否有相同的高度
setWordWrap(on:bool) 设置一个单词是否可以写到两行上
serTextElideMode(mode:Qt.TextElideMode) 设置省略号”…”的位置,参数可取Qt.ElideLelt、Qt.ElideRight、Qt.ElideMiddle 或 Qt.ElideNone
setTreePosition(logicalIndex:int) 设置树的位置
treePosition() 获取树的位置
setSortingEnabled(bool) 设置是否可以进行排序
isSortingEnabled() 获取是否可以排序
[slot]sortByColumn(int,Qt.SortOrder) 按列进行排序
[slotJresizeColumnToContents(column:int) 根据内容调整列的尺寸
scrollContentsBy(dx:int,dy:int) 将内容移动指定的距离
setUniformRowHeights(bool) 设置行是否有统一高度
树视图控件QTreeView的信号

树视图控件QTreeView的信号如表所示

QTreeView的信号及参数类型 说明
collapsed(QModelIndex) 折叠节点时发送信号
expanded(QModelIndex) 展开节点时发送信号
activated(QModelIndex) 数据项活跃时发送信号
clicked(QModelIndex) 单击数据项时发送信号
doubleClicked(QModelIndex) 双击数据项时发送信号
entered(QModelIndex) 光标进入数据项时发送信号
iconSizeChanged(QSize) 图标尺寸发生变化时发送信号
pressed(QModelIndex) 按下鼠标按键时发送信号
viewportEntered() 光标进入树视图时发送信号

标准数据模型QStandardltemModel

标准数据模型QStandardItemModel可以存储多行多列的数据

  • 表格数据表格中的每个数据称为数据项QStandardItem
  • 每个数据项下面还可以存储多行多列的子数据表格并形成层级关系,这样会形成比较复杂的结构关系。数据项可以存储文本、图标勾选状态等信息。

用QStandardItemModel创建标准数据模型的方法如下所示其中parent是QObject或继承自QObject的实例对象,rows 和columns 分别是行数和列数

用QStandardItem创建数据项的方法如下所示用QStandardItem(rows,columns)方法可以创建一个含有多行多列子数据项的数据项。

1
2
3
4
5
6
7
8
9
10
from PySide6.QtGui import QStandardItemModel, QStandardItem

QStandardItemModel(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QStandardItemModel(rows: int, columns: int, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

QStandardItem(self) -> None
QStandardItem(icon: Union[PySide6.QtGui.QIcon, PySide6.QtGui.QPixmap], text: str) -> None
QStandardItem(other: PySide6.QtGui.QStandardItem) -> None
QStandardItem(rows: int, columns: int = 1) -> None
QStandardItem(text: str) -> None
标准数据模型QStandardItemModel的常用方法

标准数据模型QStandardItemModel的常用方法如表所示,主要方法介绍如下标

  • 准数据模型最高层的列数和行数用setColumnCount(columns:int)和setRowCount(row;int)方法设置;
    • 用columnCount(parent;QModelIndex)方法和rowCount(parent:QModelIndex)方法可获得某层的列数和行数。
  • 用appendColumn(Sequence[QStandardItem])方法可以添加列;
    • 用appendRow(Sequence[QStandardItem])方法或appendRow(QStandardItem)方法可添加行
    • 用insertColumn(Sequence[QStandardItem])方法和insertRow(Sequence[QStandardItem])方法插人列行;
    • 用takeColumn(column:int)方法和 takeRow(row:int)方法移除列和行。
  • 用setItem(row;int,column;int,item;QStandardItem)方法或 setItem(row; int,item:QStandardItem)方法可以在数据模型中设置数据项,
    • 用item(row:int,column:int=0)方法可以获取数据项,
    • 用takeltem(row:int,column:int=0)方法可移除数据项,
    • 用clear()方法可清除所有的数据项。
  • 用setData(QModelIndex,Any,role =Qt EditRole)方法和setItemData(QModelIndex,Dict[int,Any])方法可以设置数据项的角色数据,
    • 用clearItemData(QModelIndex)方法可以清除数据项上的角色数据。
  • 获得数据项的索引
    • index(row:int,column:int,parent: QModelIndex)
    • indexFromItem(QStandardItem)
    • sibling(row:int,column:int,idx:QModelIndex)
  • 标准数据模型有行表头和列表头
    • 用setHorizontalHeaderItem(column:int,item:QStandardItem)方法和 setVerticalHeaderItem(row;int,item: QStandardItem)方法设置水平表头和竖直表头的数据项;
    • 用takeHorizontalHeaderItem(column;int)方法和takeVerticalHeaderItem(row;int)方法移除表头的数据项,并返回被移除的表头数据项。
QStandardItemModel的方法及参数类型 返回值的类型 说明
removeRows(row:int,count:int, parent: QModelIndex) bool 移除多行
setltem(row: int, column: int, item: QStandardItem) None 根据行和列设置项
setltem(row: int, item: QStandardItem) None 根据行设置数据项
item(row: int,column: int=0) QStandardItem 根据行和列获取项
takeltem(row: int,column: int=0) QStandardItem 移除数据项
setData(QModelIndex,Any,role = Qt.EditRole) bool 设置角色值
data(QModellndex, role=Qt.DisplayRole) Any 获取角色值
setItemData(QModelIndex,Dict[int,Any]) bool 用字典设置项的值
itemData(QModelIndex) Dict[int,Any] 获取多个项的值
setHeaderData(int, Qt.Orientation, Any, role= Qt.EditRole) bool 设置表头值
headerData(int, Qt.Orientation, role=Qt.DisplayRole) Any 获取表头的值
setHorizontalHeaderltem(column: int, QStandardItem) None 设置水平表头的项
setHorizontalHeaderLabels(labels: Sequence[str]) None 设置水平表头的文本内容
horizontalHeaderItem(column:int) QStandardItem 获取水平表头的项
setVerticalHeaderItem(row: int, item: QStandardItem) None 设置竖直表头的项
setVerticalHeaderLabels(labels: Sequence[str]) None 设置竖直表头的文本内容
verticalHeaderItem(row: int) QStandardItem 获取竖直表头的项
takeHorizontalHeaderItem(coloumn:int) QStandardItem 移除水平表头的项
takeVerticalHeaderItem(row:int) QStandardItem 移除竖直表头的项
index(row: int, column: int, parent: QModelIndex) QModelIndex 根据行列获取数据项索引
indexFromItem(QStandardItem) QModelIndex 根据项获取索引
sibling(row: int, column: int, idx: QModelIndex) QModelIndex 获取同级别的索引
invisibleRootItem() QStandardItem 获取根目录的项
clear() None 清除所有的数据项
clearItemData(index: QModelIndex) bool 清除项中的数据
findItems(str,Qt.MatchFlag,column=0) List[QStandardItem] 获取满足匹配条件的数据项列表
flags(QModelIndex) Qt.ItemFlags 获取数据项的标识
hasChildren(parent:QModelIndex) bool 获取是否有子项
itemFromIndex(QModelIndex) QStandardItem 根据索引获取项
parent(child: QModelIndex) QModelIndex 获取父项的索引
setSortRole(role:int) None 设置排序角色
sortRole() int 获取排序角色
sort(column:int,order=Qt.AscendingOrder) None 根据角色值排序
数据项QStandardItem的常用方法

数据项QStandardItem的常用方法如表所示,主要方法介绍如下

  • 数据项可以设置文本、字体、图标、前景色、背景色勾选状态和提示信息等。
    • 用setText(str)方法设置数据项显示的文本;
    • 用setIcon(QIcon)方法设置图标;
    • 用setFont(QFont)方法设置数据项的字体;
    • 用setForeground(QColor)方法设置前景色;
    • 用setCheckable(bool)方法设置是否可以勾选,
    • 用setCheckState(Qt.CheckState)方法设置勾选状态
  • 数据项下面可以有多行多列子数据项
    • 行和列可以在创建数据项时用构造函数设置,
    • 也可用setRowCount(int)方法和 setColumnCount(int)方法设置;
    • 用rowCount()方法和columnCount()方法获取行和列的数量。
  • 可用多种方法添加插入和移除子数据项的行和列,
    • 用setChild(row:int,column;int,QStandardItem)方法和setChild(row:intQStandardItem)方法设置子数据项;
    • 用row()和column()方法获取数据项所在的行和列;
    • 用child(row:int,column;int=0)方法获取子数据项;
    • 用hasChildren()方法获取是否有子数据项;
    • 用takeChild(row:int;column:int-0)方法移除子数据项,并返回被移除的子数据项。
QStandardltem的方法及参数类型 返回值的类型 说 明
index() QModelIndex 获取数据项的索引
setColumnCount(int) None 设置列数
columnCount() Int 获取列数
setRowCount(int) None 设置行数
rowCount() int 获取行数
setChild(row: int.column:int, QStandardltem) None 根据行和列设置子数据项
setChild(row:int,QStandardItem) None 根据行设置子数据项
hasChildren() bool 获取是否有子数据项
child(row: int,column: int=0) QStandardItem 根据行和列获取子数据项
takeChild(row: int,column:int=0) QStandardltem 移除并返回子数据项
row()、column() int 获取数据项所在的行和列
appendColumn(Sequence[QStandardItern.]) None 添加列
appendRow(Sequence[QStandardItem]) None 添加行
appendRow(QStandardItem) None 添加行
appendRows(Sequence[QStandardItem]) None 添加多行
insertColumn(column:int,Sequence[QStandardItem]) None 插人列
insertColumns(column: int,count:int) None 插人多列
insertRow(row: int,Sequence[QStandardItem]) None 插人行
insertRow(row:int,QStandardItem) None 插人行
insertRows(row:int,count:int) None 插人多行
insertRows(row:int,Sequence[QStandardItem]) None 插人多行
removeColumn(column:int) None 移除列
removeColumns(column: int, count: int) None 移除多列
removeRow(row:int) None 移除行
removeRows(row:int,count:int) None- 移除多行
takeColumn(column:int) List[QStandardItem] 移除列,并返回被移除的数据项列表
takeRow(row:int) List[QStandardItem] 移除行,并返回被移除的数据项列表
model() QStandardItemModel 获取数据模型
parent() QStandardItem 获取父数据项
setAutoTristate(bool) None 设置自动有第3种状态
isAutoTristate() bool 获取自动有第3种状态
setTristate(bool) None 设置是否有弟3种状态
setForeground(brush: Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor,QGradient,QImage,QPixmap]) None 设置前景色
foreground() QBrush .获取前景画刷
setBackground(brush: Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor:QGradient,QImage,QPixmap]) None 设置背景色
background() QBrush 获取背景画刷
setCheckable(bool) None 设置是否可以勾选
setCheckState(Qt.CheckState) None 设置勾选状态
checkState() Qt.CheckState 获取勾选状态
isCheckable() bool 获取是否可以勾选
setData(value: Any,role: int=257) None 设置数据
data(role:int=257) Any 获取数据
clearData() None 清空数据
setDragEnabled(bool) None 设置是否可以拖拽
isDragEnabled() bool 获取是否可以拖拽
setDropEnabled(bool) None 设置是否可以拖放
isDropEnabled() bool 获取是否可以拖放
setEditable(bool) None 设置是否可以编辑
setEnabled(bool) None 设置是否激活
setFlags(Qt.ItemFlag) None 设置标识
isEditable() bool 获取是否可编辑
isEnabled() bool 获取是否激活
isSelectable() bool 获取是否可选择
isUserTristate() bool 获取是否有用户第3状态
setFont(QFont) None 设置字体
setIcon(QIcon) None 设置图标
setSelectable(bool) None 设置选中状态
setStatusTip(str) None 设置状态信息
setText(str) None 设置文本
text() str 欢取文本
setTextAlignment(Qt.Alignment) None 设置文本对齐方式
setToolTip(str) None 设置提示信息
setWhatsThis(str) None 设置按Shilt+F1键的提示信息
write(QDataStream) None 把项写人到数据流中
read(QDataStream) None 从数据流中读取项
sortChildren(column:int,order = Qt.AscendingOrder) None 对列进行排序

表格视图控件QTableView

表格视图控件QTableView 可以用多行多列的单元格来显示标准数据模型,也可显示其他类型的数据模型

用QTableView创建表格视图控件的方法如下所示,其中parent是继承自QWidget的窗口或容器控件。

1
2
3
from PySide6.QtWidgets import QTableView

QTableView(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
表格视图控件QTableView的常用方法

表格视图控件QTableView 以二维表格的形式显示数据模型中的数据,其常用方法如表所示,主要方法介绍如下。

  • 用setModel(QAbstractItemModel)方法设置表格视图控件的数据模型
  • 用setRootIndex(QModelIndex)方法设置根目录(不可见)的数据索引,
  • 用setSelectionModel(QItemSelectionModel)方法设置选择模型
  • 用setColumnWidth(int, int)方法和 setRowHeight(int, int)方法设置列的宽度和行的高度,
    • 用columnWidth(int)方法和 rowHeight(int)方法获取列的宽度和行的高度。
  • 表格视图控件有坐标系
    • 用columnAt(x;int)方法获取坐标位置处的列号
    • 用rowAt(y:int)方法获取y坐标位置处的行号,
    • 用columnViewportPasition(column;int)方法获取指定列的x坐标值,
    • 用rowViewportPosition(row;int)方法获取指定行的坐标值。
  • 行和列可以根据内容调整高度和宽度
    • 用resizeColumnToContents(column; int)方法和resizeColumnsToContents()方法自动调整列的宽度,
    • 用resizeRowToContents(row:int)方法和 resizeRowsToContents()方法自动调整行的高度。
  • 在表格的左上角有个按钮,单击该按钮可以选中所有数据,
    • 用setCornerButtonEnabled(bool)方法设置是否激活该按钮。
    • 用setShowGrid(bool)方法设置是否显示表格线条,
  • 用setGridStyle(Qt.PenStyle)方法可以设置表格线条的样式,其中参数 Qt PenStyle 可取:
    • Qt.NoPen(没有表格线条)
    • Qt.SolidLine,
    • Qt.DashLine、
    • Qt.DotLine,
    • Qt.DashDotLine,
    • Qt.DashDotDotLine
    • Qt.CustomDashLine(用setDashPattern()方法自定义)
QTableView的方法及参数类型 返回值的类型 说明
setModel(QAbstractItemModel) None 设置关联的数据模型
setRootIndex(QModelIndex) None 设置根目录的数据索引
setSelectionModel(QItemSelectionModel) None 设置选择模型
selectionModel() QItemSelectionModel 获取选择模型
setSelection(rect:QRect,command: QItemSelectionModel.SelectionFlags) None 选择指定范围内的数据项
columnAt(x:int) int 获取×坐标位置处的列号
rowAt(y: int) int 获取y坐标位置处的行号
columnViewportPosition(column:int) int 获取指定列的×坐标值
rowViewportPosition(row:int) int 获取指定行的y坐标值
indexAt(QPoint) QModelIndex 获取指定位置的数据索引
selectedIndexes() List[int] 获取选中的项的索引列表
resizeColumnToContents(column:int) None 自动调整指定列的宽度
resizeColumnsToContents() None 根据内容自动调整列的宽度
resizeRowToContents(row:int) None 自动调整指定行的高度
resizeRowsToContents() None 根据内容自动调整行的高度
scrollTo(QModelIndex) None 滚动表格使指定内容可见
selectColumn(column:int) None 选择列
selectRow(row:int) None 选择行
setColumnHidden(column:int,bool) None 设置是否隐藏列
hideColumn(column:int) None 隐藏列
setRowHidden(row:int,bool) None 设置是否隐藏行
hideRow(row:int) None 隐藏行
showColumn(column:int) None 显示列
showRow(row:int) None 显示行
isColumnHidden(column:int) bool 获取指定的列是否隐藏
isRowHidden(row:int) bool 获取指定的行是否隐藏
islndexHidden(QModelIndex) bool 获取索引对应的单元格是否隐藏
setShowGrid(bool) None 设置是否显示表格线条
showGrid() bo01 获取表格线条是否已显示
setGridStyle(Qt.PenStyle) None 设置表格线的样式
setColumnWidth(column:int,width:int) None 设置列的宽度
columnWidth(column:int) int 获取列的宽度
setRowHeight(row: int,height: int) None 设置行的高度
rowHeight(row:int) int 获取行的高度
setCornerButtonEnabled(bool) None 设置是否激活右下角按钮
isCornerButtonEnabled() bool 获取右下角按钮是否激活
setVerticalHeader(QHeaderView) None 设置竖直表头
verticalHeader() QHeaderView 获取竖直表头
setHorizontalHeader(QHeaderView) None 设置水平表头
horizontalHeader() QHeaderView 获取水平表头
setSpan(row:int,column: int, rowSpan: intcolumnSpan:int) None 设置单元格的行跨度和列跨度
columnSpan(row:int,column:int) int 获取单元格的列跨度
rowSpan(row:int,column:int) int 获取单元格的行跨度
clearSpans() None 清除跨度
setWordWrap(bool) None 设置字可以写到多行上
setSortingEnabled(bool) None 设置是否可以排序
isSortingEnabled() bool 获取是否可以排序
sortByColumn(int,Qt.SortOrder) None 按列进行排序
scrollContentsBy(dx: int,dy:int) None 把表格移动指定的距离
scrollTo(index: QModelIndex,hint = QAbstractItemView.EnsureVisible) None 使指定的项可见
setAlternatingRowColors(enable: bool) None 设置行的颜色交替变化
表格视图控件QTableView的信号

表格视图控件QTableView的信号如表所示

QTableView的信号及参数类型 说 明
activated(QModelIndex) 数据项活跃时发送信号
clicked(QModelIndex) 单击数据项时发送信号
doubleCIicked(QModelIndex) 双击数据项时发送信号
entered(QModelIndex) 光标进入数据项时发送信号
iconSizeChanged(QSize) 图标尺寸发生变化时发送信号
pressed(QModelIndex) 按下鼠标按时发送信号
viewportEntered() 光标进入视图控件时发送信号

选择模型和代理控件

选择模型 QltemSelectionMode

在列表、树和表格视图中,如要对数据项进行操作,需要先选中数据项,被选中的数据项高亮或反色显示。

在 PySide6 中被选中的数据项记录在选择模型 QItemSelectionModel中,如果多个视图控件同时关联到一个数据模型,选择模型可以记录多个视图控件中被选中的数据项,形成数据选择集 QItemSelection。视图控件有自已默认的选择模型,般可以满足用户的需要;另外可以单独创建新的选择模型,以实现特殊目的。

视图控件都有 setSelectionModel(QItemSelectionModel)方法和 selectionModel()方法,用于设置视图控件的选择模型和获取选择模型。

用selectionModel()方法获取某一个视图控件的选择模型后,可以使用setSelectionModel()方法提供给其他视图共享选择模型因此一般没有必要新建选择模型

用QItemSelectionModel 创建选择模型的方法如下

1
2
3
4
from PySide6.QtCore import QItemSelectionModel

QItemSelectionModel(model: PySide6.QtCore.QAbstractItemModel, parent: PySide6.QtCore.QObject) -> None
QItemSelectionModel(model: Union[PySide6.QtCore.QAbstractItemModel, NoneType]= None) -> None
选择模型 QItemSelectionModel 的常用方法
  • 用selection()方法可以获取项的选择集 QItemSelection;

  • 用select(index; QModelIndex,command:QItemSelectionModel,SelectionFlags)方法可以往选择集中添加内容,或从选择集中移除选择,其中command是QItemSelectionModel,SelectionFlags 的枚举值,可取的值如表示。

    QItemSelectionModel.SelectionFlags 的取值 说明
    QItemSelectionModel, NoUpdate 选择集没有变化
    QItemSelectionModel.Clear 清空选择集
    QItemSelectionModel, Select 选择所有指定的项
    QItemSelectionModel.Deselect 取消选择所有指定的项
    QItemSelectionModel.Toggle 根据项的状态选择或不选择
    QItemSelectionModel.Current 更新当前的选择
    QItemSelectionModel.Rows 选择整行
    QItemSelectionModel.Columns 选择整列
    QItemSelectionModel.SelectCurrent Select | Current
    QItemSelectionModel.ToggleCurrent Toggle | Current
    QItemSelectionModel.ClearAndSelect Clear | Select
QtemSelectionModel的方法及参数类型 返回值的类型 说明
[slot]clear() None 清空选择模型并发送selectionChanged() 和currentChanged()信号
[slot]reset() None 清空选择模型,不发送信号
[slot]clearCurrentIndex() None 清空当前的数据索引模型并发送 currentChanged()信号
[slot]clearSelection() None 清空选择模型并发送 selectionChanged() 信号
[slot]setCurrentIndex(index: QModelIndex,command: QItemSelectionModel.SelectionFlags) None 设置当前的项,并发送currentChanged() 信号
[slot]select(index: QModelIndex, command: QItemSelectionModel, SelectionFlags) None 选择项,并发送selectionChanged()信号
[slot]select(selection:QItemSelection, command:QItemSelectionModel.SelectionFlags) None 选择项,并发送selectionChanged()信号
rowIntersectsSelection(row: int,parent: QModelIndex) bool 如果选择的数据项与parent的子数据项的 指定行有交集,则返回True
columnIntersectsSelection(column:int, parent:QModelIndex) bool 如果选择的数据项与parent的子数据项的 指定列有交集,则返回True
currentIndex() QModelIndex 获取当前数据项的索引
hasSelection() b001 获取是否有选择项
isColumnSelected(column: int,parent: QModelIndex) bool 获取parent下的某列是否全部选中
isRowSelected(row:int,parent: QModelIndex) bool 获取parent下的某行是否全部选中
isSelected(index:QModelIndex) bool 获取某数据项是否选中
selectedRows(column:int=0) ListCint] 获取某行中被选中的数据项的索引列表
selectedColumns(row:int=0) ListCint] 获取某列中被选中的数据项的索引列表
selectedIndexes() ListCint] 获取被选中的数据项的索引列表
selection() QItemSelection 获取项的选择集
setModel(QAbstractItemModel) None 设置数据模型
选择模型QItemSelectionModel 的信号

选择模型QItemSelectionModel的信号如表所示

QItemSelectionModel的信号及参数类型 说明
curentChanged(current: QModelIndex, previous: QModellndex) 当前数据项发生改变时发送信号
currentColumnChanged(current: QModelIndex, previous: QModelIndex) 当前数据项的列改变时发送信号
currentRowChanged(current:QModelIndex, previous:QModelIndex) 当前数据项的行改变时发送信号
modelChanged(QAbstractItemModel) 数据模型发生改变时发送信号
selectionChanged(selected: QItemSelection, deselected: QItemSelection) 选择区域发生改变时发送信号
选择集QItemSelection

选择集QItemSelection是指数据模型中已经被选中的项的集合其方法如表所示。

QItemSelection的方法及参数类型 返回值的类型 说月 明
select(topLeft: QModelIndex, bottomRight: QModelIndex) None 添加从左上角到右下角位置处的 所有项
merge(other: QItemSelection, command: QItemSelectionModel.SelectionFlags) None 与其他选择集合并
indexes() List[QModelIndexJ 获取选择集中的数据索引列表
contains(index:QModelIndex) bool 获取指定的项是否在选择集中
clear() None 清空选择集
count() int 获取选择集中元素的个数

代理控件QStyledltemDelegate

在视图控件中双击某个数据项,可以修改数据项当前显示的值,即可以输入新的值。

  • 输人新值时,并不是直接在视图控件上输入(视图控件只具有显示数据的功能),而是在视图控件的单元格位置出现一个新的可以输入数据的控件,
  • 例如 QLieEdit。QLineEdit 读取数据项的值作为初始值,供用户修改,修改完成后通过数据项的索引把数据保存到数据模型中,并通知视图控件显示新的数据,像这种为视图控件提供编辑功能的控件称为代理控件或委托控件。

系统为每种数据类型定义了默认的代理控件,用户也可以自定义代理控件。

  • 例如某个数据项存储性别值该数据项只有”男”和”女”两个选择可以用QComboBox作为代理控件双击该数据项,弹出QComboBox 控件,从QComboBox 的列表中选择”男”或”女”;

  • 再如对于存储成绩的数据项,用QDoubleSpinBox作为代理控件,设置其可以输人1位小数定义代理控件需要用QStyledItemDelegate类或 QItemDelegate类创建子类,这两个类都继承自QAbstractItemDelegate类。

  • 这两个类的主要区别是前者可以使用当前的样式表来设置代理控件的样式因此建议使用前者来定义代理控件。

  • 在QStyledItemDelegate或QItemDelegate 的子类中定义代理控件的类型位置,以及如何读取和返回数据。

  • 视图控件都有从 QAbstractItemView 继承而来的:

    • setItemDelegate(delegate: QAbstractltemDelegate)方法为所有的数据项设置代理控件
    • setItemDelegateForColumn(column; int,delegate: QAbstractItemDelegate) 方法为列数据项设置代理控件
    • setItemDelegateForRow(row;int,delegate:QAbstractItemDelegate)方法为行数据项设置代理控件
  • 创建代理控件可以用项编辑器工厂QItemEditorFactory定义默认的代理控件,也可以自定义代理控件的类型本书讲解自定义代理控件。自定义代理控件需要重写 QStyledItemDelegate 类或 QItemDelegate 类的下面4个函数:

    • createEditor(parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex)->QWidget函数用于创建代理控件的实例对象并返回该实例对象
    • setEditorData(editor:QWidget,index:QModelIndex)-> None 函数,用于读取视图控件的数据项的值到代理控件中。
    • setModelData(editor: QWidget, model: QAbstractItemModel, index:QModelIndex)->None函数,用于将编辑后的代理控件的值返回到数据模型中
    • updateEditorGeometry(editor: QWidget, option: QStyleOptionViewItem,index:QModelIndex)->None 函数,用于设置代理控件显示的位置。
    • createEditor)函数中的参数 parent 指代理控件所在的窗口,通常取视图控件所在的窗体;
    • 其他3个函数的editor 指 createEditor()返回的代理控件,用于传递数据;
    • QModelIndex是数据项的索引,系统会给实参传递索引;
    • QStyleOptionViewItem 传递的一些属性用于确定代理控件的位置和外观,其属性如表所示。其中枚举值QStyleOptionViewltem.Position 可取:
      • QStyleOptionViewItem.Left
      • QStyleOptionViewItem.Right
      • QStyleOptionViewltem.op
      • QStyleOptionViewItem.Bottom;
    • 枚举值 QStyleOptionViewItem.ViewItemFeatures 可取:
      • QStyleOptionViewltem None
      • QStyleOptionViewItem.WrapText
      • QStyleOptionViewltem.Alternate
      • QStyleOptionViewItem.HasCheckIndicator
      • OStyleOptionViewltem.HasDisplay
      • QStyleOptionViewItem.HasDecoration;
    • 枚举值 QStyleOptionViewItem.ViewItemPosition 可取:
      • QStyleOptionViewItem.Beginning
      • QStyleOptionViewItem.Middle
      • QStyleOptionViewItem.End
      • QStyleOptionViewItem.OnlyOne(行中只有一个项.两端对齐)。
QStyleOptionViewltem的属性 属性值的类型 说明
backgroundBrush QBrush 项的背景画刷
checkState Qt.CheckState 项的勾选状态
decorationAlignment Qt.Alignment 项的图标对齐位置
decorationPosition QStyleOptionViewItem.Position 项的图标位置
decorationSize QSize 项的图标尺寸
displayAlignment Qt.Alignment 项的文字对齐位置
features QStyleOptionViewItem.ViewItemFeatures 项所具有的特征
font QFont 项的字体
icon QIcon 项图标
index QModelIndex 项的模型索引
showDecorationSelected bool 项是否显示图标
text QString 项显示的文本
textElideMode Qt.TextElideMode 省略号的模式
viewItemPosition QStyleOptionViewltem.ViewItemPosition 项在行中的位置
direction Qt.LayoutDirection 布局方向
palette QPalette 调色板
Tect QRect 项的矩形区域
styleObject QObject 项的窗口类型
version int 版本

Layout布局

控件表单布局QFormLayout

表单布局QFormLayout 由左右两列和多行构成将控件放到左右两列中,通常左列放置QLabel 控件,右列放置 QLineEdit 控件QSpinBox 等输人控件,也可以让一个控件单独占据一行。表单布局支持嵌套。

表单布局QFormLayout 继承自QLayout,用QFormLayout类创建实例对象的方法如下所示,其中 parent 是窗口或容器类控件。

1
2
3
from PySide6.QtWidgets import QFormLayout

QFormLayout(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

表单布局QFormLayout 的常用方法

表单布局QFormLayout 的常用方法如表所示,主要方法介绍如下。

  • 用addRow()方法在底部添加行,用insertRow()方法在中间插人行。addRow()和insertRow()方法是重构型方法,有多种不同的参数。

    • 用addRow(label.QWidget,field;QWidget)和addRow(label:QWidget;field;QLayout)方法在左列放置第1个QWidget,在右列放置第2个QWidget或 QLayout;
    • 用addRow(labelText:str,field:QWidget) addRow(labelText:str,field;QLayout)方法在左列创建标题是 str的 QLabel 控件,在右列放置QWidget或QLayout,这时新建的 QLabel和QWidget 或 QLayouthis 已经是伙伴关系;
    • 用addRow(widget:QWidget)和 addRow(layout;QLayout)方法把控件和布局放置到一行上,占据左右两列的位置。
  • 水平和竖直方向的间距

    • 用setHorizontalSpacing(spacing:int) setVerticalSpacing(spacing:int)方法可以分别设置控件在水平和竖直方向的间距。
  • 对齐方式

    • 用setLabelAlignment(Qt.Alignment)方法可以设置左列控件的文字对齐方式
    • 用setFormAlignment(Qt.Alignment)方法可以设置表单布局内控件的水平和竖直方向的对齐方式,其中参数Qt.Qlignment 可以取:
      • 水平方向的对齐方式
        • Qt.Alignleft
        • Qt.AlignRight
        • Qt.AlignHCenter
        • Qt.AlignJustify
      • 竖直方向的对齐方式有
        • Qt.AlignTop
        • Qt.AlignBottom
        • Qt.AlignVCenter
        • Qt.AlignBaseline。
      • Qt.AlignCenter 方式是水平和竖直都在中心。
  • 左列控件和右列控件的换行策略

    • 用setRowWrapPolicy(QFormLayout,RowWrapPolicy)方法可以设置左列控件和右列控件的换行策略,参数QFormLayoutRowWrapPolicy :
      • 如果取QFormLayout.DontWrapRows,表示右列的输人控件(如QLieEdit、QSpinBox和QDoubleSpinBox)始终在左列标签控件的右边;
      • 如果取QFormLayout.WrapLongRows,表示如果左侧标签的标题文字很长标签所占据的空间会挤压右侧输人控件的空间,如果整行的空间不足以放置标签,则右侧的输入控件会放到下一行;
      • 如果取QFormLayout,WrapAllRows,表示左侧标签控件始终在右侧输入控件的上面。
  • 设置可伸缩控件的伸缩方式

    • 用setFieldGrowthPolicy(QFormLayout, FieldGrowthPolicy)方法可以设置可伸缩控件的伸缩方式,右列的输人控件通常可以随着窗体的改变而改变,宽度是可调节的。参数QFormLayout.FieldGrowthPolicy:
      • 如果取QFormLayout.FieldsStayAtSizeHint,表示控件的伸缩量不会超过有效的范围,控件尺寸由sizeHint()方法获取的值设置;
      • 如果取QFormLayout,ExpandingFieldsGrow,则对于设置了水平setSizePolicy()属性或最小伸缩量的控件使其扩充到可以使用的空间,其他没有设置setSizePolicy()属性的控件在有效的范围内变化;
      • 如果取QFormLayout.AllNonFixedFieldsGrow,则对于设置了 setSizePolicy()属性的控件,使其扩充到可以使用的空间。
    • 设置控件随窗口大小改变时尺寸的变化方式
      • 用setSizeConstraint(QLayout,SizeConstraint)方法可以设置控件随窗口大小改变时尺寸的变化方式,这是从 QLayout 继承过来的方法。枚举类型参数 QLayout.SizeConstraint:
        • 如果取 QLayout,SetDefaultConstraint,表示控件的最小尺寸根据setMinimunSize(QSize)方法或setMinimunSize(int,int)方法设定的值确定;
        • 如果取QLayout.SetNoConstraint;表示控件尺寸的变化量不受限制;
        • 如果取QLayout.SetMinimumSize;表示将控件的尺寸设置成由控件的setMinimumSize()方法设定的尺寸值;
        • 如果取 QLayoutSetFixedSize,表示将控件的尺寸设置成由控件的sizeHint()方法获取的尺寸值;
        • 如果取QLayout;SetMaximumSize,表示将控件的尺寸设置成由控件的 setMaximumSize()方法设定的尺寸值;
        • 如果取QLayout.SetMinAndMaxSize,表示控件的尺寸可以在最小值和最大值之间变化。
    QFormLayout的方法及参数类型 说 .明
    addRow(label: QWidget,field:QWidget) 末尾添加行,两个控件分别在左右
    addRow(label:QWidget,field: QLayout) 末尾添加行,控件在左,布局在右
    addRow(labelText: str,field:QWidget) 末尾添加行,左侧创建名称为str的标签,右侧是控件
    addRow(labelText: str,field:QLayout) 末尾添加行,左侧创建名称为str的标签,右侧是布局
    addRow(widget: QWidget) 末尾添加行,只有1个控件,控件占据左右两列
    addRow(layout: QLayout) 末尾添加行,只有:1个布局,布局占据左右两列
    insertRow(row:int,QWidget,QWidget) 在第row行插人,两个控件分别在左右
    insertRow(row:int,QWidget,QLayout) 在第row行插人,控件在左,布局在右
    insertRow(row:int,str,QWidget) 在第row行插人,左侧创建名称为 str的标签,右侧是控件
    insertRow(row:int,str,QLayout) 在第row行插人,左侧创建名称为str的标签,右侧是布局
    insertRow(row:int,QWidget) 在第row行插入,只有1个控件,控件占据左右两列
    insertRow(row:int,QLayout) 在第row行插入,只有1个布局,布局占据左右两列
    removeRow(row:int) 删除第row行及其控件 .
    removeRow(layout:QLayout) 删除布局
    removeRow(widget:QWidget) 删除控件
    setHorizontalSpacing(spacing:int) 设置水平方向的间距
    setVerticalSpacing(spacing: int) 设置竖直方向的间距
    setRowWrapPolicy(QFormLayout RowWrapPolicy) 设置左列控件和右列控件的换行策略
    rowCount() 返回表单布局中行的数量
    setLabelAlignment(Qt.Alignment) 设置左列的对齐方法
    setFormAlignment(Qt.Alignment) 设置控件在表单布局中的对齐方法
    setContentsMargins(int,int,int,int) setContentsMargins(QMargins) 设置布局内的控件与布局外边界的左、上、右、下的距离
    setFieldGrowthPolicy(QFormLayout FieldGrowthPolicy) 设置可伸缩控件的伸缩方式
    setSizcConstraint(QLayout.SizeConstraint) 设置控件随窗口大小改变时尺寸的变化方式

表单布局QFormLayout 的应用实例

下面的程序在窗口中用表单布局建立一些控件的布局,用于输人一些基本信息,程序运行界面如图所示。

image-20230226203810203

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from PySide6.QtWidgets import(QApplication, QWidget, QLineEdit, QSpinBox, QLabel, QTextBrowser, QFormLayout, QRadioButton, QHBoxLayout, QPushButton)
from PySide6.QtCore import Qt
import sys


class myWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QFormLayout")
self.resize(300, 200)
self.setupUi()

def setupUi(self):
formLayout = QFormLayout(self)

name = QLabel("姓名(&N):")
self.name_lineEdit = QLineEdit()
name.setBuddy(self.name_lineEdit)
formLayout.addRow(name, self.name_lineEdit) # 添加行

number = QLabel("学号(&B):")
self.number_lineEdit = QLineEdit()
number.setBuddy(self.number_lineEdit) # 定义伙伴关系
formLayout.addRow(number, self.number_lineEdit) # 添加行

self.age_spinBox = QSpinBox()
formLayout.addRow("年龄(&A);", self.age_spinBox) # 添加行
self.male_radioButton = QRadioButton("男(&M)")
self.male_radioButton.setChecked(True)
self.female_radioButton = QRadioButton("女(&F)")

h_layout = QHBoxLayout()
h_layout.addWidget(self.male_radioButton)
h_layout.addWidget(self.female_radioButton)
formLayout.addRow("性别: ", h_layout) # 添加行
self.append_btn = QPushButton("添加(&A)")
formLayout.addRow(self.append_btn) # 添加行
self.address_lineEdit = QLineEdit()
formLayout.insertRow(4, "地址(&D);", self.address_lineEdit) # 插人行

self.class_lineEdit = QLineEdit()
formLayout.insertRow(4, "班级(&C):", self.class_lineEdit) # 插人行
self.textBrowser = QTextBrowser()
formLayout.addRow(self.textBrowser) # 添加行,按钮单独占据一行
formLayout.setLabelAlignment(Qt.AlignRight) # 对齐方式

self.append_btn.clicked.connect(self.append_clicked) # 信号与槽函数的连接

def append_clicked(self):
sex = "男"
if self.female_radioButton.isChecked():
sex = "女"
template = "姓名:{} 学号:{} 年龄:{} 性别:{} 班级:{} 地址:{}"
self.textBrowser.append(template.format(self.name_lineEdit.text(),
self.number_lineEdit.text(),
self.age_spinBox.value(),
sex,
self.class_lineEdit.text(),
self.address_lineEdit.text()))


if __name__ == '__main__':
app = QApplication(sys.argv)
win = myWindow()

win.show()
sys.exit(app.exec())

盒子布局QBoxLayout

QBoxLayout 占用它获得的空间(来自其父布局或 parentWidget()),将其划分为一排框,并使每个托管小部件填充一个框。

qhboxlayout-with-5-child.png

如果QBoxLayout的方向是将框放置在一行中,大小合适。每个小部件(或其他盒子)将至少获得其最小尺寸,最多获得其最大尺寸。任何多余的空间都会根据拉伸系数进行共享(详细信息如下)。

qvboxlayout-with-5-children.png

如果QBoxLayout的方向是垂直,则框被放置在一列中,同样具有合适的尺寸。

创建QBoxLayout的最简单方法是使用其中一个便利类,例如QHBoxLayout(用于盒子)或QVBoxLayout。您也可以直接使用QBoxLayout构造函数,将其方向指定

建议使用QVBoxLayout和QBoxLayout,而不是QBoxLayout,因为它们的构造函数很方便。

构造

1
2
3
4
from PySide6.QtWidgets import QBoxLayout

QBoxLayout(Direction: PySide6.QtWidgets.QBoxLayout.Direction,
parent: Union[PySide6.QtWidgets.QWidget, NoneType] = None) -> None

使用direction和parent widget.dirparent构建一个新的QBoxLayout
布局直接设置为的顶级布局。一个小部件只能有一个顶层布局。由layout() parent返回

  • Direction:PySide6.QtWidgets.QBoxLayout.Direction

    此类型用于确定长方体布局的方向。

    方向 描述
    QBoxLayout.LeftToRight 从左到右水平。
    QBoxLayout.RightToLeft 从右向左水平。
    QBoxLayout.TopToBottom 从上到下垂直。
    QBoxLayout.BottomToTop 从下到上垂直。

方法

  • 添加布局或组件

    如果QBoxLayout不是顶级布局(即它没有管理小部件的所有区域和子级),则必须先将其添加到其父布局中,然后才能对其执行任何操作。

    • 添加布局的正常方法是调用parentLayout.addLayout(QBoxLayout)
    • 完成此操作后,您可以使用以下四个功能之一将方框添加到QBoxLayout:
      • addWidget()将一个小部件添加到QBoxLayout并设置小部件的拉伸因子。(拉伸因子沿着一排方框。)
      • addSpacing():创建一个空框;这是您用来创建漂亮而宽敞的对话框的功能之一。有关设置边距的方法,请参见下文。
      • addStretch():以创建一个空的、可拉伸的框。
      • addLayout():将包含另一个QLayout的框添加到行中,并设置该布局的拉伸因子。
  • 指定位置插入

    • 使用insertWidget()、insertSpacing()、insertStretch()或insertLayout()在布局中的指定位置插入框。
  • QBoxLayout还包括两种边距宽度:

    • setContentsMargins():设置小部件每一侧的外部边界的宽度。这是沿着QBoxLayout的四条边中的每一条保留空间的宽度。
    • setSpacing():设置相邻方框之间的宽度。(您可以使用addSpacing()在特定位置获得更多空间。)
    • 默认边距由样式提供。大多数Qt样式指定的默认边距对于子窗口小部件是9,对于窗口是11。
    • 间距默认与顶层布局的页边距相同,或与父布局相同。
  • 要从布局中删除小部件

    • 调用removeWidget()
    • 在小部件上调用hide()也可以有效地将小部件从布局中删除,直到调用show()为止。
方法 参数 描述
addLayout(layout[, stretch=0]) layout – PySide6.QtWidgets.QLayout
stretch – int
添加到框的末尾,使用序列拉伸因子。布局拉伸
addSpacerItem(spacerItem) spacerItem – PySide6.QtWidgets.QSpacerItem 添加到此方框布局的末尾。spacerItem
addSpacing(size) size – int 将大小为的不可拉伸空间(QSpacerItem)添加到此方框布局的末尾。QBoxLayout提供默认的边距和间距。此函数可添加额外的空间。size
addStretch([stretch=0]) stretch – int 将最小大小和拉伸因子为零的可拉伸空间(QSpacerItem)添加到此方框布局的末尾。stretch
addStrut(arg__1) arg__1 – int 将盒子的垂直尺寸(例如,如果盒子是的话,高度)限制在最小值。其他限制可能会增加限制。左到右尺寸
addWidget(arg__1[, stretch=0[, alignment=Qt.Alignment()]]) arg__1 – PySide6.QtWidgets.QWidget
stretch – int
alignment – Alignment
添加到此方框布局的末尾,拉伸因子为,对齐方式为。widgetstretchalignment
拉伸因子仅适用于QBoxLayout的方向,并且相对于该QBoxLayout中的其他框和小部件。拉伸系数越高的小工具和盒子越长。
如果拉伸因子为0,并且QBoxLayout中的任何其他控件的拉伸因子都不大于零,则空间将根据所涉及的每个小部件的QWidget:sizePolicy()进行分配。
路线由指定。默认对齐方式为0,这意味着小部件填充整个单元格。对齐
direction() RETURN TYPE Direction 返回长方体的方向。addWidget()和addSpacing()朝着这个方向工作;拉伸向这个方向伸展。
insertItem(index, arg__2) index – int
arg__2 – PySide6.QtWidgets.QLayoutItem
插入到此方框布局中的位置。如果为负,则将该项添加到末尾
insertLayout(index, layout[, stretch=0]) index – int

layout – PySide6.QtWidgets.QLayout

stretch – int
插入位置,带拉伸因子。如果为负数,则在末尾添加布局。layoutinedexstretchindex
布局成为长方体布局的子级。
insertSpacerItem(index, spacerItem) index – int

spacerItem – PySide6.QtWidgets.QSpacerItem
插入位置,最小尺寸和拉伸系数为零。如果为负数,则在末尾添加空格。spacerItemindexindex
insertSpacing(index, size) index – int

size – int
在位置插入不可拉伸的空格(QSpacerItem),大小为。如果为负数,则在末尾添加空格。indexsizeindex
方框布局具有默认的边距和间距。此功能增加了额外的空间。
insertStretch(index[, stretch=0]) index – int

stretch – int
在最小大小和拉伸因子为零的位置插入可拉伸空间(QSpacerItem)。如果为负数,则在末尾添加空格。indexstretchindex
insertWidget(index, widget[, stretch=0[, alignment=Qt.Alignment()]]) index – int

widget – PySide6.QtWidgets.QWidget

stretch – int

alignment – Alignment
插入位置,带拉伸因子和对齐方式。如果为负数,则在末尾添加小部件。idgetindexstretchalignmentindex
拉伸因子仅适用于QBoxLayout的方向,并且相对于该QBoxLayout中的其他框和小部件。拉伸系数越高的小工具和盒子越长。
如果拉伸因子为0,并且QBoxLayout中的任何其他控件的拉伸因子都不大于零,则空间将根据所涉及的每个小部件的QWidget:sizePolicy()进行分配。
路线由指定。默认对齐方式为0,这意味着小部件填充整个单元格。对齐
setDirection(arg__1) arg__1 – Direction 将此布局的方向设置为.direction
setStretch(index, stretch) index – int

stretch – int
设置位置处的拉伸因子。到.indexstretch
setStretchFactor(l, stretch) l – PySide6.QtWidgets.QLayout

stretch – int

RETURN TYPE bool
这是一个重载函数。
将布局的拉伸因子设置为,如果在此布局中找到,则返回(不包括子布局);否则返回.layoutstretchtrue.layoutfalse
setStretchFactor(w, stretch) w – PySide6.QtWidgets.QWidget

stretch – int

RETURN TYPE bool
将的拉伸因子设置为,如果在此布局(不包括子布局)中找到,则返回true;否则返回.widgetstretchwidgetfalse
stretch(index) PARAMETERS
index – int

RETURN TYPE
int
返回位置.index处的拉伸因子

水平布局QHBoxLayout和竖直布局QVBoxLayout

表单布局QFormLayout 可把多个控件分成两列多行

水平布局QHBoxLayout只能把多个控件水平排列成一行,竖直布局 QVBoxLayout 只能把多个控件竖直排列成一列。

构造方法

QHBoxLayout和QVBoxLayout 是从QBoxLayout.类继承而来的。

用QHBoxLayout类和QVBoxLayout类创建水平布局和竖直布局对象的方法如下所示其中parent是窗口或容器类控件。

1
2
3
4
5
6
7
8
from PySide6.QtWidgets import QHBoxLayout, QVBoxLayout

QHBoxLayout(self) -> None
QHBoxLayout(parent: PySide6.QtWidgets.QWidget) -> None


QVBoxLayout(self) -> None
QVBoxLayout(parent: PySide6.QtWidgets.QWidget) -> None

常用方法

水平布局QHBoxLayout 和竖直布局QVBoxLayout 使用从父类QBoxLayout 继承的方法,常用方法如表所示,主要方法介绍如下。

  • 添加控件和子布局
    • 用addWidget(QWidget,stretch:int =0, Qt.Alignment)方法和 addLayout(QLayout,stretch;int=0)方法可在末尾添加控件和子布局,其中参数 stretch 是布局内部各控件和子布局的相对伸缩系数,相对伸缩系数取整数,同时可以指定控件的对齐方式Qt.Alignment;
    • 用insertWidget(index:int,QWidget,stretch:int=0,Qt.Alignment)方法和insertLayout(index:int,QLayout,stretch:int=0)方法可以在指定的索引位置插人控件和子布局。
  • 插入占位符
    • 用addSpacing(size:int)方法和insertSpacing(index:int,size:int)方法可以在未尾添加或在某个位置插人固定长度的占位空间;
    • 用addStretch(stretch:int =0)方法或insertStretch(index:int,stretch:int=0)方法可以在末尾添加或在某个位置插入可以伸缩的占位空间;
  • 设置最小宽高
    • 用addStrut(int)方法可以设置水平布局在竖直方向的最小高度,也可设置竖直布局在水平方向的最小宽度。
  • 设置布局方向
    • 用setDirection(QBoxLayout.Direction)方法可以设置布局的方向.例如把水平布局改变成竖直布局,参数QBoxLayout,Direction 可以取:
      • QBoxLayout.LeftToRight(从左到右水平布局)
      • QBoxLayout.RightToLeft(从右到左水平布局)
      • QBoxLayout.TopToBottom(从上到下竖直布局)
      • QBoxLayout.BottomToTop(从下到上竖直布局)
QHBoxLayoui或QVBoxLayout的方法及参效类型 说 明
addWidger(Qwidget, stretch: int= 0, Qt.Alignment) 添加控件,可设置伸缩系数和对齐方式
addLayout(QLayout.stretch:int=0) 添加子布局,可设置伸缩系数
addSpacing(size:int) 添加固定长度的占位空间
addStretch(stretch:int=0) 添加可伸缩空间
addStrut(int) 指定垂向最小值
insertWidget(index: int, QWidget.stretch: int=0, Qt.Alignment) 根据索引插入控件,可设置伸缩系数和对齐方式
insertLayout(index: int,QLayout.stretch:int=0) 根据索引插人子布局,可设置伸缩系数
insertSpacing(index: int,size:int) 根据索引插入固定长度的占位空间
insertStretch(index:int,stretch:int=0) 根据索引插入可伸缩的空间
count() 获取控件、布局和占位空间的数量
maximumSize() 获取最大尺寸
minimumSize() 获取最小尺寸
setDirection(QBoxLayout.Direction) 设置布局的方向
setGeometry(QRect) 设置左上角位置和宽度、高度
setSpacing(spacing:int) 设置布局内部控件之间的间隙
spacing() 获取内部控件之间的间隙
setStretch(index: int,stretch; int) 根据索引设置控件或布局的伸缩系数
stretch(index: int) 获取第int 个控件的伸缩比例系数
setStretchFactor(QWidget,stretchi int) 给控件设置伸缩系数,成功则返回True
setStretchFactor(QLayout.stretch;int) 给布局设置伸缩系数、成功则返回True
setContentsMargins(int,int,int,int)
setContentsMargins(margins; QMargins)
设置布局内的控件与边框的页边距
setSizeConstraint(QLayout, SizeConstraint) 设置控件随窗口尺寸改变时的变化方式

QVBoxLayout、QHBoxLayout例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 23:03
# File_name: 01-QVBoxLayout、QHBoxLayout.py


import sys
from PySide6.QtWidgets import QWidget, QVBoxLayout, QBoxLayout, QLabel, QApplication


# 除名称、方向外,和父类QBoxLayout完全一致
# 甚至可以通过 setDirection() 方法把水平布局和垂直布局互换


class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QVBoxLayout")
self.resize(500, 500)
self.move(400, 250)
self.setup_ui()

def setup_ui(self):
v_layout = QVBoxLayout()
self.setLayout(v_layout)
v_layout.setDirection(QBoxLayout.BottomToTop)
# v_layout.setDirection(QBoxLayout.RightToLeft) # 甚至可以改变为水平布局

lb1 = QLabel("lb1")
lb1.setStyleSheet("background-color: cyan;")
lb2 = QLabel("lb2")
lb2.setStyleSheet("background-color: orange;")

v_layout.addWidget(lb1)
v_layout.addWidget(lb2)


if __name__ == "__main__":
app = QApplication(sys.argv)

window = Window()
window.show()

sys.exit(app.exec())

格栅布局QGridLayout

格栅布局QGridLayout(或称为网格布局)提供多行多列的布局位置,可以把控件或子布局放到这些布局节点上,也可以让一个控件或子布局占用多行多列的布局位置。

构造方法

QGridLayout继承自QLayout。用QGridLayout类创建实例对象的方法如下所示,其中parent 是窗口或容器类控件。

1
2
3
from PySide6.QtWidgets import QGridLayout

QGridLayout(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

格栅布局QGridLayout 的常用方法

格栅布局QGridLayout 的常用方法如表所示,主要方法介绍如下

  • 添加添加控件和子布局控件
    • 用addWidget(QWidget)方法可以在格栅布局第1列的末尾添加控件;
    • 用addWidget(QWidget,row,column[,Qt.Alignment])方法和 addLayout(QLayout,row,column[,Qt.Alignment])方法可以在指定行和指定列添加控件和子布局,同时可选是否指定控件的对齐方式;
    • 用addWidget(QWidget,row,column,rowspan,column_span[,Qt.Alignment])方法和addLayout(row,column,row_span,column_span[,Qt.Alignment])方法可以在指定行和指定列处添加控件和子布局控件和子布局可以跨多行多列。
  • 缩放系数
    • 用setRowStretch(row,stretch)方法和 setColumnStretch(column,stretch)方法可以设置行和列的相对缩放系数。
  • 行列间距
    • 用setHorizontalSpacing(int)和 setVerticalSpacing(int)方法可以分别设置行之间的距离和列之间的距离
    • 用setSpacing(int)方法可以同时设置行列之间的距离
QGridLayout 的方法及参数类型 说 明
addWidget(QWidget) 在第1列的末尾添加控件
addWidget(QWidget,row:int, column:int, Qt.Alignment) 在指定的行列位置添加控件
addWidget(QWidget, row:int, column: int, rowSpan: int,columnSpan:int,Qt.Alignment) 在指定的行列位置添加控件,控件可以设置成跨多 行多列
addLayout(QLayout, row:int, column:int,Qt.Alignment) 添加子布局
addLayout(QLayout, row:int,column:int, rowSpan:int,columnSpan:int,Qt.Alignment) 添加子布局
setRowStretch(row:int,stretch;int) 设置行的伸缩系数
setColumnStretch(column:int,stretch;int) 设置列的伸缩系数
setHorizontalSpacing(spacing:int) 设置控件的水平间距
setVerticalSpacing(spacing:int) 设置控件的竖直间距
setSpacing(spacing:int) 设置控件的水平和竖直间距
rowCount() 获取行数
columnCount() 获取列数
setRowMinimumHeight(row:int,minSize:int) 设置行最小高度
setColumnMinimumWidth(column:int,minSize: int) 设置列最小宽度
setGeomelry(QRect) 设置格栅布局的位置和尺寸
setContentsMargins(left:int,top:int,right: int, bottom:int)
setContentsMargins(margins: QMargins)
设置布局内的控件与边框的页边距
setSizeConstraint(QLayout.SizeConstraint) 设置控件随窗口尺寸改变时的变化方式
cellRect(row:int,column:int) 获取单元格的矩形区域 QRect

格栅布局QGridLayout例子

image-20230319185501408

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import sys
from PySide6.QtWidgets import QApplication, QWidget, QGridLayout, QPushButton, QSpacerItem, QSizePolicy, QHBoxLayout, QLineEdit, QPlainTextEdit


class GridLayoutDemo(QWidget):
def __init__(self, parent=None):
super(GridLayoutDemo, self).__init__(parent)
grid = QGridLayout()
self.setLayout(grid)

# 添加行列标识
for i in range(1, 8):
rowEdit = QLineEdit('row%d' %(i))
rowEdit.setReadOnly(True)
grid.addWidget(rowEdit, i, 0)
colEdit = QLineEdit('col%d' %(i))
colEdit.setReadOnly(True)
grid.addWidget(colEdit, 0, i)
col_rol_Edit = QLineEdit('rol0_col0')
col_rol_Edit.setReadOnly(True)
grid.addWidget(col_rol_Edit, 0, 0, 1, 1)

# 开始表演
spacer = QSpacerItem(100, 70, QSizePolicy.Maximum)
grid.addItem(spacer, 0, 0, 1, 1)
grid.addWidget(QPushButton('row1_col2_1_1'), 1, 2, 1, 1)
grid.addWidget(QPushButton('row1_col3_1_1'), 1, 3, 1, 1)
grid.addWidget(QPlainTextEdit('row2_col4_2_2'), 2, 4, 2, 2)
grid.addWidget(QPlainTextEdit('row3_col2_2_2'), 3, 2, 2, 2)
grid.addWidget(QPushButton('row5_col5_1_1'), 5, 5, 1, 1)
spacer2 = QSpacerItem(100, 100, QSizePolicy.Maximum)
grid.addItem(spacer2, 6, 5, 1, 2)
grid.addWidget(QPushButton('row7_col6_1_1'), 7, 6, 1, 1)

hlayout = QHBoxLayout()
hlayout.addWidget(QPushButton('button_h1'))
hlayout.addWidget(QPushButton('button_h2'))
grid.addLayout(hlayout, 7, 1, 1, 2)

grid.setColumnStretch(5, 1)
grid.setColumnStretch(2, 1)
grid.setColumnMinimumWidth(0, 80)

self.move(300, 150)
self.setWindowTitle('QGridLayout例子')


if __name__ == "__main__":
app = QApplication(sys.argv)
demo = GridLayoutDemo()
demo.show()
sys.exit(app.exec())

层次布局QStackedLayout

QStackedLayout 类提供了一堆小部件,其中一次只有一个小部件可见。

QStackedLayout可用于创建类似于QTabWidget提供的用户界面。还有一个建立在QStackedLayout之上的方便的QStackedWidget类。

QStackedLayout可以用许多子小部件(“页面”)填充。例如:

1
2
3
4
5
6
7
8
9
firstPageWidget = QWidget()
secondPageWidget = QWidget()
thirdPageWidget = QWidget()
stackedLayout = QStackedLayout()
stackedLayout.addWidget(firstPageWidget)
stackedLayout.addWidget(secondPageWidget)
stackedLayout.addWidget(thirdPageWidget)
mainLayout = QVBoxLayout() mainLayout.addLayout(stackedLayout)
setLayout(mainLayout)
1
2
3
4
5
from PySide6.QtWidgets import QStackedLayout

QStackedLayout(self) -> None
QStackedLayout(parent: PySide6.QtWidgets.QWidget) -> None
QStackedLayout(parentLayout: PySide6.QtWidgets.QLayout) -> None
  • parentLayout – PySide6.QtWidgets.QLayout
  • parent – PySide6.QtWidgets.QWidget

构造一个没有父级的 QStackedLayout。此QStackedLayout必须稍后安装在小部件上才能生效。

构造一个新的 QStackedLayout 并将其插入到给定的 parentLayout,使用给定的 parent,此布局将自行安装在控件上,parent管理其子项的几何图形。

方法

QStackedLayout没有为用户提供切换页面的内在方法。这通常是通过QComboBox或QListWidget来完成的,QListWidget存储QStackedLayout页面的标题。

  • 填充布局时,微件将添加到内部列表中。
    • indexOf() 函数返回该列表中小部件的索引。
    • 可以使用addWidget()函数将小部件添加到列表的末尾,也可以使用 insertWidget() 函数插入给定索引处。
    • removeWidget() 函数从布局中删除给定索引处的小部件。
    • 布局中包含的小部件数量可以使用count()函数获得。
  • widget() 函数返回给定索引位置的小部件。
  • 屏幕上显示的小部件的索引由currentIndex()给出,可以使用setCurrentIndex()进行更改。
    • 以类似的方式,可以使用currentWidget()函数检索当前显示的小部件,并使用setCurrentWidget()函数进行更改。
  • 每当布局中的当前小部件发生更改或从布局中删除小部件时,都会分别发出 currentChanged() 和 widgetRemoved() 信号。
方法 参数 描述
currentIndex() RETURN TYPE
int
此属性保存可见小部件的索引位置。
如果没有当前小部件,则当前索引为-1。
currentWidget() PySide6.QtWidgets.QWidget 返回当前小部件,或者如果此布局中没有小部件。无
insertWidget(index, w) index – int

w – PySide6.QtWidgets.QWidget

RETURN TYPE
int
在此QStackedLayout中的给定位置插入给定。如果超出范围,则附加小部件(在这种情况下,返回的是的实际索引)
如果在调用此函数之前,QStackedLayout为空,则给定的将成为当前的小部件.widget
在小于或等于当前索引的索引处插入新的小部件将增加当前索引,但保留当前小部件。
setStackingMode(stackingMode) stackingMode – StackingMode 此属性确定处理子窗口小部件可见性的方式。。
默认值为。将属性设置为允许您使用覆盖窗口小部件的布局,这些窗口小部件在其他窗口小部件(例如图形编辑器)上进行额外绘制。StackOneStackAll
stackingMode() RETURN TYPE
StackingMode
此属性确定处理子窗口小部件可见性的方式。。
默认值为。将属性设置为允许您使用覆盖窗口小部件的布局,这些窗口小部件在其他窗口小部件(例如图形编辑器)上进行额外绘制。StackOneStackAll
widget(arg__1) PARAMETERS
arg__1 – int

RETURN TYPE
PySide6.QtWidgets.QWidget
返回给定位置的小部件,或者如果给定位置没有小部件,则返回。index无
[Slots]setCurrentIndex(index) index – int 此属性保存可见小部件的索引位置。
如果没有当前小部件,则当前索引为-1。
[Slots]setCurrentWidget(w) w – PySide6.QtWidgets.QWidget 将当前小部件设置为指定的。新的当前小部件必须已包含在此堆叠布局中。小部件

PySide6.QtWidgets.QStackedLayout.StackingMode:

显示模式 描述
QStackedLayout.StackOne 只有当前小部件可见。这是默认设置。
QStackedLayout.StackAll 所有小部件都可见。当前小部件仅被提升。

实例

image-20230319194850330image-20230319194903138image-20230319194920553

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# -*- coding: utf-8 -*-


import sys
from PySide6.QtWidgets import *


class StackedLayoutDemo(QWidget):
def __init__(self, parent=None):
super(StackedLayoutDemo, self).__init__(parent)
self.setWindowTitle("QStackedLayout布局管理例子")
self.resize(400, 100)
layout = QVBoxLayout()
self.setLayout(layout)

# 添加页面导航
pageComboBox = QComboBox()
pageComboBox.addItem("Page 1")
pageComboBox.addItem("Page 2")
pageComboBox.addItem("Page 3")
layout.addWidget(pageComboBox)

# 添加QStackedLayout
stackedLayout = QStackedLayout()
layout.addLayout(stackedLayout)

# 添加页面1-3
pageWidget1 = QWidget()
layout1 = QHBoxLayout()
pageWidget1.setLayout(layout1)
stackedLayout.addWidget(pageWidget1)
pageWidget2 = QWidget()
layout2 = QVBoxLayout()
pageWidget2.setLayout(layout2)
stackedLayout.addWidget(pageWidget2)
pageWidget3 = QWidget()
layout3 = QFormLayout()
pageWidget3.setLayout(layout3)
stackedLayout.addWidget(pageWidget3)

# 设置页面1-3
for i in range(5):
layout1.addWidget(QPushButton('button%d' % i))
layout2.addWidget(QPushButton('button%d' % i))
layout3.addRow('row%d' % i, QPushButton('button%d' % i))

# 导航与页面链接
pageComboBox.activated.connect(stackedLayout.setCurrentIndex)

# 添加按钮切换导航页1-3
buttonLayout = QHBoxLayout()
layout.addLayout(buttonLayout)
button1 = QPushButton('页面1')
button2 = QPushButton('页面2')
button3 = QPushButton('页面3')
buttonLayout.addWidget(button1)
buttonLayout.addWidget(button2)
buttonLayout.addWidget(button3)
button1.clicked.connect(lambda: stackedLayout.setCurrentIndex(0))
button2.clicked.connect(lambda: stackedLayout.setCurrentWidget(pageWidget2))
button3.clicked.connect(lambda: stackedLayout.setCurrentIndex(2))

label = QLabel('显示信息')
layout.addWidget(label)
stackedLayout.currentChanged.connect(lambda x: label.setText('切换到页面%d' %(x + 1)))


if __name__ == "__main__":
app = QApplication(sys.argv)
form = StackedLayoutDemo()
form.show()
sys.exit(app.exec())

信号

信号 描述
[Signal]currentChanged(index) index – int
每当布局中的当前窗口小部件发生变化时,就会发出此信号。指定新的当前小部件的索引,如果没有新的小部件,则指定-1(例如,如果QStackedLayoutidex中没有小部件)
[Signal]widgetRemoved(index) index – int
每当小部件从布局中移除时,就会发出此信号。小部件的作为parameter.index传递

事件与事件的处理函数

事件(event)和前文所介绍的经常用的信号一样,也是实现可视化控件之间联动的重要方法。

事件是程序收到外界的输入,处于某种状态时自动发送的信号。

事件有固定的类型每种类型有自己的处理函数,用户只要重写这些函数,即可达到特定的目的。

通过事件可以用一个控件监测另外一个控件,并可过滤被监测控件发出的事件。

事件的类型与处理函数

事件的概念

可视化应用程序在接受外界输入设备的输入时,例如鼠标、键盘等的操作,会对输入设备输入的信息进行分类,根据分类的不同,用不同的函数进行处理,做出不同的反应。

外界对 PySide程序进行输人信息的过程称为事件,例如在窗口上单击鼠标、用鼠标拖动窗口在输人框中输人数据等,这些都是外界对程序的输人,都可以称为事件。

PySide 程序对外界的输人进行处理的过程称为事件处理,根据外界输入信息的不同,处理事件的函数也不同。

前面编制的可视化程序中,在主程序中都会创建一个 QApplication 的应用程序实例对象,然后调用实例对象的 exec()函数,这将使应用程序进入一个循环,不断监听外界输入的信息。当输人的信息满足某种分类时,将会产生一个事件对象 QEvent(),事件对象中记录了外界输人的信息,并将事件对象发送给处理该事件对象的函数进行处理。

事件与前面讲过的信号与槽相似,但是又有不同。信号是指控件或窗口本身满足一定条件时,发送一个带数据的信息或不带数据的信息,需要编程人员为这个信息单独写处理这个信息的槽函数,并将信号和槽函数关联,发送信号时,自动执行与之关联的槽函数。而事件是外界对程序的输人,将外界的输人进行分类后交给函数处理,处理事件的函数是固定的,只需要编程人员把处理事件的函数重写,来达到处理外界输入的目的,而不需要将事件与处理事件的函数进行连接,系统会自动调用能处理事件的函数,并把相关数据作为实参传递给处理事件的函数。

下面是一个处理鼠标单击事件的程序,在窗口的空白处单击鼠标左键,在 QLineEdit 控件上显示出鼠标单击点处的窗口坐标值,单击鼠标右键,显示右键单击处屏幕坐标值。

单击鼠标左键或右键将会产生QMouseEvent 事件,QMouseEvent事件的实例对象中有与鼠标事件相关的属性,如 button()方法获取单击的是左键还是右键,x()和 y()方法取鼠标单击点处窗口坐值,globalX()和 globalY()方法获取鼠标单击点处屏幕坐标值。

QWidget窗口处理 QMouseEvent 事件的函数有:

  • mouseDoubleClickEvent(QMouseEvent)
  • mouseMoveEvent(QMouseEvent)
  • mousePressEvent(QMouseEvent)
  • mouseReleaseEvent(QMouseEvent)
  • moveEvent(QMoveEvent)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 20:31
# File_name: 01-简单的鼠标点击事件.py
import PySide6.QtGui
from PySide6.QtWidgets import QApplication, QWidget, QLabel
from PySide6.QtCore import Qt
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(500, 500)
self.qlabel = QLabel(self)
self.qlabel.setGeometry(15, 5, 500, 30)
self.qlabel.setText("请点击")

def mousePressEvent(self, event: PySide6.QtGui.QMouseEvent) -> None: # 重写处理mousePress 事件的函数
super().mousePressEvent(event)

template1 = "单击点的窗口坐标是x:{} y:{}"
template2 = "单击点的屏幕坐标是x:{} y:{}"

if event.button() == Qt.LeftButton: # button()获取键或右键
string = template1.format(event.position().x(), event.position().y()) # x()和()获取窗口坐标
self.qlabel.setText(string)

if event.button() == Qt.RightButton: # globalX()和globalY()获取全局坐标
string = template2.format(event.globalPosition().x(), event.globalPosition().y())
self.qlabel.setText(string)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

QEvent类

QEvent类是所有事件的基类,它在 QtCore 模块中。

外界输人给序的信息首先交给QEvent 进行分类,得到不同类型的事件,然后系统将事件及相关信息交给控件或窗口的事件处理函数进行处理,得到对外界输人的响应QEvent 类的属性只有 accepted。

常用方法如表所示,主要方法介绍如下:

QEvent的方法及参数类型 返回值的类型 说明
accept() None 事件被接受
ignore() None 事件被拒绝
isAccepted() bool 事件是否被接受
setAccepted(accepted: bool) None 设置事件是否被接受
clone() QEvent 重写该函数,返回事件的复本
isPointerEvent() bool 是QPointerEvent 事件时返回True
isSinglePointEvent() bool 是 QSinglePointEvent事件时返回True
spontaneous() bool 获取事件是否立即被处理
type() QEvent.Type 获取事件的类型
[static]registerEventType(hint: int=—1) int 注册新的事件类型
  • 用accept()或 setAccepted(True)方法接受一个事件
  • 用ignore()或 setAccepted(False)方法拒绝一个事件。
  • 被接受的事件不会再传递给其他对象;被拒绝的事件会传递给其他对象处理,如果没有对象处理,则该事件会被丢弃。
  • 如果事件被QWidget的event()函数进行了处理则用spontaneous()方法的返回值是True,否则返回值是False。
  • event()函数根据事件类型起到分发事件到指定处理函数的作用,可以在event()函数中对事件进行处理
    • 用registerEventType(hint:int=-1)方法可以注册一个新事件类型其中hint的取值介于QEventUser(1000)和 QEvent.MaxUser(65535)之间,返回新事件的D号。

用type()方法可以返回事件的类型。QEvent中定义了事件的类型,QEent定义的主要事件类型如表所示:

事件类型常量(QEvent.Type) 所属事件类 说明
QEvent.None 0 - 不是一个事件
QEvent.ActivationChange 99 - 顶层窗口激活状态发生变化
QEvent.ApplicationFontChange 36 - 程序的默认字体发生变化
QEvent.ApplicationPaletteChange 38 - 程序的默认调色板发生变化
QEvent.ApplicationStateChange 214 - 应用程序的状态发生变化
QEvent.ApplicationWindowIconChange 35 - 应用程序的图标发生变化
QEvent.Clipboard 40 - 剪贴板的内容发生改变
QEvent.ContentsRectChange 178 - 控件内容区外边距发生改变
QEvent.CursorChange 183 - 控件的鼠标指针发生改变
QEvent.DynamicPropertyChange 170 - 动态属性已添加、更改或删除
QEvent.EnabledChange 98 - 控件的enabled状态已更改
QEvent.EnterEditFocus 150 - 编辑控件获得焦点进行编辑
QEvent.FontChange 97 - 控件的字体发生改变
QEvent.GrabKeyboard 188 - item获得键盘抓取(仅限QGraphicsItem)
QEvent.GrabMouse 186 - item获得鼠标抓取(仅限QGraphicsItem)
QEvent.KeyboardLayoutChange 169 - 键盘布局已更改
QEvent.LanguageChange 89 - 应用程序翻译发生改变
QEvent.LayoutDirectionChange 90 - 布局的方向发生改变
QEvent.LayoutRequest 76 - 控件的布局需要重做
QEvent.Leave 11 - 光标离开控件的边界
QEvent.LeaveWhatsThisMode 125 - 程序离开”What’sThis?”模式
QEvent.LLeaveEditFocus 151 - 编辑控件失去编辑的焦点
QEvent.LocaleChange 88 - 系统区域设置发生改变
QEvent.ModifiedChange 102 - 控件修改状态发生改变
QEvent.MouseTrackingChange 109 - 鼠标跟踪状态发生改变
QEvent.NonClientAreaMouseMove 173 - 光标移动发生在客户区域外
QEvent.PaletteChange 39 - 控件的调色板发生改变
QEvent.ParentAboutToChange 131 - 控件的parent将要更改
QEvent.ParentChange 21 - 控件的parent发生改变
QEvent.PlatformPanel 212 - 请求-个特定于平台的面板
QEvent.Polish 75 - 控件被抛光
QEvent.PolishRequest 74 - 控件应该被抛光
QEvent.ReadOnlyChange 106 - 控件的read-only状态发生改变
QEvent.ShowToParent 26 - 子控件被显示
QEvent.StyleChange 100 - 控件的样式发生改变
QEvent.ToolTipChange 184 - 控件的tooltip发生改变
QEvent.UngrabMouse 187 - Item失去鼠标抓取(QGraphicsItemQQuickItem)
QEvent.UpdateRequest 77 - 控件应该被重绘
QEvent.WhatsThisClicked 118 - “What’sThis”帮助链接被单击
QEvent.WindowActivate 24 - 窗口已激活
QEvent.WindowBlocked 103 - 窗口被模式对话框阻塞
QEvent.WindowDeactivate 25 - 窗户被停用
QEvent.WindowIconChange 34 - 窗口的图标发生改变
QEvent.WindowTitleChange 33 - 窗口的标题发生改变.
QEvent.ActionAdded 114 QActionEvent 一个新QAction被添加
QEvent.ActionChanged 113 QActionEvent 一个QAction被改变
QEvent.ActionRemoved 115 QActionEvent 一个QAction被移除
QEvent.ChildAdded 68 QChildEvent 一个对象获得孩子
QEvent.ChildPolished 69 QChildEvent 一个控件的孩子被抛光
QEvent.ChildRemoved 71 QChildEvent 一个对象失去孩子
QEvent.Close 19 QCloseEvent Widget被关闭
QEvent.ContextMenu 82 QContextMenuEvent 上下文弹出菜单
QEvent.DeferredDelete 52 QDeferredDeleteEvent 对象被清除后将被删除
QEvent.DragEnter 60 QDragEnterEvent 拖放操作时光标进入控件
QEvent.DragLeave 62 QDragLeaveEvent 拖放操作时光标离开控件
QEvent.DragMove 61 QDragMoveEvent 拖放操作正在进行
QEvent.Drop 63 QDropEvent 拖放操作完成
QEvent.Enter 10 QEnterEvent 光标进人控件的边界
QEvent.FileOpen 116 QFileOpenEvent 文件打开请求
QEvent.FocusIn 8 QFocusEvent 控件或窗口获得键盘焦点
QEvent.FocusOut 9 QFocusEvent 控件或窗口失去键盘焦点
QEvent.FocusAboutToChange 23 QFocusEvent 控件或窗口焦点即将改变
QEvent.Gesture 198 QGestureEvent 触发了-个手势
QEvent.GestureOverride 202 QGestureEvent 触发了手势覆盖
QEvent.UngrabKeyboard 189 QGraphicsItem Item失去键盘抓取
QEvent.GraphicsSceneContextMenu 159 QGraphicsSceneConte-xtMenuEvent 在图形场景上弹出右键菜单
QEvent.GraphicsSceneDragLeave 166 QGraphicsSceneDrag-DropEvent 拖放操作时光标离开场景
QEvent.GraphicsSceneDragMove 165 QGraphicsSceneDrag-DropEvent 在场景上正在进行拖放操作
QEvent.GraphicsSceneDrop 167 QGraphicsSceneDrag-DropEvent 在场景上完成拖放操作
QEvent.GraphicsSceneDragEnter 164 QGraphicsScene-DragDropEvent 拖放操作时光标进入场景
QEvent.GraphicsSceneHoverEnter 160 QGraphicsSceneHoverEvent 光标进入图形场景中的悬停项
QEvent.GraphicsSceneHoverLeave 162 QGraphicsSceneHover-Event 光标离开图形场景-个悬停项
QEvent.GraphicsSceneHoverMove 161 QGraphicsSceneHover-Event 光标在场景的悬停项内移动
QEvent.GraphicsSceneMouseDoubleClick 158 QGraphicsSceneMouseEvent 光标在图形场景中双击
QEvent.GraphicsSceneMouseMove 155 QGraphicsSceneMouseEvent 光标在图形场景中移动
QEvent.GraphicsSceneMousePress 156 QGraphicsSceneMouse-Event 光标在图形场景中按下
QEventGraphicsSceneMouseRelease 157 QGraphicsSceneMouse-Event 光标在图形场景中释放
QEvent.GraphicsSceneMove 182 QGraphicsSceneMove-Event 控件被移动
QEvent.GraphicsSceneResize 181 QGraphicsSceneResize-Event 控件已调整大小
QEvent.GraphicsSceneWheel 168 QGraphicsSceneWheel-Event 鼠标滚轮在图形场景中滚动
QEvent.GraphicsSceneHelp 163 QHelpEvent 用户请求图形场景的帮助
QEvent.ToolTip 110 QHelpEvent #NAME?
QEvent.WhatsThis 111 QHelpEvent 控件显示”What’sThis”帮助
QEvent.Hide 18 QHideEvent 控件被隐藏
QEvent.HideToParent 27 QHideEvent 子控件被隐藏
QEvent.HoverEnter 127 QHoverEvent 光标进入悬停控件
QEvent.HoverLeave 128 QHoverEvent 光标离开悬停控件
QEvent.HoverMove 129 QHoverEvent 光标在悬停控件内移动
QEvent.IconDrag 96 QIconDragEvent 窗口的主图标被拖走
QEvent.InputMethod 83 QInputMethodEvent 正在使用输人法
QEvent.InputMethodQuery 207 QInputMethodQuery-Event 输人法查询事件
QEvent.KeyPress 6 QKeyEvent 键盘按下
QEvent.KeyRelease 7 QKeyEvent 键盘释放
QEvent.ShortcutOverride 51 QKeyEvent 按下按键.用于覆盖快捷键
QEvent.MouseButtonDblClick 4 QMouseEvent 鼠标再次按下
QEvent.MouseButtonPress 2 QMouseEvent 鼠标按下
QEvent.MouseButtonRelease 3 QMouseEvent 鼠标释放
QEvent.MouseMove 5 QMouseEvent 鼠标移动
QEvent.Move 13 QMoveEvent 控件的位置发生改变
QEvent.NativeGesture 197 QNativeGestureEvent 系统检测到手势
QEvent.Paint 12 QPaintEvent 需要屏幕更新
QEvent.Resize 14 QResizeEvent 控件的大小发生改变
QEvent.Scroll 205 QScrollEvent 对象需要滚动到提供的位置
QEvent.ScrollPrepare 204 QScrollPrepareEvent 对象需要填充它的几何信息
QEvent.Shortcut 117 QShortcutEvent 快捷键处理
QEvent.Show 17 QShowEvent 控件显示在屏幕上
QEvent.StatusTip 112 QStatusTipEvent 状态提示请求
QEvent.TabletMove 87 QTabletEvent Wacom写字板移动
QEvent.TabletPress 92 QTabletEvent Wacom写字板按下
QEvent.TabletRelease 93 QTabletEvent Wacom写字板释放
QEvent.Timer 1 QTimerEvent 定时器事件
QEvent.TouchBegin 194 QTouchEvent 触摸屏或轨迹板序列的开始
QEvent.TouchCancel 209 QTouchEvent 取消触摸事件序列
QEvent.TouchEnd 196 QTouchEvent 触摸事件序列结束
QEvent.TouchUpdate 195 QTouchEvent 触摸屏事件
QEvent.Wheel 31 QWheelEvent 鼠标滚轮滚动
QEvent.WindowStateChange 105 QWindowStateChangeEvent 窗口的状态(最小化、最大化或全屏)发生改变

event()函数

当GUI应用程序捕捉到事件发生后,会首先将其发送到 QWidget 或子类的event(QEvent)函数中进行数据处理,如果没有重写event()函数进行事件处,理事件将会分发到事件默认的处理函数中,因此event()函数是事件的集散地。

如果重写了 event()函数当event()函数的返回值是True 时,表示事件已经处理完毕事件不会再发送给其他处理函数;当event()函数的返回值是 False时,表示事件还没有处理完毕。event()函数可以截获某些类型的事件,并处理事件

下面的程序是将上节中的例子做了改动将鼠标的单击事件放到event()函数中进行处理,只截获QEvent.MouseButtonPress事件,通过 super()函数调用父类的 event()函数其他类型的事件仍交由QWidget 的event()函数处理和分发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 21:18
# File_name: 02-event()函数.py
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLineEdit
from PySide6.QtCore import QEvent, Qt


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(500, 500)
self.lineEdit = QLineEdit(self)
self.lineEdit.setGeometry(0, 0, 500, 30)

def event(self, even): # 重写event函数
if even.type() == QEvent.MouseButtonPress: # 按键的情况
template1 = "单击点的窗口坐标是x:{} y:{}"
template2 = "单击点的屏幕坐标是x:{} y:{}"

if even.button() == Qt.LeftButton: # button()获取键或右键
string = template1.format(even.position().x(), even.position().y()) # x()和()获取窗口坐标
self.lineEdit.setText(string)
return True

elif even.button() == Qt.RightButton: # globalX()和globalY()获取全局坐标
string = template2.format(even.globalPosition().x(), even.globalPosition().y())
self.lineEdit.setText(string)
return True

else: # 按中键的情况
return True

else: # 对于不是按鼠标键的事件,交给 owidget 来处理
finished = super().event(even) # super()函数调用父类丽数
return finished


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

常用事件的处理函数

窗口或控件中用于常用事件的处理函数及参数类型如表所示,传递的参数是对应类的实例对象,参数所代表的类的使用方法在后续内容中进行介绍

常用事件的处理函数及参数类型 说 明
actionEvent(QActionEvent) 当增加、插人、删除QAction时调用该函数
changeEvent(QEvent) 状态发生改变时调用该函数,事件类型包括:
QEvent.ToolBarChange、QEvent.ActivationChange、QEvent.EnabledChange、 QEvent.FontChange、QEvent.StyleChange、QEvent.PaletteChange、 QEvent.WindowTitleChange、QEvent.IconTextChange、QEvent.ModifiedChange、QEvent.MouseTrackingChange、QEvent.ParentChange、 QEvent.WindowStateChange、QEvent.LanguageChange、QEvent.LocaleChange、QEvent.LayoutDirectionChange、QEvent.ReadOnlyChange
childEvent(QChildEvent) 容器控件中添加或移除控件时调用该函数
closeEvent(QCloseEvent) 关闭窗口时调用该函数
contextMenuEvent(QContextMenuEvent) 当窗口或控件的contextMenuPolicy 属性值是 Qt.DefaultContextMenu,单击右键弹出右键菜单时调用该函数
dragEnterEvent(QDragEnterEvent) 用鼠标拖拽物体进入窗口或控件时调用该函数
dragLeaveEvent(QDragLeaveEvent) 用鼠标拖拽物体离开窗口或控件时调用该函数
dragMoveEvent(QDragMoveEvent) 用鼠标拖拽物体在窗口或控件中移动时调用该函数
dropEvent(QDropEvent) 用鼠标拖拽物体在窗口或控件中释放时调用该函数
enterEvent(QEnterEvent) 光标进人窗口或控件时调用该函数
focusInEvent(QFocusEvent) 用键盘使窗口或控件获得焦点时调用该函数
focusOutEvent(QFocusEvent) 用键盘使窗口或控件失去焦点时调用该函数
hideEvent(QHideEvent) 隐藏或最小化窗口时调用该函数
inputMethodEvent(QInputMethodEvent) 输人方法的状态发生改变时调用该数
keyPressEvent(QKeyEvent) 按下键盘的按键时调用该函数
keyReleaseEvent(QKeyEvent) 释放键盘的按键时调用该函数
leaveEvent(QEvent) 光标离开窗口或控件时调用该函数
mouseDoubleClickEvent(QMouseEvent) 双击鼠标时调用该函数
mouseMoveEvent(QMouseEvent) 光标在窗口或控件中移动时调用该函数
mousePressEvent(QMouseEvent) 按下鼠标的按键时调用该函数
mouseReleaseEvent(QMouseEvent) 释放鼠标的按键时调用该函数
moveEvent(QMoveEvent) 移动窗口或控件时调用该函数
paintEvent(QPaintEvent) 控件或窗口需要重新绘制时调用该函数
resizeEvent(QResizeEvent) 窗口或控件的尺寸(长度或宽度)发生改变时调用该函数
showEvent(QShowEvent) 显示窗口或从最小化恢复到原窗口状态时调用该函数 .
tabletEvent(QTabletEvent) 平板电脑处理事件
timerEvent(QTimerEvent) 用窗口或控件的 startTimer(interval: int, timerType:Qt.CoarseTimer)方法启动一个定时器时调用该函数
wheelEvent(QWheelEvent) 转动鼠标的滚轮时调用该函数

每个窗口或控件的功能是不同的,因此窗口和控件的事件也不同,用于处理事件的函数也不同。

下面介绍的窗口或常用控件的事件处理函数如表所示。要调用窗口或控件的事件处理函数,需要继承窗口类或控件类创建其子类,在子类中重写事件处理函数。

窗口或控件 窗口或控件的事件处理函数
QWidget actionEvent()
changeEvent()
closeEvent()
contextMenuEvent()
dragEnterEvent()
dragLeaveEvent()
dragMoveEvent()
dropEvent()
enterEvent()
focusInEvent()
focusOutEvent()
hideEvent()
inputMethodEvent()
keyPressEvent()
leaveEvent()
keyReleaseEvent()
mouseDoubleClickEvent()
mouseMoveEvent()
showEvent()
mousePressEvent()
mouseReleaseEvent()
moveEvent()
paintEvent()
event()resizeEvent()
tabletEvent()
wheelEvent()
QMainWindo contextMenuEvent()
event()
QDialog showEvent()
closeEvent()
contextMenuEvent()
eventFilter()
keyPressEvent()
resizeEvent()
QLabel changeEvent()
contextMenuEvent()
event()
focusInEvent()
focusutEvent()
keyPressEyent()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
paintEyent()
QLineEdit changeEvent()
contextMenuEvent()
dragEnterEvent()
dragleaveEvent()
dragMoveEvent()
dropEvent()
focusInEvent()
focusutEvent()
paintEvent()
inputMethodEvent()
keyPressEvent()
keyReleaseEvent()
mouseMoveEvent()
mouseDoubleClickEvent()
mousePressEvent()
rouseReleaseEvent()
QTextEdit changeEvent()
contextMenuEvent()
dragEnterEvent()
dragLeaveEvent()
dragMoveEvent()
dropEvent()
focusInEvent()
focusCutEvent()
showEvent()
inputMethodEvent()
keyPressEvent()
keyReleaseEvent()
resizeEvent()
mouseDoubleClickEvent()
mouseMoyeEvent()
mousePressEvent()
paintEvent()
mouseReleaseEvent()
wheelEvent()
QPlainTextEdit changeEvent()
contextMenuEvent()
dragEnterEvent()
dragLeaveEvent()
dragMoveEvent()
dropEvent()
focusInEvent()
focusOutEvent()
paintEvent()
inputMethodEvent()
keyPressEvent()
keyReleaseEvent()
resizeEvent()
mouseDoubleClickEvent()
mouseMoveEvent()
mousePressEvent()
showEvent()
mouseReleaseEvent()
wheelEvent()
QTextBrowser event()
focusOutEvent()
keyPressEvent()
mouseMoveEvent()
paintEvent()
mousePressEvent()
mouseReleaseEvent()
QComboBox changeEvent()
contextMenuEvent()
focusInEvent()
focusOutEvent()
hideEvent()
inputMethodEvent()
keyPressEvent()
keyReleaseEvent()
musePressEvent()
mouseReleaseEvent()
paintEvent()
resizeEvent()
showEvent()
wheelEvent()
QScrollBar event()
contextMenuEvent()
hideEvent()
mouseMoveEvent()
paintEvent()
mousePressEvent()
mouseReleaseEvent()
wheelEvent()
QSlider event()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
paintEvent()
QDial event()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
paintEvent()
resizeEvent()
QProgressBar event()
paintEvent()
QPushButton event()
focusInEvent()
focusOutEvent()
keyPressEvent()
mouseMoveEvent()
paintEvent()
QCheckBox event()
mouseMoveEvent()
paintEvent()
QRadioButton event()
mouseMoveEvent()
paintEvent()
OCalendarWidget event()
eventFilter(t)
keyPressEvent()
mousePressEvent()
resizeEvent()
QLCDNumber event()
paintEvent()
QDateTimeEdit focusInEvent()
keyPressEvent()
mousePressEvent()
paintEvent()
wheelEvent()
QGroupBox changeEvent()
childEvent(QChildEvent)
event()
focusInEvent()
resizeEvent()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
paintEvent()
QFrame changeEvent()
event()
paintEvent()
QScrollArea event()
eventFilter(QObject,
QEvent)
resizeEvent()
QTabWidget changeEvent()
event()
keyPressEvent()
paintEvent()
resizeEvent()
showEvent()
QToolBox changeEvent()
closeEvent()
event()
paintEvent()
QSplitter childEvent(QChildEvent)
event()
eventFilter()
paintEvent()
resizeEvent()
showEvent()
timerEvent()
viewportEvent()
QWebEngineView closeEvent()
contextMenuEvent()
dragEnterEvent()
dragLeaveEvent()
dragMoveEvent()
dropEvent()
event()
hideEvent()
showEvent()
QDockWidget changeEvent()
closeEvent()
event()
paintEvent()
QMdiArea childEvent(QChildEvent)
event()
eventFilter()
paintEvent()
resizeEvent()
showEvent()
timerEvent()
viewportEvent()
QMdiSubWindow changeEvent()
childEvent(QChildEvent)
closeEvent()
contextMenuEvent()
event()
eventFilter()
focusInEvent()
focusOutEvent()
hideEvent()
timerEvent()
keyPressEvent()
leaveEvent()
mouseDoubleClickEvent()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
moveEvent()
paintEvent()
resizeEvent()showEvent()
QToolButton actionEvent()
changeEvent()
enterEvent()
event()
leaveEvent()
timerEvent()
mousePressEvent()
mouseReleaseEvent()
paintEvent()
QToolBar actionEvent()
changeEvent()
event()
paintEvent()
QMenuBar actionEvent()
changeEvent()
event()
eventFilter()
focusnEvent()
leaveEvent()
focusOutEvent()
keyPressEvent()
nouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
paintEvent()
resizeEvent()
timerEvent(QTimerEvent)
QStatusBar event()
paintEvent()
resizeEvent()
showEvent()
QTabBar changeEvent()event()
hideEvent()
keyPressEvent()
mouseDoubleClickEvent()
mouseMoveEvent()
mousePressEyent()
ouseReleaseEvent()
paintEyent()
resizeEvent()
showEvent()
timerEyent(QTimerEvent)
wheelEvent()
QListWidget dropEvent()
event()
QTableWidget dropEvent()
event()
QTreeWidget dropEvent()
event()
QListView dragLeaveEvent()
dragMoveEvent()
dropEvent()
event()
mouseMoveEvent()
mouseReleaseEvent()
paintEvent()
resizeEvent()
timerEvent(QTimerEvent)
wheelEvent()
QTreeView changeEvent()
dragMoveEvent()
keyPressEvent()
mouseDoubleClickEvent()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
paintEvent()
timerEvent(QTimerEvent)
viewportEvent()
QTableView paintEyent()
timerEvent(QTimerEvent)
QVideoWidget event()
hideEvent()
moveEvent()
resizeEvent()
showEvent()
QGraphicsView contextMenuEvent()
dragEnterEvent()
dragLeaveEvent()
ragMoveEvent()
dropEvent()
event()
focusInEvent()
focusOutEvent()
inputMethodEvent()
keyPressEvent()
keyReleaseEvent()
mouseDoubleClickEvent()
paintEvent()
mouseMoveEyent()
mousePressEyent()
mouseReleaseEvent()
resizeEvent()
showEvent()
viewportEvent()
wheelEvent()
QGraphicsScene event()
focusInEyent()
focusOutEvent()
keyPressEvent()
keyReleaseEvent()
eventFilter(QObject,
QEvent)
inputMethodEvent()
helpEvent(QGraphicsSceneHelpEvent)
wheelEvent(QGraphicsSceneWheelEvent)
contextMenuEvent(QGraphicsSceneContextMenuEvent)
dragEnterEyent(QGraphicsSceneragDropEvent)
dragleaveEvent(QGraphicsSceneDragDropEvent)
dragMoveEvent(QGraphicsSceneDragDropEvent)
dropEvent(QGraphicsSceneDragDropEvent)
mouseDoubleClickEvent(QCraphicsSceneMouseEvent)
mouseMoveEvent(QGraphicsSceneMouseEvent)
mousePressEvent(QGraphicsSceneMouseEvent)
mouseReleaseEvent(QGraphicsSceneMouseEvent)
QGraphicsWidget changeEyent()
closeEvent()
hideEvent()
showEvent()
polishEvent()
grabKeyboardEvent(QEvent)
grabMouseEvent(QEvent)
ungrabKeyboardEventQEvent)
ungrabMouseEvent(QEvent)
windowFrameEvent(QEvent)
moveEventQGraphicsSceneMoveEvent)
rasizeEvent(QGraphicsSceneResizeEvent)
QGraphicsItem focusInEvent()
focusOutEvent()
inputMethodEvent()
keyPressEvent()
QEvent()
keyReleaseEvent()
sceneEvent()
dropEvent(QGraphicsSceneDragDropEvent)
sceneEventFilter(QGraphicsItem,
QEvent)
wheelEvent(QGraphicsSceneWheelEvent)
contextMenuEvent(QGraphicsSceneContextMenuEvent)
dragEnterEvent(QGraphicsSceneDragDropEvent)
dragLeaveEvent(QGraphicsSceneDragDropEvent)
dragMoveEvent(QGraphicsSceneDragDropEvent)
hoverEnterEvent(QGraphicsSceneHoverEvent)
hoverLeaveEvent(QGraphicsSceneHoverEvent)
hoverMoveEvent(QGraphicsSceneHoverEvent)
mouseDoubleClickEvent(GraphicsSceneMouseEvent)
mouseMoveEvent(QGraphicsSceneMouseEvent)
mousePressEvent(QGraphics-SceneMouseEvent)
mouseReleaseEvent(QGraphicsSceneMoGseEvent)

鼠标事件和键盘事件

鼠标事件和键盘事件是用得最多的事件,通过鼠标和键盘事件可以拖拽控件、弹出快捷菜单等。

鼠标事件QMouseEvent和滚轮事件QWheelEvent

鼠标事件类QMouseEvent涉及鼠标按键的单击释放和鼠标移动操作与QMouseEvent关联的事件类型有:

  • QEvent.MouseButtonDblClick
  • QEvent.MouseButtonPress
  • QEvent.MouseButtonRelease
  • QEvent.MouseMove

当在一个窗口或控件中按住鼠标按键或释放按键时会产生鼠标事件QMouseEvent

鼠标移动事件只会在按下鼠标按键的情况下才会发生,除非通过显式调用窗口的 setMouseTracking(True)函数来开启鼠标轨迹跟踪,这种情况下只要鼠标指针移动,就会产生一系列鼠标事件。

处理QMouseEvent类鼠标事件的函数有:

  • mouseDoubleClickEvent(QMouseEvent)(双击鼠标按键)
  • mouseMoveEvent(QMouseEvent)(移动鼠标)
  • mousePressEvent(QMouseEvent)(按下鼠标按键)
  • mouseReleaseEvent(QMouseEvent)(释放鼠标按键)。

鼠标滚轮的滚动事件类是QWheelEvent,处理QWheelEvent 滚轮事件的函数是 wheelEvent(QWheelEvent)。

鼠标事件QMouseEvent 的常用方法

当产生鼠标事件时,会生成 QMouseEvent 类的实例对象,并将实例对象作为实参传递给相关的处理函数。

QMouseEvent 类包含了用于描述鼠标事件的参数。

QMouseEvent类在 QtGui模块中,它的常用方法如表 4-5所示,主要方法介绍如下。

  • 用button()方法可以获取产生鼠标事件的按键,用buttons()方法获取产生鼠标事件时被按住的按键,返回值可以是:

    • Qt.NoButton
    • Qt.AllButtons
    • Qt.LeftButton
    • Qt.RightButton
    • Qt.MidButton
    • Qt.MiddleButton
    • Qt.BackButton
    • Qt.ForwardButton
    • Qt.TaskButton
    • Qt.ExtraButtoni(i=1,2,…,24)
  • 用source()方法可以获取鼠标事件的来源,返回值可以是:

    • Qt.MouseEventNotSynthesized(来自鼠标)
    • Qt.MouseEventSynthesizedBySystem(来自鼠标和触摸)
    • Qt.MouseEventSynthesizedByQt(来自触摸屏)
    • Qt.MouseEventSynthesizedByApplication(来自应用程序)
  • 产生鼠标事件的同时,有可能按下了键盘上的 Ctrl Shift 或 Alt 等修饰键,用modifiers()方法可以获取这些键。modifiers()方法的返回值可以是:

    • Qt.NoModifier(没有修饰键)
    • Qt.ShiftModifier(Shift 键)
    • Qt.ControlModifier(Ctrl键)
    • Qt.AltModifier(Alt 键)
    • Qt.MetaModifier(Meta 键,Windows 系统为 window键)
    • Qt.KeypadModifier(小键盘上的键)
    • Qt.GroupSwitchModifier(Modeswitch 键)
  • 用deviceType()方法可以获取产生鼠标事件的设备类型,返回值是 QInputDevice.DeviceType 的枚举值可取:

    • QInputDevice.Unknown
    • QInputDevice.Mouse
    • QInputDevice.TouchScreen
    • QInputDevice.TouchPad
    • QInputDevice.Stylus
    • QInputDevice.Airbrush
    • QInputDevice.Puck
    • QInputDevice.Keyboard
    • QInputDevice.AlDevices(以上设备中的任意一种)。
  • 用flags()方法可以识别产生鼠标事件时的标识,返回值是 QtMouseEventFlags的枚举值,只可以取Qt.MouseEventCreatedDoubleClick,用于标识鼠标的双击事件

QMouseEvent的方法 返回值的类型 说 明
button() Qt.MouseButton 获取产生鼠标事件的按键
buttons() Qt.MouseButtons 获取产生鼠标事件时被按下的按键
flags() Qt.MouseEventFlags 获取鼠标事件的标识
source() Qt.MouseEventSource 获取鼠标事件的来源
modifiers() Qt.KeyboardModifiers 获取修饰键
device() QInputDevice 获取产生鼠标事件的设备
deviceType() QInputDevice.DeviceType 获取产生鼠标事件的设备类型
globalPos() QPoint 获取全局的鼠标位置
globalX() int 获取全局的X坐标
globalY() int 获取全局的Y坐标
localPos() QPointF 获取局部鼠标位置
screenPos() QPointF 获取屏幕的鼠标位置
windowPos() QPointF 获取相对于接受事件窗口的鼠标位置
pos() QPoint 获取相对于控件的鼠标位置
此方法在新版本已经会发出弃用警告改用position()
position() QPoint 获取相对于控件的鼠标位置
x() int 获取相对于控件的X坐标
此方法在新版本已经会发出弃用警告改用position().x()
y() int 获取相对于控件的Y坐标
此方法在新版本已经会发出弃用警告改用position().y()

滚轮事件QWheelEvent的方法

滚轮事件 QWheelEvent类处理鼠标的滚轮事件,其常用方法如表所示大部分方法与QMouseEvent 的方法相同,主要不同的方法如下所述。

  • 滚轮角度

    • angleDelta().y()返回两次事件之间鼠标竖直滚轮旋转的角度

    • angleDelta()x()返回两次事件之间鼠标水平滚轮旋转的角度。

    • 如果没有水平滚轮,则angleDetal().x()的值为 0,正数值表示滚轮相对于用户在向前滑动,负数值表示滚轮相对于用户在向后滑动

  • pixelDelta()方法返回两次事件之间控件在屏幕上的移动距离(单位是像素)

  • inverted()方法将 angleDelta()和 pixelDelta()的值与滚轮转之间的取值关系反向,即正数值表示滑轮相对于用户在向后滑动,负数值表示滑轮相对于用户在向前滑动。

  • phase()方法返回设备的状态,返回值有:

    • Qt.NoScrollPhase(不支持滚动)
    • Qt.ScrollBegin(开始位置)
    • Qt.ScrollUpdate(处于滚动状态)
    • Qt.ScrollEnd(结束位置)
    • Qt.ScrollMomentum(不触碰设备,由于惯性仍处于滚动状态)
QWheelEvent的方法 返回值的类型
angleDelta() QPoint
pixelDelta() QPoint
phase() Qt.ScrollPhase
inverted() bool
source() Qt.MouseEventSource
buttons() Qt.MouseButtons
globalPos() QPoint
globalPosF() QPointF
deviceType() QInputDevice.DeviceType
modifiers() Qt.KeyboardModifiers|
globalPosition() QPointF
globalX() int
globalY() int
pos() QPoint
posF() QPointF
position() QPointF
x() int
y() int

QMouseEvent 类和QWheelEvent 类的应用实例

下面的程序涉及鼠标单击、拖拽、双击和滚轮滚动的事件

双击窗口的空白处或者单击菜单,弹出打开图片的对话框,选择图片后,显示出图片

按住 Ctrl 键和鼠标左键并拖动鼠标可以移动图片,按住 Ctrl键并滚动滚轮可以缩放图片。

程序中通过控制绘图区域的中心位置来移动图像,通过控制图像区域的宽度和高度来缩放图像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 23:00
# File_name: 01-鼠标事件QMouseEvent和滚轮事件QWheelEvent .py
from PySide6.QtWidgets import QApplication, QWidget, QFileDialog, QMenuBar
from PySide6.QtGui import QPixmap, QPainter, QMouseEvent, QWheelEvent
from PySide6.QtCore import QRect, QPoint, Qt.QPointF
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 600)
self.pixmap = QPixmap() # 创建QPixmap图像
self.pix_width = 0 # 获取初始宽度
self.pix_height = 0 # 获取初始高度
self.translate_x = 0 # 用于控制x向平移
self.translate_y = 0 # 并用于控制y向平移
self.pixmap_scal_x = 0 # 用于记录图像的长度比例,用于图像缩放
self.pixmap_scal_y = 0 # 用于记录图像的高度比例,用于图像缩放
self.start = QPoint(0, 0) # 鼠标单击时光标位置

# 记录图像中心的变量,初始定义在窗口的中心
self.center = QPoint(int(self.width() / 2), int(self.height() / 2))
menuBar = QMenuBar(self)
menuFile = menuBar.addMenu("文件(&F)")
menuFile.addAction("打开(&0)").triggered.connect(self.actionOpen_triggered)
menuFile.addSeparator()
menuFile.addAction("退出(&E)").triggered.connect(self.close) # 动作与槽连接

def paintEvent(self, event): # 窗口绘制处理函数,当窗口刷新时调用该函数
self.center = QPoint(self.center.x() + self.translate_x, self.center.y() + self.translate_y)

# 图像绘制区域的左上角点,用于缩放图像
point_1 = QPoint(self.center.x() - self.pix_width, self.center.y() - self.pix_height)

# 图像绘制区域的右下角点,用于缩放图像
point_2 = QPoint(self.center.x() + self.pix_width, self.center.y() + self.pix_height)

self.rect = QRect(point_1, point_2) # 图像绘制区域
painter = QPainter(self) # 绘图
painter.drawPixmap(self.rect, self.pixmap)

def mousePressEvent(self, event: QMouseEvent): # 鼠标按键按下事件的处理函数
self.start: QPointF = event.position() # 鼠标位置
# 这里在Qt6使用pos()会发出弃用警告官方建议的是用position()代替pos()

def mouseMoveEvent(self, event: QMouseEvent) -> None: # 鼠标移动事件的处理函数
if event.modifiers() == Qt.ControlModifier and event.buttons() == Qt.LeftButton:
# 这里直接从event获取坐标会发出弃用警告,官方建议的是用position()间接获得坐标
self.translate_x = event.position().x() - self.start.x() # 鼠标的移动量
self.translate_y = event.position().y() - self.start.y()

self.start = event.position()
self.update() # 会调用paintEvent()

def wheelEvent(self, event: QWheelEvent) -> None: # 鼠标滚轮事件的处理函数
if event.modifiers() == Qt.ControlModifier:
if(self.pix_width > 10 and self.pix_height > 10) or event.angleDelta().y() > 0:
self.pix_width = self.pix_width + int(event.angleDelta().y() / 10 * self.pixmap_scal_x)
self.pix_height = self.pix_height + int(event.angleDelta().y() / 10 * self.pixmap_scal_y)

self.update()

def mouseDoubleClickEvent(self, event): # 双击鼠标事件的处理函数
self.actionOpen_triggered()

def actionOpen_triggered(self): # 打开文件动作
fileDialog = QFileDialog(self)
fileDialog.setNameFilter("图像文件(*.png *.jpeg *.jpg)")
fileDialog.setFileMode(QFileDialog.FileMode.ExistingFile)

if fileDialog.exec():
self.pixmap.load(fileDialog.selectedFiles()[0])
self.pix_width = int(self.pixmap.width() / 2) # 获取初始宽高
self.pix_height = int(self.pixmap.height() / 2)

self.pixmap_scal_x = self.pix_width /(self.pix_width + self.pix_height)
self.pixmap_scal_y = self.pix_height /(self.pix_width + self.pix_height)
self.center = QPoint(int(self.width() / 2), int(self.height() / 2))

self.update()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

键盘事件QKeyEvent

键盘事件QKeyEvent 涉及键盘键的按下和释放与QKeyEvent 关联的事件类型有:

  • QEvent.KeyPress
  • QEvent.KeyRelease
  • QEvent.ShortcutOverride

处理键盘事件的函数是 keyPressEvent(QKeyEvent)和 keyReleaseEvent(QKeyEvent)。

  • 当发生键盘事件时将创建QKeyEvent的实例对象,并将实例对象作为实参传递给处理函数键盘事件QKeyEvent的常用方法如所示主要方法介绍如下:
    • 如果同时按下多个键,可以用count()方法获取按键的数量。
    • 如果按下一个键不放,将连续触发键盘事件,用isAutoRepeat()方法可以获取某个事件是否是重复事件。
    • 用key()方法可以获取按键的Qtkey代码值不区分大小写;可以用text()方法获取按键的字符,区分大小写。
    • 用matches(QKeySequenceStandardKey)方法可以判断按下的键是否匹配标准的按键,QKeySequenceStandardKey中定义了常规的标准按键例如:
      • Ctrl+C表示复制、Ctrl+V表示粘贴、Ctrl+S表示保存Ctrl+0表示打开Ctrl+w或Ctrl+F4表示关闭。
QKeyEvent的方法 返回值的类型 说明
count() int 获取按键的数量
isAutoRepeat() bool 获取是否是重复事件
key() int 获取按键的代码
matches(QKeySequence.StandardKey) bool 如果按键匹配标准的按键,则返 回 True
modifiers() Qt.KeyboardModifiers 获取修饰键
text() Str 返回按键上的字符

鼠标拖放事件QDropEvent和QDragMoveEvent

可视化开发中经常会用鼠标拖放动作来完成一些操作,例如把一个 docx 文档拖到Word 中直接打开,把图片拖放到一个图片浏览器中打开,拖放一段文字到其他位置等。

拖放事件包括鼠标进人、鼠标移动和鼠标释放事件,还可以有鼠标移出事件,对应的事件类型分别是:

  • QEvent.DragEnter
  • QEvent.DragMove
  • QEvent.Drop
  • QEvent.DragLeave。

拖放事件类分别为QDragEnterEvent,QDragMoveEvent,QDropEvent和QDragLeaveEvent,其实例对象中保存着拖放信息,例如被拖放文件路径、被拖放的文本等。拖放事件的处理函数分别是:

  • dragEnterEvent(QDragEnterEvent)
  • dragMoveEvent(QDragMoveEvent)
  • dropEvent(QDropEvent)
  • dragLeaveEvent(QDragLeaveEvent)

QDropEvent 和 QDragMoveEvent 的方法

QDragEnterEvent类是从QDropEvent类和QDragMoveEvent 类继承而来的,它没有自己特有的方法;

QDragMoveEvent 类是从QDropEvent 类继承而来的,它继承了QDropEvent类的方法,又添加了自已新的方法;

QDragLeaveEvent类是从QEvent类继承而来的,它也没有自己特有的方法。

QDropEvent类和QDragMoveEvent类的方法分别如表所示,主要方法介绍如下。

  • 使一个控件或窗口接受拖放
    • 必须用setAcceptDrops(True)方法设置成接受拖放,
    • 在进入事件的处理函数 dragEnterEvent(QDragEnterEvent)中,需要把事件对象设置成 accept(),否则无法接受后续的移动和释放事件
  • 在拖放事件中用mimeData()方法获取被拖放物体的QMimeData 数据MIME(multipurposeinternet mail extensions)是多用途互联网邮件扩展类型。关于QMimeData的介绍参见下面的内容。
  • 在释放动作中,被拖拽的物体可以从原控件中被复制或移动到目标控件中
    • 复制或移动动作可以通过 setDropAction(QtDropAction)方法来设置其中Qt.DropAction可以取:
      • Qt.CopyAction(复制)
      • Qt.MoveAction(移动)
      • Qt.LinkAction(链接)
      • Qt.IgnoreAction(什么都不做)
      • Qt.TargetMoveAction(目标对象接管)
    • 另外系统也会推荐一个动作,可以用proposedAction()方法获取推荐的动作,用possibleActions()方法获取有可能实现的动作用dropAction()方法获取采取的动作。

QDropEvent的常用方法

QDropEvent 的方法 返回值的类型 说明
keyboardModifiers() Qt.KeyboardModifiers 获取修饰键
mimeData() QMimeData 获取 mime 数据
mouseButtons() Qt.MouseButtons 获取按下的鼠标按键
pos() QPoint 获取释放时的位置
posF() QPointF 获取释放时的位置
dropAction() Qt.DropAction 获取采取的动作
possibleActions() Qt.DropActions 获取可能实现的动作
proposedAction() Qt.DropAction 系统推荐的动作
acceptProposedAction() None 接受推荐的动作
setDropAction(Qt.DropAction) None 设置释放动作
source() QObject 获取被拖对象

QDragMoveEvenl的常用方法

QDragMoveEvent的方法 返回值的类型 说 ,明
accept() None 在控件或窗口的边界内都可接受移动事件
accept(QRect) None 在指定的区域内接受移动事件
ignore() None 在整个边界内部忽略移动事件
ignore(QRect) None 在指定的区域内部忽略移动事件
answerRect() QRect 返回可以释放的区域

QMimeData类

QMimeData 类用于描述存放到粘贴板上的数据,并通过拖放事件传递粘贴板上的数据,从而在不同的程序间传递数据,也可以在同一个程序内传递数据。

创建 QMimeData 实例对象的方法是 QMimeData(),它在 QtCore模块中。QMimeData 可以存储的数据有文本、图像、颜色和地址等。

QMimeData类的方法如表所示,可以分项设置和获取数据,也可以用setData(str,QByteArray)方法设置数据

QMimeData的数据格式各种数据设置和获取的方法如表所示。

QMimeData类的方法

QMimeData的方法及参数类型 返回值的类型 说明
formats() List[str] 获取格式列表
hasFormat(str) bo0l 获取是否有某种格式
removeFormat(str) None 移除格式
setColorData(Any) None 设置颜色数据
hasColor() bool 获取是否有颜色数据
colorData() Any 获取颜色数据
setHtml(str) None 设置Html数据
hasHtml() bool 判断是否有 Html数据
html() Str 获取 Html数据
setImageData(Any) None 设置图像数据
hasImage() bool 获取是否有图像数据
imageData() Any 获取图像数据
setText(str) None 设置文本数据
hasText() bool 判断是否有文本数据
text() str 获取文本数据
setUrls(Sequence[QUrl]) None 设置Url数据
hasUrls() bool 判断是否有Url数据
urls() List[QUrl] 获取 Url数据
setData(str,QByteArray) None 设置某种格式的数据
data(str) QByteArray 获取某种格式的数据
clear() None 清空格式和数据

QMimeData的数据格式和方法

格式 是否存在 获取方法 设置方法 举例
text/plain hasText() text() setText() setText(“拖动文本”)
text/html hasHtml() html() setHtml() setHtml(“拖动文本“)
text/uri-list hasUrls() urls() setUrls() setUrls([QUrl(“www.qq.com/")])
image/ * hasImage() imageData() setImageData() setImageData(QImage(“ix.png”))
application/x-color basColor() colorData() setColorData() setColorData(QColor(23,56, 53))

拖放事件的应用实例

下面的程序是在上一个实例的基础上增加了拖拽功能,除了可以双击窗口、用菜单打开二个图像文件外,也可以把一个图像文件拖拽到窗口上打开。

需要注意的是,要使窗口或控件接受拖放操作,应该用setAcceptDrops(bool)方法将其设置成 True。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 20:29
# File_name: demo.py

import sys
from PySide6.QtWidgets import QApplication, QWidget, QFileDialog, QMenuBar
from PySide6.QtGui import QPixmap, QPainter, QMouseEvent, QWheelEvent, QDragEnterEvent, QDropEvent
from PySide6.QtCore import QRect, QPoint, Qt.QPointF


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setAcceptDrops(True) # 设置成接受拖放事件
self.resize(600, 600)

self.pixmap = QPixmap() # 创建QPixmap图像
self.pix_width = 0 # 获取初始宽度
self.pix_height = 0 # 获取初始高度

self.translate_x = 0 # 用于控制x向平移
self.translate_y = 0 # 用于控制y向平移

self.pixmap_scale_x = 0 # 用于记录图像的长度比例,用于图像缩放
self.pixmap_scale_y = 0 # 用于记录图像的高度比例,用于图像缩放

self.start = QPoint(0, 0) # 鼠标单击时光标位置

# 记录图像中心的变量,初始定义在窗口的中心
self.center = QPoint(int(self.width() / 2), int(self.height() / 2))
menuBar = QMenuBar(self)
menuFile = menuBar.addMenu("文件(&F)")
menuFile.addAction("打开(80)").triggered.connect(self.actionOpen_triggered)
menuFile.addSeparator()
menuFile.addAction("退出(8E)").triggered.connect(self.close) # 动作与槽连接

def paintEvent(self, event): # 窗口绘制处理函数,当窗口刷新时调用该函数
self.center = QPoint(self.center.x() + self.translate_x, self.center.y() + self.translate_y)

# 图像绘制区域的左上角点,用于缩放图像
point_1 = QPoint(self.center.x() - self.pix_width, self.center.y() - self.pix_height)

# 图像绘制区域的右下角点,用于缩放图像
point_2 = QPoint(self.center.x() + self.pix_width, self.center.y() + self.pix_height)

self.rect = QRect(point_1, point_2) # 图像绘制区域
painter = QPainter(self) # 绘图
painter.drawPixmap(self.rect, self.pixmap)

def actionOpen_triggered(self):
fileDialog = QFileDialog(self)
fileDialog.setNameFilter("图像文件(*.png *.jpeg *.jpg)")
fileDialog.setFileMode(QFileDialog.FileMode.ExistingFile)

if fileDialog.exec():
self.pixmap.load(fileDialog.selectedFiles()[0])
self.pix_width = int(self.pixmap.width() / 2) # 获取初始宽高
self.pix_height = int(self.pixmap.height() / 2)

self.pixmap_scal_x = self.pix_width /(self.pix_width + self.pix_height)
self.pixmap_scal_y = self.pix_height /(self.pix_width + self.pix_height)
self.center = QPoint(int(self.width() / 2), int(self.height() / 2))

self.update()

def mousePressEvent(self, event: QMouseEvent) -> None: # 鼠标按下事件处理
self.start: QPointF = event.position() # 鼠标位置
# 这里在Qt6使用pos()会发出弃用警告官方建议的是用position()代替pos()

def mouseMoveEvent(self, event: QMouseEvent) -> None: # 鼠标移动事件处理
if event.modifiers() == Qt.ControlModifier and event.buttons() == Qt.LeftButton:
# 这里直接从event获取坐标会发出弃用警告,官方建议的是用position()间接获得坐标
self.translate_x = event.position().x() - self.start.x() # 鼠标的移动量
self.translate_y = event.position().y() - self.start.y()

self.start = event.position()
self.update() # 会调用paintEvent()

def wheelEvent(self, event: QWheelEvent) -> None: # 鼠标滚动事件
if event.modifiers() == Qt.ControlModifier:
if(self.pix_width > 10 and self.pix_height > 10) or event.angleDelta().y() > 0:
self.pix_width = self.pix_width + int(event.angleDelta().y() / 3 * self.pixmap_scal_x)
self.pix_height = self.pix_height + int(event.angleDelta().y() / 3 * self.pixmap_scal_y)

self.update()

def mouseDoubleClickEvent(self, event: QMouseEvent) -> None:
self.actionOpen_triggered()

def dragEnterEvent(self, event: QDragEnterEvent) -> None: # 进入拖动事件
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()

def dropEvent(self, event: QDropEvent) -> None: # 拖动释放事件
urls = event.mimeData().urls() # 获取被拖动文件的地址列表
fileName = urls[0].toLocalFile() # 将文件地址转成本地地址
self.pixmap.load(fileName)
self.pix_width = int(self.pixmap.width() / 2) # 获取初始宽度
self.pix_height = int(self.pixmap.height() / 2) # 获取初始高度

self.pixmap_scal_x = self.pix_width /(self.pix_width + self.pix_height)
self.pixmap_scal_y = self.pix_height /(self.pix_width + self.pix_height)
self.center = QPoint(int(self.width() / 2), int(self.height() / 2))

self.update()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

拖拽类QDrag

如果要在程序内部拖放控件,需要先把控件定义成可移动控件,可移动控件需要在其内部定义 QDrag 的实例对象。

QDrag 类用于拖放物体,它继承自 QObject 类,创建 QDrag实例对象的方法是 QDrag(QObject),参数 QObject 表示只要是从 QObject 类继承的控件都可以。

QDrag类的方法和信号

QDrag类的方法如表所示,主要方法介绍如下:

  • 创建QDrag实例对象后,用exec(supportedActions;Qt.DropActions,delaultAction;QtDropAction)或 exec(supportedActions; Qt.DropActions一Qt.MoveAction)方法开启拖放,参数是拖放事件支持的动作和默认动作,QtDropAction可以取:
    • QtCopyAction(复制数据到目标对象)
    • Qt.MoveAction(移动数据到目标对象)
    • Qt.LinkAction(在目标和原对象之间建立链接关系)
    • Qt.IgnoreAction(忽略,对数据不做任何事情)
    • QtTargetMoveAction(目标对象接管数据)
  • 用setMimeData(QMimeData)方法设置mime对象,传递数据;用mimeData()方法获取mime数据
  • 用setPixmap(QPixmap)方法设置拖拽时鼠标显示的图像,用setDragCursor(QPixmap,QtDropAction)方法设置拖拽时光标的形状用setHotSpot(QPoint)方法设置热点位置。热点位置是拖拽过程中,光标相对于控件左上角的位置。
  • 为了防止误操作,可以用QApplication的setStartDragDistance(int)方法和setStartDragTime(msec)方法设置拖动开始一定距离或一段时间后才开始进行拖放事件。
QDrag的方法及参数类型 返回值的类型 说明
exec(supportedActions: Qt.DropActions = Qt.MoveAction) Qt.DropAction 开始拖动操作,并返回释放时的 动作
exec(supportedActions: Qt.DropActions, defaultAction: Qt.DropAction)
defaultAction() Qt.DropAction 返回默认的释放动作
setDragCursor(QPixmap, Qt.DropAction) None 设置拖拽时的光标形状
dragCursor(Qt.DropAction) QPixmap 获取拖拽时的光标形状
setHotSpot(QPoint) None 设置热点位置
hotSpot() QPoint 获取热点位置
setMimeData(QMimeData) None 设置拖放中传递的数据
mimeData() QMimeData 获取数据
setPixmap(QPixmap) None 设定拖拽时鼠标显示的图像
pixmap() QPixmap 获取图像
source() QObject 返回被拖放物体的父控件
target() QObject 返回目标控件
supportedActions() Qt.DropActions 获取支持的动作
cancel() None 取消拖放

信号

信号 说明
actionChanged(Qt.DropAction)
targetChanged(QObject)

QDrag的应用实例

下面实例先重写了QPushButton 的 mousePressEvent()事件,在该事件中定义了QDrag的实例,这样QPushButton的实例对象就是可移动控件;

然后又重新定义了QFrame框架,在内部定义了两个QPushButton,重写了dragEnterEvent()函数dragMoveEvent()函数和dropEvent()函数。

程序运行后,可以随机用鼠标左键移动按钮的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/2 20:51
# File_name: 03-QDrag的应用实例.py
from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QFrame, QHBoxLayout
from PySide6.QtGui import QDrag, QMouseEvent
import sys
from PySide6.QtCore import QMimeData, Qt


class MyPushButton(QPushButton):
def __init__(self, parent=None):
super().__init__(parent)

def mousePressEvent(self, event: QMouseEvent) -> None:
if event.button() == Qt.LeftButton: # 按键事件
self.drag = QDrag(self)
self.drag.setHotSpot(event.position().toPoint())
mime = QMimeData()
self.drag.setMimeData(mime)
self.drag.exec()


class MyFame(QFrame):
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.setFrameShape(QFrame.Shape.Box)
self.btn_1 = MyPushButton(self)
self.btn_1.setText("push button 1")
self.btn_1.move(100, 100)
self.btn_2 = MyPushButton(self)
self.btn_2.setText("push button 2")
self.btn_2.move(200, 200)

def dragEnterEvent(self, event):
self.child = self.childAt(event.position().toPoint()) # 获取指定位置的控件
event.accept()

def dragMoveEvent(self, event):
if self.child:
self.child.move(event.position().toPoint() - self.child.drag.hotSpot())

def dropEvent(self, event):
if self.child:
self.child.move(event.position().toPoint() - self.child.drag.hotSpot())


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi()

self.resize(600, 400)
self.setAcceptDrops(True)

def setupUi(self):
self.frame_1 = MyFame(self)
self.frame_2 = MyFame(self)
H = QHBoxLayout(self)
H.addWidget(self.frame_1)
H.addWidget(self.frame_2)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

上下文菜单事件QContextMenuEvent

上下文菜单事件QContextMenuEvent的方法

上下文菜单通常通过单击鼠标右键后弹出。

上下文菜单的事件类型是 QEvent.ContextMenu,处理函数是 contextMenuEvent(QContextMenuEvent),其中上下文菜单类QContextMenuEvent 的方法如表所示。主要方法介绍如下。

QContextMenuEvent的方法 返回值的类型 说明
globalPos() QPoint 光标的全局坐标点
globalX() int 全局坐标的X值
globalY() int 全局坐标的Y值
pos() QPoint 局部坐标点
x() int 局部坐标的x值
y() int 局部坐标的y值
reason() QContextMenuEvent.Reason 获得产生上下文菜单的原因
modifiers() Qt.KeyboardModifiers 获取修饰键
  • 用globalPos()方法、globalX()方法和 globalY()方法可以获得单击鼠标右键时的全局坐标位置

  • 用pos()方法、X()方法和 y()方法可以获得窗口的局部坐标位置

  • 用reason()方法可以获得产生上下文菜单的原因,返回值是 QContextMenuEvent.Reason 的枚举值,可能是:

    • QContextMenuEvent.Mouse 值为0,上下文菜单来源于鼠标
    • QContextMenuEvent.Keyboard 值为1,键盘(Windows 系统是菜单键)
    • QContextMenuEvent.Other 值为2,除鼠标及键盘之外的
  • 在contextMenuEvent(QContextMenuEvent)处理函数中,用菜单的 exec(QPoint)方法在指定位置显示菜单,菜单可以是在其他位置已经定义好的,也可以是在处理函数中临时定义的。
    只有在窗口或控件的 contextMenuPlolicy 属性为Qt.DefaultContextMenu 时,单击鼠标右键才会执行处理函数,通常情况下 Qt.DefaultContextMenu是默认值。

  • 如果不想弹出右键菜单,可以通过 setContextMenuPolicy(Qt.ContextMenuPolicy)方法将该属性设置为其他值,Qt.ContextMenuPolicy的取值如表所示:

    Qt.ContextMenuPolicy 取值 说明
    Qt.NoContextMenu 0 控件不具有上下文菜单,上下文菜单被推到控件的父窗口
    Qt.DefaultContextMenu 1 控件或窗口的contextMenuEvent()被调用
    Qt.ActionsContextMenu 2 将控件 actions()方法返回的QActions当作上下文菜单项,单击 鼠标右键后显示该菜单
    Qt.CustomContextMenu 3 控件发送 customContextMenuRequested(Qpoint)信号,如果要 自定义菜单,用这个枚举值,并自定义一个处理函数
    Qt.PreventContextMenu 4 控件不具有上下文菜单,所有的鼠标右键事件都传递到 mousePressEvent()和 mouseReleaseEvent()函数

上下文菜单事件QContextMenuEvent应用实例

下面的程序建立一个空白窗口,在窗口单击鼠标右键,弹出上下文菜单,然后选择打开项,选择一幅图片后,在窗口上显示该图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/2 21:29
# File_name: 04-上下文菜单事件QContextMenuEvent 应用实例.py

from PySide6.QtWidgets import QApplication, QWidget, QFileDialog, QMenu
from PySide6.QtGui import QPixmap, QPainter
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True) # 设置可接受拖放事件
self.resize(600, 400)
self.pixmap = QPixmap() # 创建QPixmap图像

def contextMenuEvent(self, event):
contextMenu = QMenu(self)

contextMenu.addAction("打开(&0)").triggered.connect(self.actionOpen_triggered) # 槽连接

contextMenu.addSeparator()
contextMenu.addAction("退出(&E)").triggered.connect(self.close) # 动作与槽连接

contextMenu.exec(event.globalPos())

def paintEvent(self, event): # 窗口绘制处理函数,当窗口刷新时调用该函数
painter = QPainter(self) # 绘图
painter.drawPixmap(self.rect(), self.pixmap)

def mouseDoubleClickEvent(self, event): # 双击鼠标事件的处理函数
self.actionOpen_triggered()

def actionOpen_triggered(self): # 打开文件的动作
fileDialog = QFileDialog(self)
fileDialog.setNameFilter("图像文件(*.png *jpeg *.jpg)")
fileDialog.setFileMode(QFileDialog.FileMode.ExistingFile)
if fileDialog.exec():
self.pixmap.load(fileDialog.selectedFiles()[0])
self.update()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

剪贴板QClipboard

剪贴板 QClipboard类似于拖放,可以在不同的程序间用复制和粘贴操作来传递数据QClipboard 位于QtGui模块中,继承自 QObject类,用QClipboard(parent=None)方法可以创建剪贴板对象。

可以直接往剪贴板中复制文本数据、QPixmap 和 QImage,其他数据类型可以通过QMimeData来传递,剪贴板QClipboard 的常用方法如表所示。

QClipboard的方法及参数类型 返回值的类型 说 明
setText(str) None 将文本复制到剪贴板
text() str 从剪贴板上获取文本
text(str) Tuple[str,str] 从str指定的数据类型中获取文本,数据类型如 plain 或html
setPixmap(QPixmap) None 将QPixmap 图像复制到剪贴板上
pixmap() QPixmap 从剪贴板上获取QPixmap 图像
setImage(QImage) None 将QImage图像复制到剪贴板上
image() QImage 从剪贴板上获取QImage图像
setMimeData(QMimeData) None 将QMimeData数据赋值到剪贴板上
mimeData() QMimeData 从剪贴板上获取QMimeData数据
elear() None 清空剪贴板

信号

剪贴板的主要信号是 dataChanged(),当剪贴板上的数据发生变化时发送该信号

窗口和控件的常用事件

窗口和控件的常用事件包括窗口或控件的隐藏、显示、移动、缩放、重绘、关闭、获得和失去焦点等,通常需要重写这些事件的处理函数,以便达到特定的目的。

显示事件QShowEvent和隐藏事件QHideEvent

在用show()方法或 setVisible(True)方法显示一个顶层窗口之前会发生 QEvent.Show事件调用showEvent(QShowEvent)处理函数,显示事件类 QShowEvent 只有从QEvent 继承的属性没有自已特有的属性。

在用hide()方法或 setVisible(False)方法隐藏一个顶层窗口之前会发生 QEvent.Hide 事件调用hideEvent(QHideEvent)处理函数,隐藏事件类QHideEvent 只有从 QEvent 继承的属性,没有自已特有的属性。利用显示和隐藏事件的处理函数,可以在窗口显示之前或被隐藏之前做一些预处理工作。

缩放事件QResizeEvent和移动事件QMoveEvent

当一个窗口或控件的宽度和高度发生改变时会触发 QEvent.Resize 事件,调用resizeEvent(QResizeEvent)处理函数。

缩放事件类QResizeEvent 只有两个方法oldSize()和 size(),分别返回缩放前和缩放后的窗口尺寸QSize

当改变一个窗口或控件的位置时会触发 QEvent,Move 事件,调用moveEvent(QMoveEvent)处理函数。

移动事件类QMoveEvent 只有两个方法oldPos()和 pos(),分别返回窗口左上角移动前和移动后的位置 QPoint。

绘制事件QPaintEvent

绘制事件QPaintEvent是窗体系统产生的在一个窗口首次显示隐藏后又显示缩放窗口移动控件,以及调用窗口的 update() repaint()resize()方法时都会发 QEvent.Paint事件。

绘制事件发生时,会调用paintEvent(QPaintEvent)处理函数该函数是受保护的,不能直接用代码调用,通常在 paintEvent(QPaintEvent)处理函数中处理一些与绘图显示有关的事情。

绘制事件类QPaintEvent 只有两个方法 rect()和 region()方法分别返回被重绘的矩形区域 QRect 和裁剪区域 QRegion。

进人事件和离开事件 QEnterEvent

当光标进入窗口时,会触发 QEvent, Enter 进人事件,进人事件的处理函数是enterEvent(QEnterEvent),QEnterEvent 的方法如表所示;

QEnterEvent的方法 返回值的类型 QEnterEvent的方法 返回值的类型
clone() QEnterEvent pos() QPoint
globalPos() QPoint screenPos() QPointF
globalX() int windowPos() QPointF
globalY() int x() int
localPos() QPointF y() int

当光标离开窗口时,会触发QEvent,Leave 离开事件离开事件的处理函数是 leaveEvent(QEvent)。可以重写这两个函数,以达到特定的目的。

焦点事件 QFocusEvent

一个控件获得键盘焦点时,可以接受键盘的输人。控件获得键盘焦点的方法很多,例如按 Tab 键、鼠标、快捷键等。

  • 当一个控件获得和失去键盘输人焦点时,会触发 QEvent.FocusIn 和QEvent.FocusOut 事件,这两个事件的处理函数分别是 focusInEvent(QFocusEvent)和 focusOutEvent(QFocusEvent)
  • 焦点事件类QFocusEvent 的方法有gotFocus() _lostFocus()和 reason()。
  • 事件类型 type()
    • 当事件类型 type()的值是 QEvent.FocusIn 时gotFocus()方法的返回值是 True,
    • 当事件类型type()的值是QEvent.FocusOut 时lostFocus()方法的返回值是 True;
  • reason()方法返回获得焦点的原因其返回值的类型是Qt.FocusReason,其值 有:
    • Qt.MouseFocusReason
    • Qt.TabFocusReason
    • Qt.BacktabFocusReason
    • Qt.ActiveWindowFocusReason
    • Qt.PopupFocusReason
    • Qt.ShortcutFocusReason
    • Qt.MenuBarFocusReason
    • Qt.OtherFocusReason

关闭事件0CloseEvent

当用户单击窗口右上角的X按钮或执行窗口的 close()方法时,会触发 QEvent,Close事件,调用closeEvent(QCloseEvent)处理该事件。

如果事件用ignore()方法忽略了,则什么也不会发生;

如果事件用accept()方法接收了,首先窗口被隐藏,在窗口设置了setAttribute(Qt.WA_DeleteOnClose,True)属性的情况下,窗口会被删除。

窗口事件类QCloseEvent 没有特殊的属性,只有从 QEvent 继承来的方法。

定时器事件QTimerEvent

从QObject 类继承的窗口和控件都会有startTimer(int,timerType =Qt.CoarseTimer)方法和 killTimer(int)方法。

startTimer()方法会启动一个定时器,并返回定时器的 ID 号。

  • 如果不能启动定时器,则返回值是 0,参数 int 是定时器的事件间隔,单位是毫秒
  • timerType 是定时器的类型,可以取
    • Qt.PreciseTimer
    • Qt.CoarseTimer
    • Qt.VeryCoarseTimer。
  • 窗口或控件可以用startTimer()方法启动多个定时器,启动定时器后,会触发 timerEvent(QTimerEvent)事件,QTimerEvent是定时器事件类。
    • 用QTimerEvent的 timerId()方法可以获取触发定时器事件的定时器ID;
    • 用killTimer(int)方法可以停止定时器,参数是定时器的 ID。

下面的程序启动窗口上的两个定时器,这两个定时器的时间间隔不同,用定时器事件识别是哪个定时器触发了定时器事件,可用按钮停止定时器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 20:29
# File_name: demo.py

from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
from PySide6.QtCore import Qt
import sys


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.ID_1 = self.startTimer(500, Qt.TimerType.PreciseTimer) # 创建第 1个定时器
self.ID_2 = self.startTimer(1000, Qt.TimerType.CoarseTimer) # 创建第2个定时器

btn_1 = QPushButton("停止第1个定时器", self)
btn_2 = QPushButton("停止第2个定时器", self)
btn_1.clicked.connect(self.killTimer_1)
btn_2.clicked.connect(self.killTimer_2)

h = QHBoxLayout(self)
h.addWidget(btn_1)
h.addWidget(btn_2)

def timerEvent(self, event): # 定时器事件
print("我是第" + str(event.timerId()) + "个定时器")

def killTimer_1(self):
if self.ID_1:
self.killTimer(self.ID_1) # 停止第1个定时器
print(f"{'=' * 20}第1个定时器停止{'=' * 20}")

def killTimer_2(self):
if self.ID_2:
self.killTimer(self.ID_2) # 停止第2个定时器
print(f"{'=' * 20}第2个定时器停止{'=' * 20}")


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWidget()

win.show()
sys.exit(app.exec())

事件过滤和自定义事件

前面已讲过,一个控件或窗口的event()函数是所有事件的集合点,可以在event()函数中设置某种类型的事件是接收还是忽略,另外还可以用事件过滤器把某种事件注册给其他控件或窗口进行监控、过滤和拦截。

事件的过滤

一个控件产生的事件可以交给其他控件进行处理,而不是由自身的处理函数处理,原控件称为被监测控件,进行处理事件的控件称为监测控件。要实现这个目的,需要将被监测控件注册给监测控件。

事件过滤器的注册与删除

要把被监测对象的事件注册给监测控件,需要在被监测控件上安装监测器,被监测控件的监测器用installEventFilter(QObject)方法定义,其中QObject 是监测控件。

如果一个控件上安装了多个事件过滤器,则后安装的过滤器先被使用。用removeEventFilter(QObiect)方法可以解除监测。

事件的过滤

要实现对被监测对象事件的过滤需要在监测对象上重写过滤函数 eventFilter(QObject,QEvent),其中参数 QObject 是传递过来的被监测对象,QEent 是被检测对象的事件类对象。

过滤函数如果返回 True,表示事件已经过滤掉了,如果返回 False,表示事件没有被过滤。

事件过滤器的应用实例

下面的程序在两个QFrame控件上分别定义了两个QPushButton 按钮把这两个按钮的事件注册到窗口上,监控按钮的移动事件,如果移动其中的一个按钮,另一个按钮也同步移动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 20:30
# File_name: 01-事件过滤器的应用实例.py

from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QFrame, QHBoxLayout
from PySide6.QtGui import QDrag, QMouseEvent
import sys
from PySide6.QtCore import QMimeData, Qt.QEvent


class MyPushButton(QPushButton):
def __init__(self, parent=None):
super().__init__(parent)

self.setText("MyPushButton")

def mousePressEvent(self, event: QMouseEvent) -> None: # 按键事件
if event.button() == Qt.LeftButton:
self.drag = QDrag(self)
self.drag.setHotSpot(event.position().toPoint())
mime = QMimeData()
self.drag.setMimeData(mime)
self.drag.exec()


class MyFrame(QFrame):
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.setFrameShape(QFrame.Shape.Box)
self.btn = MyPushButton(self)

def dragEnterEvent(self, event):
self.child = self.childAt(event.position().toPoint()) # 获取指定位置的控件
if self.child:
event.accept()
else:
event.ignore()

def dragMoveEvent(self, event):
if self.child:
self.child.move(event.position().toPoint() - self.child.drag.hotSpot())


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupi()
self.resize(600, 400)
self.setAcceptDrops(True)

def setupi(self):
self.frame_1 = MyFrame(self)
self.frame_2 = MyFrame(self)
H = QHBoxLayout(self)
H.addWidget(self.frame_1)
H.addWidget(self.frame_2)

self.frame_1.btn.installEventFilter(self) # 将 btn的事件注册到窗口 self上
self.frame_1.btn.installEventFilter(self) # 将btn的事件注册到窗口 self上

def eventFilter(self, watched, event): # 事件过滤函数
if watched == self.frame_1.btn and event.type() == QEvent.Move:
self.frame_2.btn.move(event.pos())
return True

if watched == self.frame_2.btn and event.type() == QEvent.Move:
self.frame_1.btn.move(event.pos())
return True

return super().eventFilter(watched, event)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

自定义事件

除了可以直接使用PySide6 中标准的事件外,用户还可以自定义事件,指定事件产生的时机和事件的接受者。

自定义事件类

用户定义自己的事件首先要创建一个继承自QEvent 的类,并给自定义事件一个ID号(值),该ID号的值只能在 QEvent,User(值为 1000)和 QEvent,MaxUser(值为 65535)之间,且不能和已有的ID号相同。

为保证ID 号的值不冲突,可以用QEvent 类的静态函数registerEventType(hint;int=-1)注册自定义事件的ID号,并检查给定的ID号是否合适如果ID 号合适,会返回指定的 ID 号值,如果不合适,则推荐一个ID 号值。

在自定义事件类中根据情况定义所需的属性和方法。

自定义信号的发送

需要用QCoreApplication 的 sendEvent(receiver,event)函数或 postEvent(receiver;event)函数发送自定义事件,其中 receiver 是自定义事件的接收者,event 是自定义事件的实例化对象。

用sendEvent(receiver,event)函数发送的自定义事件被QCoreApplication的notify()函数直接发送给 receiver 对象,返回值是事件处理函数的返回值;

用postEvent(receiver,event)函数发送的自定义事件添加到事件队列中,它可以在多线程应用程序中用于在线程之间交换事件

自定义事件的处理函数

控件或窗口上都有个 customEvent(event)丽数,用于处理自定义事件,自定义事件类的实例作为实参传递给形参event,也可以用event(event)函数处理在 customEvent(event)函数或 event(event)函数中根据事件类型进行相应的处理,也可用事件过滤器来处理。

自定义事件的应用实例

下面的程序是建立自定义事件的例子,读者可以通过这个例子了解建立自定义事件的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/2 23:07
# File_name: 02-自定义事件的应用实例.py

from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QFrame, QHBoxLayout
from PySide6.QtGui import QDrag
import sys
from PySide6.QtCore import QMimeData, Qt.QEvent, QCoreApplication


# 自定义事件
class MyEvent(QEvent):
# myID = QEvent,registerEventType(2000)
def __init__(self, position, object_name=None):
super().__init__(QEvent.User)
# super().__init__(MyEvent.myID)

self.__pos = position # 位置属性,可对数据作其他处理
self.__name = object_name # 名称属性

def get_pos(self): # 自定义事件的方法
return self.__pos

def get_name(self): # 自定义事件的方法
return self.__name


class MyPushButton(QPushButton):
def __init__(self, name=None, parent=None, window=None):
super().__init__(parent)

self.setText(name)
self.windowl = window

def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.drag = QDrag(self)
self.drag.setHotSpot(event.position().toPoint())
mime = QMimeData() # 按健事件
self.drag.setMimeData(mime)
self.drag.exec()

def moveEvent(self, event):
self.__customEvent = MyEvent(event.pos(), self.objectName()) # 自定义事件
QCoreApplication.sendEvent(self.window(), self.__customEvent) # 发送事件


class MyFrame(QFrame):
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.setFrameShape(QFrame.Shape.Box)

def dragEnterEvent(self, event):
self.child = self.childAt(event.position().toPoint())
if self.child: # 获取指定位置的控件
event.accept()
else:
event.ignore()

def dragMoveEvent(self, event):
if self.child:
self.child.move(event.position().toPoint() - self.child.drag.hotSpot())


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUi()
self.resize(600, 400)
self.setAcceptDrops(True)

def setupUi(self):
self.frame_1 = MyFrame(self)
self.frame_2 = MyFrame(self)
H = QHBoxLayout(self)
H.addWidget(self.frame_1)
H.addWidget(self.frame_2)

self.btn1 = MyPushButton("PushButton 1", self.frame_1, window=self) # 按钮的名称
self.btn1.setObjectName("button1") # 按钮1

self.btn2 = MyPushButton("PushButton 2", self.frame_1, window=self) # 按钮的名称
self.btn2.setObjectName("button2") # 按钮2

self.btn3 = MyPushButton("PushButton 3", self.frame_2, window=self) # 按钮的名称
self.btn3.setObjectName("button3") # 按钮3

self.btn4 = MyPushButton("PushButton 4", self.frame_2, window=self) # 按钮的名称
self.btn4.setObjectName("button4") # 按钮4

def customEvent(self, event): # 自定义事件的处理函数
if event.type() == MyEvent.User: # if event.type() == MyEvent.myID:
if event.get_name() == "button1":
self.btn3.move(event.get_pos())

if event.get_name() == "button2":
self.btn4.move(event.get_pos())

if event.get_name() == "button3":
self.btn1.move(event.get_pos())

if event.get_name() == "button4":
self.btn2.move(event.get_pos())


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

多线程、线程池、定时器

在一般情况下,应用程序都是单线程运行的,但是对于 GUI程序来说,单线程有时满足不了需求。

例如,如果需要执行一个特别耗时的操作,在执行过程中整个程序就会卡顿,此时用户可能以为程序出错,所以就把程序关闭了;

或者 Widows 系统也认为程序出错,自动关闭程序。要解决这种问题就涉及多线程的知识。

一般来说,多线程技术涉及3种方法:

  • 一是使用计时器模块QTimer
  • 二是使用多线程模块QThread
  • 三是使用事件处理功能。

定时器QTimer

定时器 QTimer 像个闹钟,其作用是经过一个固定的时间间隔发送一个信号,执行与信号连接的槽函数,实现自动完成某些功能。

可以设置定时器只发送一次信号,或多次发送信号;

可以启动发送信号,也可以停止发送信号。

用QTimer 创建定时器的方法如下所示,其中parent 是继承自QObejct 的对象。QTimer 是不可见的,当父类删除时,定时器也同时删除。

1
2
3
from PySide6.QtCore import QTimer

QTimer(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

如果要在应用程序中周期性地执行某个操作,如周期性地检测主机的 CPU值,则需要使用QTimer(定时器),QTimer 类提供了重复的和单次的定时器。

要使用定时器,需要先创建一个QTimer实例,将其 timeout 信号连接到相应的槽,并调用start()函数。

然后定时器会以恒定的间隔发射 timeout 信号。start(2000)表示设置时间间隔为2秒并启动定时器,代码如下:

1
2
3
4
5
6
7
8
from PySide6.QtCore import QTimer

# 初始化一个定时器
self.timer = QTimer(self)
# 计时结束并调用 operate()
# 设置时间间隔并启动定时器
self.timer.timeout.connect(self.operate)
self.timer.start(2000)

在默认情况下,isSingleShot0返回 False,如果返回 True,则计时器信号只会触发一次,可以通过 setSingleShot(True)修改默认值

计时器的另一种使用方法是延迟计时,这种方法要使用 sigleShot 信号(前者是timeout 信号),如 singleShot(5000,receiver)表示5 秒之后会触发 receiver 信号。

定时器QTimer的常用方法

定时器QTimer的常用方法如表所示,主要方法介绍如下

QTimer的方法及参数类型 返回值的类型 说明
setInterval(msec:int) None 设置信号发送的时间间隔(毫秒)
interval() int 获取信号发送的时间间隔(毫秒)
isActive() bool 获取定时器是否激活
remainingTime() int 获取距下次发送信号的时间(毫秒)
setSingleShot(bool) None 设置定时器是否为单次发送
isSingleShot() bool 获取定时器是否为单次发送
setTimerType(atype: Qt.TimerType) None 设置定时器的类型
timerType() Qt.TimerType 获取定时器的类型
[slot]start(msec:int) None 经过msec毫秒后启动定时器
[slot]start() None 启动或重新启动定时器,时间间隔的单位为毫秒。
如果定时器已经运行,那么它将被停止并重新启动。
如果isSingleShot0为True,那么定时器将仅被激活一次
[slot]stop() None 停止定时器
timerId() int 获取定时器的ID号
[static]singleShot(int,Callable) None 经过int毫秒后,调用Python的可执行函数 Callable
[static]singleShot(msec: int, receiver: QObject,member: bytes) None 经过int毫秒后,执行receiver的槽函数 member
[static]singleShot(msec: int, timerType: Qt.TimerType, receiver:QObject,member: bytes) None 经过int毫秒后,执行receiver的槽函数 member
  • 定时器的使用

    • 一般是先建立定时器对象,用setInterval(int)方法设置定时器发送信号的时间间隔,然后将定时器的信号 timeout 与某个槽函数关联最后用start()方法启动定时器。
    • 如果只需要定时器发送1次信号,可以设置 setSingleShot(bool)为True,否则将会连续不断地发送信号,可以用stop()方法停止定时器信号的发送
    • 如果只是 1次发送信号,也可以不用创建定时器对象,用定时器类的静态方法singleShot()直接连接某个控件的槽函数。
    • 如果定义了多个定时器,可以用timeld()方法获取定时器的编号。
  • 定时器的精度

    • 与系统和硬件有关用setTimerType(QtTimerType)方法可以设置定时器的精度,其中参数Qt.TimerType 的取值如表所示

      Qt.TimerType的取值 说 明
      Qt.PreciseTimer 0 精确的定时器,保持1毫秒精度
      Qt.CoarseTimer 1 精确度差的定时器,精度保持在时间间隔的5%范围内
      Qt.VeryCoarseTimer 2 精确度非常差的定时器,精度是500毫秒

定时器QTimer的信号

定时器只有一个信号 timeout(),每经过固定的时间间隔发送一次信号,或者只发送1次信号

也可以自定义信号,给定时间间隔后,在调用一个槽函数时发射信号

定时器QTimer 的应用实例

下面的程序定义了两个定时器,第1个定时器用于窗口背景图片的切换,第2个定时器用于设置按钮激活的时间,并改变按钮显示的文字,这里设置单击按钮后 10 秒激活按钮

image-20230226231742643 image-20230226231641526

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# -*- coding: UTF-8 -*-
# File date: Hi_2023/2/28 22:00
# File_name: 定时器QTimer 的应用实例.py
from PySide6.QtWidgets import QApplication, QWidget, QPushButton
from PySide6.QtGui import QPainter, QPixmap, QBitmap
from PySide6.QtCore import QRect, QTimer
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("定时器")
path = r"../../Resources/animal//m1.png"
self.pix = QPixmap(path)
self.bit = QBitmap(path)
self.rect = QRect(0, 0, self.pix.width(), self.pix.height())
self.resize(self.rect.size())

self.timer_1 = QTimer(self) # 第1个定时器
self.timer_1.setInterval(2000) # 第1个定时器的时间间隔连接
self.timer_1.timeout.connect(self.timer_1_slot) # 第1个定时器信号与槽函数的

self.timer_1.start() # 启动第1个定时器
self.status = True # 指示变量
self.timer_2 = QTimer(self) # 第2个定时器
self.timer_2.setInterval(1000) # 第2个定时器的时间间隔
self.timer_2.timeout.connect(self.pushButton_enable) # 第2个定时器信号与槽函数的连接

self.duration = 9 # 按钮激活时间
self.pushButton = QPushButton("单击发送验证码", self)
self.pushButton.setGeometry(10, 10, 200, 30)
self.pushButton.clicked.connect(self.timer_2.start) # 按钮单击信号与槽函数的#连接

def timer_1_slot(self):
self.status = not self.status
self.update() # 更新窗口会发paintEvent(),调用paintEvent()函数

def paintEvent(self, event): # paintEvent 事件
painter = QPainter(self)

if self.status:
painter.drawPixmap(self.rect, self.pix)
else:
painter.drawPixmap(self.rect, self.bit)

def timer_2_start(self): # 按钮的槽函数
self.timer_2.start()
self.pushButton.setEnabled(False)
self.pushButton.setText(str(self.duration + 1) + "后可重新发送验证码")

def pushButton_enable(self):
if self.duration > 0:
self.pushButton.setText(str(self.duration) + "后可重新发送验证码")
self.duration = self.duration - 1
else:
self.pushButton.setEnabled(True)
self.pushButton.setText("单击发送验证码")
self.timer_2.stop() # 停止定时器
self.duration = 9


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

QThread多线程

Qt中多线程最常用的方法是QThread,QThread是Ot中所有线程控制的基础,每个QThread实例代表并控制一个线程。

QThread 有两种使用方式,子类化或实例化。

  • 子类化QThread 需要重写run0函数并在该函数中进行多线程运算,这种方式相对简单一些;
  • 实例化QThread 需要通过QObject.moveToThread(targetThread:QThread)函数接管多线程类

官方介绍

QThread 对象管理程序中的一个控制线程。QThreads 在 run() 中开始执行。默认情况下,run() 通过调用 exec() 来启动事件循环,并在线程内运行 Qt 事件循环。

您可以通过使用 moveToThread() 将工作器对象移动到线程来使用工作线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Worker(QObject):

Q_OBJECT
# public slots
def doWork(parameter):
result = QString()
/* ... here is the expensive or blocking operation ... */
resultReady.emit(result)

# signals
def resultReady(result):

class Controller(QObject):

Q_OBJECT
workerThread = QThread()
# public
Controller() {
worker = Worker()
worker.moveToThread(workerThread)
workerThread.finished.connect(worker.deleteLater)
self.operate.connect(worker.doWork)
worker.resultReady.connect(self.handleResults)
workerThread.start()

~Controller() {
workerThread.quit()
workerThread.wait()

# public slots
def handleResults():
# signals
def operate():

然后,Worker 插槽中的代码将在单独的线程中执行。

可以自由地将工人的插槽连接到任何线程中来自任何对象的任何信号。跨不同线程连接信号和插槽是安全的,这要归功于一种称为 queued 的机制。

使代码在单独的线程中运行的另一种方法是子类QThread并重新实现run()。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class WorkerThread(QThread):

Q_OBJECT
def run():
result = QString()
/* ... here is the expensive or blocking operation ... */
resultReady.emit(result)

# signals
def resultReady(s):

def startWorkInAThread(self):

workerThread = WorkerThread(self)
workerThread.resultReady.connect(self.handleResults)
workerThread.finished.connect(workerThread.deleteLater)
workerThread.start()

在该示例中,线程将在 run 函数返回后退出。线程中不会运行任何事件循环,除非调用 exec()。

重要的是要记住,QThread 实例是实例化它的旧线程,而不是在调用 run() 的新线程中。这意味着 QThread 的所有排队插槽和调用的方法都将在旧线程中执行。因此,希望在新线程中调用槽的开发人员必须使用工作线程-对象方法;新插槽不应直接实现到子类化的 QThread 中。lives in

与排队的插槽或调用的方法不同,直接在 QThread 对象上调用的方法将在调用该方法的线程中执行。当子类化 QThread 时,请记住构造函数在旧线程中执行,而 run() 在新线程中执行。如果从两个函数访问成员变量,则从两个不同的线程访问该变量。检查这样做是否安全。

管理线程

  • QThread 会在线程start() 和 done() 时发送信号,或者可以使用 isDone() 和 isRunning() 来查询线程的状态。
  • 可以通过调用 exit() 或 quit() 来停止线程。在极端情况下,您可能希望强制终止()正在执行的线程。但是,这样做是危险且不鼓励的。有关详细信息,请阅读 terminate() 和 setTerminationEnabled() 的文档。

从Qt 4.8开始,可以通过将finish()信号连接到deleteLater()来释放刚刚结束的线程中的对象。

使用 wait() 阻止调用线程,直到另一个线程完成执行(或直到指定的时间过去)。

QThread 还提供静态的、独立于平台的睡眠函数:sleep()、msleep() 和 usleep() 分别允许全秒、毫秒和微秒分辨率。这些功能在Qt 5.0中公开。

  • 静态函数和 currentThread() 返回当前正在执行的线程的标识符。前者返回线程的平台特定 ID;后者返回一个 QThread 指针。
  • currentThreadId()要选择将为您的线程指定的名称(例如,由 Linux 上的命令标识),您可以在启动线程之前调用 setObjectName()。如果不调用 setObjectName() ,则为线程指定的名称将是线程对象的运行时类型的类名(例如,在 Mandelbrot 示例的情况下,因为这是 QThread 子类的名称)。请注意,这目前不适用于 Windows 上的发布版本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class WorkThread(QThread):
count = int(0)
countSignal = Signal(int)

def __init__(self):
super(WorkThread, self).init()

def run(self):
self.flag = True
while self.flag:
self.count += 1
self.countSignal.emit(self.count)
time.sleep(1)

# 上述代码的启动方式如下:
if __name__ == '__main__':
self.thread = WorkThread()
self.threadcountSignal.connect(self.flush)
self.label = QLabel('0')
self.thread.start()


def flush(self, count):
self.label.setText(str(count))

用法介绍

实例化代码也需要新建一个类实例化之后需要通过moveToThread()函数让QThread接管,标准模板如下.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/13 21:52
# File_name: 01-实例化多线程模板.py
import time

from PySide6.QtCore import QObject, Signal, QThread


class work(QObject):
count = int(0)
conuntSignal = Signal(int)

def __init__(self):
super().__init__()

def work(self):
self.flag = True
while self.flag:
self.count += 1
self.conuntSignal.emit(self.count)
time.sleep(1)


if __name__ == '__main__':
def flush():
...


worker = work()
thread = QThread()
worker.moveToThread(thread)
worker.conuntSignal.connect(flush)
thread.started.connect(worker.work)
thread.start()

上面是QThread的最基础的用法。
QThread会在线程启动和结束时发射 started 信号和 finished 信号,也可以使用函数isFinished0和isRunning0查询线程的状态。

从Qt4.8开始,可以通过将inished信号连接到 QObject.deleteLater()函数来释放刚刚结束的线程中的对象。

如果要终止线程,则可以使用函数exit()或quit()。

  • 在极端情况下,要使用terminate0函数强制终止正在运行的线程非常危险(并不鼓励这样做)
    • 同时要确保在terminate0函数之后使用wait()函数
  • 使用wait()函数可以阻塞调用线程,直到另一个线程完成执行(或直到经过指定的时间)。
    • 从 Qt 5.0 开始,QThread 还提供了静态的、与平台无关的睡眠函数,如 sleep()、msleep()和 usleep(),分别允许整秒、毫秒和微秒计时。
    • 需要注意的是,一般不使用函数wait()和sleep(),因为Qt是一个事件驱动的框架。
      • 可以使用finished 信号代替 wait()函数
      • 使用QTimer代替 sleep0函数。
  • 使用静态函数currentThreadId()和 currentThread()可以返回当前执行线程的标识符
    • 前者返回线程的平台特定ID,后者返回一个 QThread 指针。

QThread类中常用方法

方法 参数/返回值类型 说明
eventDispatcher() PySide6.QtCore.QAbstractEventDispatcher 返回线程的事件分派器对象的指针。如果线程不存在事件分派器,则此函数返回None。
exec() int 进入事件循环并等待,直到调用exit(),返回传递给exit(的值。如果通过quit()调用exit(),则返回的值为0。
此函数旨在从run()内调用。需要调用此函数来启动事件处理。
exec_() int 已经启用调用exec()
isFinished() bool 如果线程完成,则返回true;否则返回false。
isInterruptionRequested() bool 如果应停止此线程上运行的任务,则返回true。
可以通过requestInterrupt()请求中断。
此函数可用于使长时间运行的任务完全可中断。从不检查或执行此函数返回的值是安全的,但建议在长时间运行的函数中定期执行此操作。注意不要经常打电话,以保持开销低。
isRunning() bool 如果线程正在运行,则返回true;否则返回false。
loopLevel() int 返回线程的当前事件循环级别。
priority() priority 返回正在运行的线程的优先级(见下表)。如果线程未运行,则此函数返回InheritPriority。
requestInterruption() 请求线程中断。该请求是建议性的,由线程上运行的代码决定是否以及如何响应该请求。此函数不会停止线程上运行的任何事件循环,也不会以任何方式终止它。
setEventDispatcher(eventDispatcher) eventDispatcher – PySide6.QtCore.QAbstractEventDispatcher 将线程的事件分派器设置为eventDispatcher。只有在尚未为线程安装事件分派器的情况下,这才是可能的。
当QCoreApplication被实例化时,会自动为主线程创建事件分派器,并在辅助线程的start()上创建事件分派程序。
此方法获取对象的所有权。
setPriority(priority) priority – Priority 此函数设置正在运行的线程的优先级。如果线程未运行,则此函数不执行任何操作并立即返回。使用start()启动具有特定优先级的线程。
优先级参数可以是QThread::priority枚举中的任何值,InheritPriority除外。
优先级参数的效果取决于操作系统的调度策略。特别是,在不支持线程优先级的系统上(例如在Linux上,请参见
setStackSize(stackSize) stackSizeuint 将线程的最大堆栈大小设置为stackSize。如果stackSize大于零,则最大堆栈大小设置为stackSize字节,否则最大堆栈大小由操作系统自动确定。
stackSize() uint 返回线程的最大堆栈大小(如果使用setStackSize()设置);否则返回零。
wait([deadline=QDeadlineTimer(QDeadlineTimer.Forever)]) PARAMETERS
deadline – PySide6.QtCore.QDeadlineTimer

RETURN TYPE
bool
阻塞线程,直到满足以下任一条件:
与此QThread对象关联的线程已完成执行(即,当它从run()返回时)。如果线程完成,此函数将返回true。如果线程尚未启动,它也会返回true。
截止日期已到。如果达到最后期限,此函数将返回false。
设置为QDeadlineTimer::Forever(默认值)的截止时间计时器永远不会超时:在这种情况下,该函数仅在线程从run()返回或线程尚未启动时返回。
这提供了与POSIX pthread_join()函数类似的功能。
wait(time) PARAMETERS
deadline – PySide6.QtCore.QDeadlineTimer

RETURN TYPE
bool
阻塞线程,直到满足以下任一条件:其他同上
run() 线程的起点。调用start()后,新创建的线程将调用此函数。默认实现只调用exec()。
您可以重新实现此函数以促进高级线程管理。从该方法返回将结束线程的执行。
[Slots]exit([retcode=0]) retcode – int 告诉线程的事件循环退出并返回代码。
调用此函数后,线程离开事件循环,并从对exec()的调用中返回。exec()函数返回returnCode。
按照惯例,returnCode为0表示成功,任何非零值表示错误。
请注意,与同名的C库函数不同,此函数确实会返回到调用者——停止的是事件处理。
在再次调用exec()之前,此线程中不会再启动QEventLoops。如果exec()中的事件循环未运行,那么下一次对exec(的调用也将立即返回。
[Slots]quit() 告诉线程的事件循环退出,返回代码为0(成功)。相当于调用出口(0)。
如果线程没有事件循环,则此函数不起作用。
[Slots]start([priority=QThread.Priority.InheritPriority]) priority – Priority 通过调用run()开始执行线程。操作系统将根据优先级参数调度线程。如果线程已经在运行,则此函数不执行任何操作。
优先级参数的效果取决于操作系统的调度策略。特别是,在不支持线程优先级的系统上(如在Linux上,请参阅sched_setscheduler文档以了解更多详细信息),优先级将被忽略。
[Slots]terminate() 终止线程的执行。根据操作系统的调度策略,线程可能会立即终止,也可能不会立即终止。请务必在terminate()之后使用wait()。
当线程终止时,等待线程完成的所有线程都将被唤醒。
此功能很危险,不鼓励使用。线程可以在其代码路径的任何位置终止。修改数据时可以终止线程。线程没有机会自行清理、解锁任何持有的互斥锁等。简而言之,只有在绝对必要时才使用此函数。
可以通过调用setTerminationEnabled()显式启用或禁用终止。在禁用终止时调用此函数会导致延迟终止,直到重新启用终止。有关详细信息,请参阅setTerminationEnabled()的文档。
[Static]currentThread() PySide6.QtCore.QThread 返回指向管理当前执行线程的QThread的指针。
[Static]idealThreadCount() int 返回此进程可以并行运行的理想线程数。这是通过查询此进程可用的逻辑处理器的数量(如果此操作系统支持)或系统中逻辑处理器的总数来完成的。如果两个值都无法确定,则此函数返回1。
[Static]msleep(arg__1) arg__1 – int 强制当前线程休眠毫秒。
如果需要等待给定条件发生变化,请避免使用此函数。相反,将插槽连接到指示更改的信号或使用事件处理程序(请参阅event())。
此功能不能保证准确性。在重载条件下,应用程序的休眠时间可能超过毫秒。一些操作系统可能将毫秒舍入为10毫秒或15毫秒。
[Static]setTerminationEnabled([enabled=true]) enabled – bool 根据启用的参数启用或禁用当前线程的终止。该线程必须已由QThread启动。
如果启用为false,则禁用终止。以后对terminate()的调用将立即返回而不起作用。相反,将延迟终止,直到启用终止。
如果启用为true,则启用终止。以后调用terminate()将正常终止线程。如果终止被延迟(即,在禁用终止的情况下调用terminate()),则此函数将立即终止调用线程。请注意,在这种情况下,此函数不会返回。
[Static]sleep(arg__1) arg__1 – int 强制当前线程休眠秒。
如果需要等待给定条件发生变化,请避免使用此函数。相反,将插槽连接到指示更改的信号或使用事件处理程序(请参阅event())。
此功能不能保证准确性。在重载条件下,应用程序可能会休眠超过秒。
[Static]usleep(arg__1) arg__1 – int 强制当前线程休眠usecs微秒。
如果需要等待给定条件发生变化,请避免使用此函数。相反,将插槽连接到指示更改的信号或使用事件处理程序(请参阅event())。
此功能不能保证准确性。在重载条件下,应用程序可能比usecs休眠更长时间。一些操作系统可能将usecs舍入到10ms或15ms;在Windows上,它将舍入为1ms的倍数。
[Static]yieldCurrentThread() 将当前线程的执行交给另一个可运行的线程(如果有的话)。
注意,操作系统决定切换到哪个线程。
  • 优先级枚举值PySide6.QtCore.QThread.Priority
    此枚举类型指示操作系统应如何调度新创建的线程。

    Constant Description
    QThread.IdlePriority 仅在没有其他线程运行时计划。
    QThread.LowestPriority 计划频率低于低优先级。
    QThread.LowPriority 计划频率低于正常优先级。
    QThread.NormalPriority 操作系统的默认优先级。
    QThread.HighPriority 比正常优先级更频繁地安排。
    QThread.HighestPriority 比高优先级更频繁地安排。
    QThread.TimeCriticalPriority 尽可能频繁地安排。
    QThread.InheritPriority 使用与创建线程相同的优先级。这是默认值。

QThread类信号

信号 说明
finished() 该信号在相关线程完成执行之前从其发出。
发出此信号时,事件循环已停止运行。除延迟删除事件外,线程中不会再处理其他事件。该信号可以连接到deleteLater(),以释放该线程中的对象。
如果使用terminate()终止了关联的线程,则不确定该信号是从哪个线程发出的。
started() 当相关线程开始执行时,在调用run()函数之前,该信号从该线程发出。

QThread的使用方法

本案例涉及两个文件,两个脚本的功能是一样的,只是实现方法稍微不同,前者采用子类化的方式,后者采用实例化的方式,内容稍微不同,

QThread 子类化的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/13 22:33
# File_name: 02- QThread 子类化的使用.py


from PySide6.QtCore import Signal, QThread, Qt
from PySide6.QtWidgets import QMainWindow, QWidget, QLabel, QApplication, QPushButton, QHBoxLayout
from PySide6.QtGui import QFont
import sys
import time


class WorkThread(QThread):
count = int(0)
countSignal = Signal(int)

def __init__(self):
super(WorkThread, self).__init__()

def run(self):
self.flag = True
while self.flag:
self.count += 1
self.countSignal.emit(self.count)
time.sleep(1)


class MainWindow(QMainWindow):

def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('QThread demo')
self.resize(515, 208)
self.widget = QWidget()
self.buttonStart = QPushButton('开始')
self.buttonStop = QPushButton('结束')
self.label = QLabel('0')
self.label.setFont(QFont("Adobe Arabic", 28))
self.label.setAlignment(Qt.AlignCenter)

layout = QHBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.buttonStart)
layout.addWidget(self.buttonStop)
self.widget.setLayout(layout)
self.setCentralWidget(self.widget)

self.buttonStart.clicked.connect(self.onStart)
self.buttonStop.clicked.connect(self.onStop)

self.thread = WorkThread()
self.thread.countSignal.connect(self.flush)

self.thread.started.connect(lambda: self.statusBar().showMessage('多线程started信号'))
self.thread.finished.connect(self.finished)

def flush(self, count):
self.label.setText(str(count))

def onStart(self):
self.statusBar().showMessage('button start.')
print('button start.')
self.buttonStart.setEnabled(False)
self.thread.start()

def onStop(self):
self.statusBar().showMessage('button stop.')
self.thread.flag = False
self.thread.quit()

def finished(self):
self.statusBar().showMessage('多线程finish信号')
self.buttonStart.setEnabled(True)


if __name__ == "__main__":
app = QApplication(sys.argv)
demo = MainWindow()
demo.show()
sys.exit(app.exec())

QThread实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/13 22:33
# File_name: 03- QThread实例化.py


from PySide6.QtCore import Signal, QObject, QThread, Qt
from PySide6.QtWidgets import QMainWindow, QWidget, QLabel, QApplication, QPushButton, QHBoxLayout
from PySide6.QtGui import QFont
import sys
import time


class Work(QObject):
count = int(0)
countSignal = Signal(int)

def __init__(self):
super(Work, self).__init__()

def work(self):
self.flag = True
while self.flag:
self.count += 1
self.countSignal.emit(self.count)
time.sleep(1)


class MainWindow(QMainWindow):

def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('QThread demo')
self.resize(515, 208)
self.widget = QWidget()
self.buttonStart = QPushButton('开始')
self.buttonStop = QPushButton('结束')
self.label = QLabel('0')
self.label.setFont(QFont("Adobe Arabic", 28))
self.label.setAlignment(Qt.AlignCenter)

layout = QHBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.buttonStart)
layout.addWidget(self.buttonStop)
self.widget.setLayout(layout)
self.setCentralWidget(self.widget)

self.buttonStart.clicked.connect(self.onStart)
self.buttonStop.clicked.connect(self.onStop)

self.thread = QThread()
self.worker = Work()
self.worker.countSignal.connect(self.flush)

self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.work)
self.thread.finished.connect(self.finished)

def flush(self, count):
self.label.setText(str(count))

def onStart(self):
self.statusBar().showMessage('button start.')
self.buttonStart.setEnabled(False)
self.thread.start()

def onStop(self):
self.statusBar().showMessage('button stop.')
self.worker.flag = False
self.thread.quit()

def finished(self):
self.statusBar().showMessage('多线程finish.')
self.buttonStart.setEnabled(True)


if __name__ == "__main__":
app = QApplication(sys.argv)
demo = MainWindow()
demo.show()
sys.exit(app.exec())

事件处理

Q为事件处理提供了两种机制:高级的信号/槽机制,低级的事件处理机制。

本节只介绍事件处理机制的processEvents()函数的使用方法,因为这个函数能够实现实时刷新,表现形式就像多线程一样。详细介绍信号/槽机制和事件处理机制的具体用法可以在其他章节查看。

虽然使用processEvents()函数可以刷新页面,但是一般不建议这样操作,而是把耗时的操作放到子线程中。

对于执行很耗时的程序来说,PySide6需要等待程序执行完毕才能进行下一步,这个过程表现在界面上就是卡顿;

如果在执行这个耗时的程序时不断运行 QApplication processEvents()函数,那么就可以实现一边执行耗时的程序,一边刷新页面的功能,给人的感觉就是程序运行很流畅。

因此,QApplication.processEvents)函数的使用方法就是,在主函数执行耗时操作的地方加入 QApplication.processEvents()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/13 23:13
# File_name: 04-processEvents例子.py


from PySide6.QtWidgets import QWidget, QPushButton, QApplication, QListWidget, QGridLayout
import sys
import time


class WinForm(QWidget):

def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
self.setWindowTitle("实时刷新界面例子")
self.listFile = QListWidget()
self.btnStart = QPushButton('开始')
layout = QGridLayout(self)
layout.addWidget(self.listFile, 0, 0, 1, 2)
layout.addWidget(self.btnStart, 1, 1)
self.btnStart.clicked.connect(self.slotAdd)
self.setLayout(layout)

def slotAdd(self):
for n in range(10):
str_n = 'File index {0}'.format(n)
self.listFile.addItem(str_n)
QApplication.processEvents()
time.sleep(1)


if __name__ == "__main__":
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec())

线程池

QThreadPool

img

QThreadPool管理和回收单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。

每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问该对象。

1
2
3
from PySide6.QtCore import QThreadPool

QThreadPool(parent: Union[PySide6.QtCore.QObject, NoneType] = None) -> None

要使用QThreadPool线程之一,请子类QRunable并实现run()虚拟函数。然后创建该类的对象并将其传递给start()。

1
2
3
4
5
6
7
8
9
10
class HelloWorldTask(QRunnable):

def run():

print("Hello world from thread", QThread.currentThread())


hello = HelloWorldTask()
# QThreadPool takes ownership and deletes 'hello' automatically
QThreadPool.globalInstance().start(hello)
  • 默认情况下,QThreadPool 会自动删除 QRunnable。使用 setAutoDelete() 更改自动删除标志。

  • QThreadPool 支持通过从 run() 中调用 tryStart(this) 多次执行相同的 QRunnable。

    • 如果启用了自动删除,则当最后一个线程退出运行函数时,将删除 QRunnable。
    • 启用自动删除时,使用相同的 QRunnable 多次调用 start() 会产生争用条件,不建议这样做。
  • 在一定时间内未使用的线程将过期。默认到期超时为 30000 毫秒(30 秒)。这可以使用 setExpiryTimeout() 进行更改。设置负到期超时将禁用到期机制。

  • 调用 maxThreadCount() 查询要使用的最大线程数。如果需要,您可以使用 setMaxThreadCount() 更改限制。默认的 maxThreadCount() 是 idealThreadCount() 。activeThreadCount() 函数返回当前正在工作的线程数。

  • reserveThread() 函数保留一个线程供外部使用。当你完成线程时,请使用 releaseThread(),以便可以重用它。从本质上讲,这些功能会暂时增加或减少活动线程计数,并且在实现 QThreadPool 不可见的耗时操作时很有用。

请注意,QThreadPool 是用于管理线程的低级类,有关更高级别的替代方案,请参阅 Qt 并发模块。

方法 说明
activeThreadCount() 此属性保存线程池中活动线程的数量。。
clear() 从队列中删除尚未启动的可运行文件。runnable->autoDelete()返回true的可运行文件将被删除。
contains(thread) 如果线程是由该线程池管理的线程,则返回true。
expiryTimeout() 此属性以毫秒为单位保存线程过期超时值。。
在expiryTimeout毫秒内未使用的线程被视为已过期并将退出。这些线程将根据需要重新启动。默认expiryTimeout为30000毫秒(30秒)。如果expiryTimeout为负,则新创建的线程不会过期,例如,在线程池被销毁之前,它们不会退出。
注意,设置expiryTimeout对已经运行的线程没有影响。只有新创建的线程才会使用新的expiryTimeout。我们建议在创建线程池之后,但在调用start()之前立即设置expiryTimeout
maxThreadCount() 此属性保存线程池使用的最大线程数。在创建QThreadPool对象时,此属性将默认为idealThreadCount()的值。
releaseThread() 释放先前通过调用reservedThread()保留的线程。
reserveThread() 保留一个线程,忽略activeThreadCount()和maxThreadCount(()。完成线程后,调用releaseThread()以允许重用它。
即使保留maxThreadCount()线程或更多线程,线程池仍将允许至少一个线程。
此函数将增加报告的活动线程数。这意味着通过使用此函数,activeThreadCount()可以返回一个大于maxThreadCount(()的值。
setExpiryTimeout(expiryTimeout) 此属性以毫秒为单位保存线程过期超时值。。
在expiryTimeout毫秒内未使用的线程被视为已过期并将退出。这些线程将根据需要重新启动。默认expiryTimeout为30000毫秒(30秒)。如果expiryTimeout为负,则新创建的线程不会过期,例如,在线程池被销毁之前,它们不会退出。
注意,设置expiryTimeout对已经运行的线程没有影响。只有新创建的线程才会使用新的expiryTimeout。我们建议在创建线程池之后,但在调用start()之前立即设置expiryTimeout
setMaxThreadCount(maxThreadCount) 此属性保存线程池使用的最大线程数。在创建QThreadPool对象时,此属性将默认为idealThreadCount()的值。
线程池将始终至少使用1个线程,即使maxThreadCount限制为零或负。
setStackSize(stackSize) 此属性保存线程池工作线程的堆栈大小。。
该属性的值仅在线程池创建新线程时使用。更改它对已创建或正在运行的线程无效。
默认值为0,这使QThread使用操作系统默认堆栈大小。
setThreadPriority(priority) 此属性保存新工作线程的线程优先级。。
该属性的值仅在线程池启动新线程时使用。更改它对已经运行的线程没有影响。
默认值为InheritPriority,这使QThread使用与QThreadPool对象所在的优先级相同的优先级。
stackSize() 此属性保存线程池工作线程的堆栈大小。。
该属性的值仅在线程池创建新线程时使用。更改它对已创建或正在运行的线程无效。
默认值为0,这使QThread使用操作系统默认堆栈大小。
start(arg__1[, priority=0]) arg__1 – PyCallable
priority – int
start(runnable[, priority=0]) runnable – PySide6.QtCore.QRunnable
priority – int
保留一个线程并使用它来运行可运行的线程,除非该线程将使当前线程计数超过maxThreadCount()。在这种情况下,runable将被添加到运行队列中。优先级参数可用于控制运行队列的执行顺序。
注意,如果runnable->autoDelete()返回true,线程池将拥有可运行文件的所有权,并且在runnable->run()返回后,线程池会自动删除可运行文件。如果runnable->autoDelete()返回false,则runnable的所有权仍属于调用者。请注意,在调用此函数后更改runable上的自动删除会导致未定义的行为。
startOnReservedThread(runnable) runnable – PySide6.QtCore.QRunnable
释放先前使用reserveThread()保留的线程,并使用它运行可运行的线程。
注意,如果runnable->autoDelete()返回true,线程池将拥有可运行文件的所有权,并且在runnable->run()返回后,线程池会自动删除可运行文件。如果runnable->autoDelete()返回false,则runnable的所有权仍属于调用者。请注意,在调用此函数后更改runable上的自动删除会导致未定义的行为。
threadPriority() 此属性保存新工作线程的线程优先级。。
该属性的值仅在线程池启动新线程时使用。更改它对已经运行的线程没有影响。
默认值为InheritPriority,这使QThread使用与QThreadPool对象所在的优先级相同的优先级。
tryStart(arg__1) RETURN TYPE bool
tryStart(runnable) arg__1 – PyCallable
RETURN TYPE bool
tryTake(runnable) PARAMETERS runnable – PySide6.QtCore.QRunnable
RETURN TYPE bool
如果指定的可运行文件尚未启动,则尝试将其从队列中删除。如果runnable尚未启动,则返回true,runnable的所有权将转移给调用者(即使runnable->autoDelete()=true)。否则返回false。
如果runnable->autoDelete()=true,则此函数可能会删除错误的runnable。这被称为ABA问题:原始的可运行文件可能已经执行,并且已经被删除。内存被重新用于另一个可运行文件,然后将其移除,而不是预期的。因此,我们建议仅对非自动删除的可运行文件调用此函数。
waitForDone([msecs=-1]) msecs – int
RETURN TYPE bool
等待所有线程退出并从线程池中删除所有线程,最长为毫秒。如果删除了所有线程,则返回true;否则返回false。如果毫秒为-1(默认值),则忽略超时(等待最后一个线程退出)。
[Static]globalInstance() RETURN TYPE PySide6.QtCore.QThreadPool
返回全局QThreadPool实例。

QRunnable

QRunnable 类是所有可运行对象的基类。

QRunnable 类是一个接口,用于表示需要执行的任务或代码段,由 run() 函数的重新实现表示。

您可以使用 QThreadPool 在单独的线程中执行代码。如果 autoDelete() 返回(默认值),QThreadPool 会自动删除 QRunnable。使用 setAutoDelete() 更改自动删除标志。true

QThreadPool 支持通过在 run() 函数中调用 tryStart(this) 多次执行相同的 QRunnable。如果启用了自动删除,则当最后一个线程退出运行函数时,将删除 QRunnable。启用自动删除时,使用相同的 QRunnable 多次调用 start() 会产生争用条件,不建议这样做。

1
2
3
from PySide6.QtCore import QRunnable

QRunnable(self) -> None
方法 说明
autoDelete() RETURN TYPE bool
如果启用自动删除,则返回true;否则为false。
如果启用了自动删除,QThreadPool将在调用run()后自动删除此可运行文件;否则,所有权仍属于应用程序程序员。
setAutoDelete(autoDelete:bool) 如果autoDelete为true,则启用自动删除;否则将禁用自动删除。
如果启用了自动删除,QThreadPool将在调用run()后自动删除此可运行文件;否则,所有权仍属于应用程序程序员。
注意,必须在调用start()之前设置此标志。在start()之后调用此函数会导致未定义的行为。
run() 在子类中实现这个纯虚拟函数。

QPainter和Graphics/View绘图

绘图是指在绘图设备(窗口、控件、图像、打印机等)上将用户构思出的图形绘制出来,图形包括点、线、矩形、多边形、椭圆、文字及保存到磁盘上的图像等。

可以对绘制的图形进行处理如给封闭的图形填充颜色。

PySide6中绘制图形有两种方式,一种是用QPainter类来绘图,另一种是用Graphics/View 框架来绘图。

  • QPainter 绘图是过程性绘图,Graphics/View框架绘图是面向对象的绘图;
  • QPainter 绘制的图形不能选择和再编辑Graphics/View框架绘制的图形可以选择移动和编辑;
  • QPainter 绘图是Graphics/View 绘图的基础。Graphics/View框架可以自定义图项(QGraphicsItem),在自定义图项中用QPainter绘制自己的图形,形成面向对象的图项,进而形成用户自定义的控件

QPainter绘图

QPainter 是基本的绘图方法,可以绘制各种各样的图形、文字和图像,可以用渐变色填充区域。同时 QPainter 绘图方法是 Graphics/View 绘图框架的基础。

QPainter类

利用QPainer 类可以在绘图设备上绘制图片,文字和几何形状,几何形状有点、线、矩形、椭圆、弧形、弦形、饼图、多边形和贝塞尔曲线等。

绘图设备是从 QPaintDevice 继承的类,包括继承自QWidget 的窗口各种控件QPixmap 和 Qlmage。

如果绘图设备是窗口或控件,则QPainter 绘图一般放到 paintEvent()事件或者被 paintEvent()事件调用的函数中用QPainter 类创建

绘图实例的方法如下其中QPaintDevice 是指继承自QPaintDevice的绘图设备。

如果使用不带设备的 QPainter()方法创建实例对象,例如 painter=QPainter(),则在开始绘图前需要用painter,begin(QPaintDevice)方法指定绘图设备,此时painter.isActive()的返回值是 True绘图完成后,需要用painter.end()方法声明完成绘图,之后可以用begin()方法重新指定绘图设备。begin()和 end()方法都返回 bool值。

1
2
3
4
from PySide6.QtGui import QPainter

QPainter(self) -> None
QPainter(arg__1: PySide6.QtGui.QPaintDevice) -> None
QPainter 状态设置的方法
QPainter的状态设置方法及参数类型 说明
setBackground(bg: Union[QBrush,Qt.BrushStyle,Qt.GlobalColor, QColor,QGradient,QImage,QPixmap]) 设置背景色,背景色只对不透明 的文字、虚线或位图起作用
setBackgroundMode(mode:Qt.BGMode) 设置透明或不透明背景模式
setBrush(brush:Union[QBrush,Qt.BrushStyle, Qt.GlobalColor, QColor,QGradient,QImage,QPixmap]) 设置画刷
setBrush(style:Qt.BrushStyle) 设置画刷
setBrushOrigin(Union[QPointF,QPoint,QPainterPath.Element]) 设置画刷的起点
setBrushOrigin(x:int,y:int) 设置画刷的起点
setClipPath(QPainterPath,op:Qt.ClipOperation=Qt.ReplaceClip) 设置剪切路径
setClipRect(QRect,op:Qt.ClipOperation=Qt.ReplaceClip) 设置剪切矩形区域
setClipRect(Union[QRectF,QRect],op=Qt.ReplaceClip) 设置剪切矩形区域
setClipRect(x: int,y: int,w: int,h:int,op=Qt.ReplaceClip) 设置剪切矩形区域
setClipRegion(Union[QRegion,QBitmap, QPolygon,QRect],op: Qt.ClipOperation=Qt.ReplaceClip) 设置剪切区域:
setClipping(enable:bool) 设置是否启动剪切
setCompositionMode(mode:QPainter.CompositionMode) 设置图形合成模式
setFont(f:Union[QFont,str,Sequence[str]]) 设置字体
setLayoutDirection(direction:Qt.LayoutDirection) 设置布局方向
setOpacity(opacity:float) 设置不透明度
setPen(color: Union[QColor,Qt.GlobalColor,str]) 设置钢笔
setPen(pen: Union[QPen,Qt.PenStyle,QColor]) 设置钢笔
setPen(style: Qt.PenStyle) 设置钢笔
setRenderHint(hint: QPainter.RenderHint,on:bool=True) 设置渲染模式,例如抗锯齿
setRenderHints(hints:QPainter.RenderHints,on: bool=True) 设置多个渲染模式
setTransform(transform:QTransform,combine: bool=False) 设置全局变换矩阵
setWorldTransform(matrix: QTransform,combine: bool=False) 设置全局变换矩阵
setViewTransformEnabled(enable:bool) 设置是否启动视口变换
setViewport(viewport: QRect) 设置视口
setViewport(x:int,y:int.w:int,h:int) 设置视口
setWindow(window:QRect) 设置逻辑窗口
setWindow(x: int,y: int,w:int,h:int) 设置逻辑窗口
setWorldMatrixEnabled(enabled: bool) 设置是否启动全局矩阵变换
save() 保存状态到堆栈中
restore() 从堆栈中恢复状态
  • isActive() 函数指示画家是否处于活动状态。
    • 画家由 begin() 函数和采用QPaintDevice 参数的构造函数激活。
    • end() 函数和析构函数将其停用。
  • font() 是用于绘制文本的字体。如果画家是 Active() ,则可以分别使用fontInfo() 和 fontMetrics() 函数检索有关当前设置的字体及其度量的信息。
  • brush() 定义用于填充形状的颜色或图案。
  • pen() 定义用于绘制线条或边界的颜色或点画。
  • backgroundMode() 定义是否存在 background(),即它是 or 或 。OpaqueMode TransparentMode
  • background() 仅在 backgroundMode() 为 而 pen() 为 stipple 时才适用。在这种情况下,它描述了小节中背景像素的颜色。OpaqueMode
  • brushOrigin() 定义了平铺画笔的原点,通常是小部件背景的原点。
  • viewport() , window() , worldTransform() 构成了画家的坐标变换系统。有关详细信息,请参阅坐标系文档。Coordinate Transformations
  • hasClipping() 告诉画家是否剪辑。(绘画装置也会夹住。如果画家剪辑,它会剪辑到剪辑区域()。
  • layoutDirection() 定义绘制者在绘制文本时使用的布局方向。
  • worldMatrixEnabled() 指示是否启用了世界转换。
  • viewTransformEnabled() 指示是否启用了视图转换。
用QPainter 绘制五角星的实例

下面先举一个用QPainter 绘制五角星的实例,实例中计算

  • 5个顶点的坐标,用QPainter绘制折线方法

  • drawPolyline()绘制五角星并在每个顶点上绘制名称

    image-20230306233158729

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/6 23:23
# File_name: 01-用QPainter绘制五角星的实例.py


import sys, math
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPen, QPainter
from PySide6.QtCore import QPointF
from math import cos, sin, pi


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 500)
self.painter = QPainter()

def paintEvent(self, event):
if self.painter.begin(self):
font = self.painter.font()
font.setPixelSize(20)
self.painter.setFont(font) # 设置字体

pen = QPen() # 钢笔
pen.setWidth(5) # 线条宽度
self.painter.setPen(pen) # 设置钢笔
r = 100 # 五角星的外接圆半径

x = self.width() / 2
y = self.height() / 2
p1 = QPointF(r * cos(-90 * pi / 180) + x, r * sin(-90 * pi / 180) + y)
p2 = QPointF(r * cos(-18 * pi / 180) + x, r * sin(-18 * pi / 180) + y)
p3 = QPointF(r * cos(54 * pi / 180) + x, r * sin(54 * pi / 180) + y)
p4 = QPointF(r * cos(126 * pi / 180) + x, r * sin(126 * pi / 180) + y)
p5 = QPointF(r * cos(198 * pi / 180) + x, r * sin(198 * pi / 180) + y)

self.painter.drawPolyline([p1, p3, p5, p2, p4, p1]) # 绘制折线
self.painter.drawText(p1, "p1") # 绘制文字
self.painter.drawText(p2, "p2")
self.painter.drawText(p3, "p3")
self.painter.drawText(p4, "p4")
self.painter.drawText(p5, "p5")

if self.painter.isActive():
self.painter.end()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

钢笔QPen的用法

钢笔 QPen 用于绘制线条,线条有样式(实线、虚线、点虚线)、颜色、宽度等属性用QPainter 的 setPen(QPen)方法为 QPainter 设置钢笔。

用QPen 创建钢笔的方法如下

  • s是QtPenStyle的举值用于设置钢笔的样式;
  • 画刷 brush 可以用QBrush,QColorQt.GlobalColor和 QGradient 来设置;
  • c是 Qt.PenCapStyle 的枚举值,用于设置线条端点样式;
  • j是Qt.PenJoinStyle 的枚举值,用于设置线条连接点处的样式。
  • 钢笔默认的颜色是黑色,宽度是1像素,样式是实线,端点样式是 Qt.SquareCap,连接处是 Qt.BevelJoin。
1
2
3
4
5
6
7
from PySide6.QtGui import QPen

QPen(self) -> None
QPen(arg__1: PySide6.QtCore.Qt.PenStyle) -> None
QPen(brush: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap], width: float, s: PySide6.QtCore.Qt.PenStyle = Instance(Qt.SolidLine), c: PySide6.QtCore.Qt.PenCapStyle = Instance(Qt.SquareCap), j: PySide6.QtCore.Qt.PenJoinStyle = Instance(Qt.BevelJoin)) -> None
QPen(color: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int]) -> None
QPen(pen: Union[PySide6.QtGui.QPen, PySide6.QtCore.Qt.PenStyle, PySide6.QtGui.QColor]) -> None
钢笔QPen的常用方法

钢笔QPen的常用方法如表所示,主要方法介绍如下

QPen的方法及参数类型 > 说 明
setStyle(Qt.PenStyle) 设置线条样式
style() 获取线条样式
setWidth(int)、setWidthF(float) 设置线条宽度
widtb()、widthF() 获取线条宽度
isSolid() 获取线条样式是否是实线填充
setBrush(brush:Union[QBrush, Qt.BrushStyle, QColor, Qt.GlobalColor,QGradient,QImage,QPixmap]) 设置画刷
brusb() 获取画刷 QBrush
setCapStyle(Qt.PenCapStyle) 设置线端部的样式
capStyle() 获取线端部的样式 Qt.PenCapStyle
setColor(Union[QColor,Qt.GlobalColor,str,int]) 设置颜色
color() 获取颜色QColor
setCosmetic(cosmetic:bool) 设置是否进行装饰
isCosmetic() 获取是否进行装饰
setDashOffset(doffset: float) 设置虚线开始绘制的点与线起始点的距离
setDashPattern(pattern:Sequence[float]) 设置用户自定义虚线样式
dashPattern() 获取自定义样式
setJoinStyle(Qt.PenJoinStyle) 设置两相交线连接点处的样式
setMiterLimit(float) 设置斜接延长线的长度
  • 线条的宽度用setWidth(int)或 setWidthF(float)方法设置

    • 如果宽度始终为0,表示是装饰线条;
    • 装饰线条也可用setCosmetic(bool)方法设置。
  • 装饰线条是指具有恒定宽度的边,可确保线条在不同缩放比例下具有相同的宽度。

    • 线条的样式用setStyle(Qt.PenStyle)方法设置参数 Qt.PenStyle可取的值如表所示

      Qt.PenStyle的取值 说明 Qt.PenStyle的取值 说 明
      Qt.NoPen 0 不绘制线条 Qt.DashDotLine 4 点画线
      Qt.SolidLine 1 实线 Qt.DashDotDotLine 5 双点画线
      Qt.DashLine 2 虚线 Qt.CustomDashLine 6 自定义线
      Qt.DotLine 3 点线
    • 其中自定义样式需要用setDashPattern(Sequence[float])方法设置,这些样式的外观如图所示。

      image-20230306233921226

    • 钢笔的端点样式用SetCapStyle(Qt.PenCapStyle)方法设置,其中参数 Qt.PenCapStyle可取以下值,这些样式的区别如图所示。

      image-20230306234107667

      • Qt.FlatCap 不包含端点
      • Qt.SquareCap 包含端点,并延长半个宽度。
      • Qt.RoundCap
    • 两个线条连接点处的样式用setJoinStyle(QtPenJoinStyle)方法设置,其中参数Qt.PenJoinStyle 可取以下值,样式如图所示。

      image-20230306234250215

      • Qt.MiterJoin

      • Qt.BevelJoin

      • Qt.RoundJoin

      • Qt.SvgMiterJoin

      • 当线条连接样式是Qt.MiterJoin 时,用setMiterLimit(float)方法设置延长线的长度其中参数 float 是线条宽度的倍数,默认是 20其延长线的含义如图所示:

        img

    • 用setDashPattern(Sequence[float])方法可以自定义虚线样式,其中参数的奇数项表示实线的长度,偶数项表示空白处的长度,长度以线宽为单位表示为线宽的倍数。

      • 例如 setDashPattern([4,2,4,2])表示实线的长度是线宽的四倍
      • 而空白处的长度是线宽的两倍用setDashOffset(float)方法可以设置虚线开始绘制的点与线起始点之间的距离,如果这个距离是动态的,则会形成动画效果。
钢笔QPen的应用实例

下面的程序用钢笔绘制一个带有背景图像、形状是”Z”形的虚线图

image-20230306235701933

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/6 23:45
# File_name: 02- 钢笔QPen的应用实例.py


import sys, math
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPen, QPainter, QPixmap
from PySide6.QtCore import QPointF, Qt


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 500)

def paintEvent(self, event):
painter = QPainter(self)

pix = QPixmap(r"../../Resources/images/d8.png") # 图像
pen = QPen(pix, 10) # 含有背景图像的钢笔,线宽是 40
pen.setStyle(Qt.DashLine)
pen.setJoinStyle(Qt.MiterJoin)
painter.setPen(pen) # 设置钢笔

p1 = QPointF(50, 50)
p2 = QPointF(self.width() - 50, 50)
p3 = QPointF(50, self.height() - 50)
p4 = QPointF(self.width() - 50, self.height() - 50)
painter.drawPolyline([p1, p2, p3, p4]) # 绘制折线


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

画刷QBrush的用法

对于封闭的图形,如矩形、圆等,用画刷 QBrush 可以在其内部填充颜色、样式、渐变、纹理或图案。

用QBrush类创建画刷的方法如下所示其中 bs是 Qt.BrushStyle 的枚举值,用于设置画刷的风格。

1
2
3
4
5
6
7
8
9
10
11
12
from PySide6.QtGui import QBrush

QBrush(self) -> None
QBrush(brush: Union[PySide6.QtGui.QBrush, PySide6.QtCore.Qt.BrushStyle, PySide6.QtCore.Qt.GlobalColor, PySide6.QtGui.QColor, PySide6.QtGui.QGradient, PySide6.QtGui.QImage, PySide6.QtGui.QPixmap]) -> None
QBrush(bs: PySide6.QtCore.Qt.BrushStyle) -> None
QBrush(color: PySide6.QtCore.Qt.GlobalColor, bs: PySide6.QtCore.Qt.BrushStyle = Instance(Qt.SolidPattern)) -> None
QBrush(color: PySide6.QtCore.Qt.GlobalColor, pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]) -> None
QBrush(color: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], bs: PySide6.QtCore.Qt.BrushStyle = Instance(Qt.SolidPattern)) -> None
QBrush(color: Union[PySide6.QtGui.QColor, PySide6.QtGui.QRgba64, Any, PySide6.QtCore.Qt.GlobalColor, str, int], pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]) -> None
QBrush(gradient: Union[PySide6.QtGui.QGradient, PySide6.QtGui.QGradient.Preset]) -> None
QBrush(image: Union[PySide6.QtGui.QImage, str]) -> None
QBrush(pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str]) -> None
画刷QBrush的常用方法

画刷 QBrush 的常用方法如表所示,主要方法介绍如下

QBrush的方法和参数类型 返回值的类型 说明
setStyle(Qt.BrushStyle) None 设置风格
style() Qt.BrushStyle 获取风格
set Texture(QPixmap) None 设置纹理图片
texture() QPixmap 获取纹理图片
setTextureImage(QImage) None 设置纹理图片
textureImage() Qlmage 获取纹理图片
setColor(Union[QColor,Qt.GlobalColor,str]) Nonei 设置颜色
color() QColor 获取颜色
gradient() QGradient 获取渐变色·
setTransform(QTransform) None (k 设置变换矩阵 5
transform() QTransform 返回变换矩阵5
isOpaque() bool 获取是否不透明
  • 画刷的风格用setStyle(Qt.BrushStyle)方法设置,其中参数 QtBrushStyle 的取值和示意图如图示。

    img

  • 画刷的纹理可以用setTexture(QPixmap)或 setTexturelmage(QImage)方法来设置,这时样式被设置成QtTexturePattern。

画刷QBrush的应用实例

下面的程序在窗口中绘制一个矩形框,并在矩形框中用画刷填充网格线

image-20230307000659600

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/7 0:03
# File_name: 03- 画刷QBrush的应用实例.py


import sys
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPen, QPainter, QBrush
from PySide6.QtCore import Qt.QPointF, QRectF


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

def paintEvent(self, event):
painter = QPainter(self)

pen = QPen() # 钢笔
pen.setColor(Qt.blue)
pen.setWidth(5) # 线条宽度
painter.setPen(pen) # 设置钢笔

brush = QBrush(Qt.red, Qt.DiagCrossPattern) # 画刷,同时设置颜色和风格
painter.setBrush(brush) # 设置画刷

p1 = QPointF(self.width() / 4, self.height() / 4)
p2 = QPointF(3 * self.width() / 4, 3 * self.height() / 4)
painter.drawRect(QRectF(p1, p2)) # 绘制矩形


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

新变色QGradient的用法

在用画刷进行填充时,可以设置填充颜色为渐变色。

所谓渐变色是指在两个不重合的点处分别设置不同的颜色,这两个点一个是起点,另一个是终点,这两个点之间的颜色从起点的颜色逐渐过渡到终点的颜色。

定义渐变色的类是 QGradient,渐变样式分为 3 种类型分别为

  • 线性渐变 QLinearGradient
  • 径向渐变QRadialGradient
  • 圆渐变QConicalGradient

image-20230307130811878

它们都继承自 QGradient 类,也会继承QGradient 类的属性和方法。这3种渐变的样式如图所示。

  • 用QLinearGradient类创建线性渐变色的方法如下所示。线性渐变需要一个线性渐变矩形区域(起始和终止位置),参数用于确定这个矩形区域

    image-20230308120428961

    1
    2
    3
    4
    5
    6
    from PySide6.QtGui import QLinearGradient

    QLinearGradient(self) -> None
    QLinearGradient(QLinearGradient: PySide6.QtGui.QLinearGradient) -> None
    QLinearGradient(start: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element], finalStop: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element]) -> None
    QLinearGradient(xStart: float, yStart: float, xFinalStop: float, yFinalStop: float) -> None
  • 用QRadialGradient类创建径向渐变色的方法如下。径渐变需要的几何参数如图所示,需要确定圆心位置、半径、焦点位置和焦点半径。径向渐变的构造函数中,

    • 第 1个参数是圆心位置,可以用点或坐标定义;
    • 第 2 个参数是半径;
    • 第 3 个参数是焦点位置,可以用点或坐标定义;
    • 第 4 个参数是焦点半径。

    如果焦点设置到圆的外面则取圆上的点作为焦点。

    image-20230308120733545

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from PySide6.QtGui import QRadialGradient

    QRadialGradient(self) -> None
    QRadialGradient(QRadialGradient: PySide6.QtGui.QRadialGradient) -> None
    QRadialGradient(center: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element], centerRadius: float, focalPoint: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element], focalRadius: float) -> None
    QRadialGradient(center: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element], radius: float) -> None
    QRadialGradient(center: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element], radius: float, focalPoint: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element]) -> None
    QRadialGradient(cx: float, cy: float, centerRadius: float, fx: float, fy: float, focalRadius: float) -> None
    QRadialGradient(cx: float, cy: float, radius: float) -> None
    QRadialGradient(cx: float, cy: float, radius: float, fx: float, fy: float) -> None
  • 用QConicalGradient 创建圆锥渐变色的方法如下所示。如图所示圆锥渐变需要的几何参数为圆心位置和起始角度a,角度必须在0~360之间,圆心位置可以用点或坐标来定义

    images/qconicalgradient.png

    1
    2
    3
    4
    5
    6
    from PySide6.QtGui import QConicalGradient

    QConicalGradient(self) -> None
    QConicalGradient(QConicalGradient: PySide6.QtGui.QConicalGradient) -> None
    QConicalGradient(center: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element], startAngle: float) -> None
    QConicalGradient(cx: float, cy: float, startAngle: float) -> None
QGradient,OLinearGradient,ORadialGradient 和 OConicalGradient 的常用方法

QGradient,QLinearGradient,QRadialGradient 和 QConicalGradient 的常用方法如表所示,主要方法介绍如下。

QLinearGradient,QRadialGradient 和 QConicalGradient 继承自QGradient,因此也会继承 QGradient 的方法

QGradient渐变类的常用方法及参数类型 说明
setCoordinateMode(QGradient.CoordinateMode) 设置坐标模式
setColorAt(pos:float,Union[QColor,Qt.GlobalColor,str]) 设置颜色
setStops(stops:Sequence[Tuple[float,QColor]]) 设置颜色
setInterpolationMode(mode: QGradient.InterpolationMode) 设置插值模式
setSpread(QGradient.Spread) 设置扩展方式
type()->QGradient.Type 获取类型
QLinearGradient渐变类的常用方法及参数类型 说明
setStart(Union[QPointF,QPoint,QPainterPath.Element]) 设置起始点
setStart(x: float,y:float) 设置起始点
start()->QPointF 获取起始点
setFinalStop(Union[QPointF,QPoint,QPainterPath.Element]) 设置终止点
setFinalStop(x: float,y: float) 设置终止点
finalStop()> QPointF 获取终止点
QRadialGradient渐变类的常用方法及参数类型 说明
setCenter(Union[QPointF,QPoint]) 设置圆心
setCenter(x: float,y:float) 设置圆心
setRadius(radius: float) 设置半径
setCenterRadius(radius:float) 设置半径
setFocalPoint(Union[QPointF,QPoint]) 设置焦点位置
setFocalPoint(float,float) 设置焦点位置
setFocalRadius(radius:float) 设置焦点半径
QConicalGradient渐变类的常用方法及参数类型 说明
setCenter(Union[QPointF,QPoint]) 设置圆心
setCenter(x: float,y: float) 设置圆心
setAngle(float) 设置起始角度
  • 在渐变区域内,可以在多个点设置颜色值,这些点之间的颜色值根据两侧的颜色来确定

    • 在定义内部点的颜色值时,通常通过逻辑坐标来定义,渐变区域内的起始点的逻辑值是 0终止点的逻辑值是 1。
    • 如果要在中间位置定义颜色,可以用setColorAt()方法来定义,例如 setColorAt(0.1,Qtblue)、setColorAt(0.4,Qt.yellow)和 setColorAt(0.6,Qtred)定义了3个位置处的颜色值;
    • 也可以用setStops()方法一次定义多个颜色值,例如 setStops([(0.1,Qt.red),(0.5,Qt.blue)])定义了两个点处的颜色值。
  • 用stops()方法可以获得逻辑坐标和颜色值。

    • 用setCoordinateMode(QGradient,CoordinateMode)方法可以设置坐标的模式,参数 QGradient.CoordinateMode 的取值如表所示

      QGradient.CoordinateMode 的取值 说明
      QGradient.LogicalMode 0 逻辑方式,起始点为0,终止点为1。这是默认值
      QGradient.ObjectMode 3 相对于绘图区域矩形边界 的逻辑坐标,左上角的坐标是(0, 0),右下角的坐标是(1,1)
      QGradient.StretchToDeviceMode 1 相对于绘图设备矩形边界的逻辑坐标,左上角的坐标是(0, 0),右下角的坐标是(1,1)
      QGradient.ObjectBoundingMode 2 该方法与QGradient.ObjectMode 基本相同,除了 QBrush.translorm()应用于逻辑空间而不是物理空间
  • 当设置的渐变区域小于填充区域时,渐变颜色可以扩展到渐变区域以外的空间。

    • 扩展模式用setSpread(QGradient.Spread)方法定义,参数 QGradient.Spread 的取值如表所示。

      QGradient.Spread的取值 说:明
      Qgradient.PadSpread 0 用最近的颜色扩展
      Qgradient.RepeatSpread 2 重复渐变
      Qgradient.ReflectSpread 1 对称渐变
    • 扩展模式不适合圆锥渐变,圆锥渐变没有固定的边界。

  • 用setInterpolationMode(mode; QGradientInterpolationMode)方法设置渐变色内部的插值模式,参数可取 QGradient,ColorInterpolation 或 QGradient,ComponentInterpolation。

  • 用type()方法可以获取渐变类型,返回值可能是:

    • QGradient.LinearGradient
    • QGradient.RadialGradient
    • QGradient.ConicalGradient
    • QGradient.NoGradient(无渐变色)
QGradient、QLinearGradient,ORadialGradient 和 OConicalGradient 的应用实例

下面的程序将窗口工作区分成4个矩形,在这4个矩形中分别绘制线性渐变圆锥渐变和径向渐变,并应用扩展,程序运行界面如图所示

image-20230307133912253

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/7 13:25
# File_name: 04- QGradient、QLinearGradient,ORadialGradient 和 OConicalGradient 的应用实例.py


import sys
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPen, QPainter, QBrush, QLinearGradient, QRadialGradient, QConicalGradient
from PySide6.QtCore import Qt.QPointF, QRectF


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 400)

def paintEvent(self, event):
painter = QPainter(self)

pen = QPen()
pen.setColor(Qt.darkBlue)
pen.setStyle(Qt.DashLine)
pen.setWidth(5)
painter.setPen(pen)
w = self.width()
h = self.height()

linear = QLinearGradient(QPointF(0, 0), QPointF(w / 8, 0)) # 线性渐变
linear.setStops([(0, Qt.red),(0.3, Qt.yellow),(0.6, Qt.green),(1, Qt.blue)]) # 设置颜色

linear.setSpread(QLinearGradient.ReflectSpread) # 镜像扩展
brush1 = QBrush(linear) # 用线性渐变定义刷子
painter.setBrush(brush1)
painter.drawRect(QRectF(0, 0, w / 2, h / 2)) # 画矩形

conical = QConicalGradient(QPointF(w / 4 * 3, h / 4), h / 6)
conical.setAngle(60) # 起始角度
conical.setColorAt(0, Qt.red)
conical.setColorAt(1, Qt.yellow)
brush2 = QBrush(conical)
painter.setBrush(brush2)
painter.drawRect(QRectF(w / 2, 0, w / 2, h / 2))

radial1 = QRadialGradient(QPointF(w / 4, h / 4 * 3), w / 8, QPointF(w / 4, h / 4 * 3) / 15)
radial1.setColorAt(0, Qt.red)
radial1.setColorAt(0.5, Qt.yellow)
radial1.setColorAt(1, Qt.blue)
radial1.setSpread(QRadialGradient.RepeatSpread)
brush3 = QBrush(radial1)
painter.setBrush(brush3)
painter.drawRect(QRectF(0, h / 2, w / 2, h / 2))

radial2 = QRadialGradient(QPointF(w / 4 * 3, h / 4 * 3), w / 6, QPointF(w / 5 * 4, h / 5 * 4), w / 10)
radial2.setColorAt(0, Qt.red)
radial2.setColorAt(0.5, Qt.yellow)
radial2.setColorAt(1, Qt.blue)
radial2.setSpread(QRadialGradient.ReflectSpread)
brush4 = QBrush(radial2)
painter.setBrush(brush4)
painter.drawRect(QRectF(w / 2, h / 2, w / 2, h / 2))


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

绘制几何图形

QPainter 可以在绘图设备上绘制点、直线、折线矩形、圆、弧弦文本和图像等,绘制几何图形的方法介绍如下。

绘制点

QPainter 绘制点的方法如表所示。可以一次绘制一个点,也可以一次绘制多个点其中QPolygon和QPolygonF 是用于存储QPoint 和QPointF 的类

QPainter绘制单点的方法 QPainter绘制多点的方法
drawPoint(p:QPoint) drawPoints(Sequence[QPointF])
drawPoint(pt:Union[QPointF,QPoint]) drawPoints(Sequence[QPoint])
drawPoint(x:int,y: int) drawPoints(points:Union[QPolygon,Sequence[QPoint], QRect])
drawPoint(pt: QPainterPath.Element) drawPoints(points: Union[QPolygonF, .Sequence[QPointF],QPolygon,QRectF])

QPolygon和QPolygonF用于存储多个QPoint和QPointF,

  • 创建QPolygon实例的方法是QPolygon()或者QPolygon(Sequence[QPoint])
  • 创建 QPolygonF 实例的方法是QPolygonF()或QPolygonF(Sequence[Union[QPointF,QPoint]])。
  • 用QPolygon的append(QPoint)方法可以添加点,用insert(int,QPoint)方法可以插人点,用setPoint(int;QPoint)方法可以更改点;
  • 用QPolygonF的append(Union[QPointF,QPoint])方法可以添加点,用insert(int,Union[QPointF,QPoint])方法可以插人点。
绘制直线

QPainter 绘制直线的方法如表所示。绘制直线需要用两个点。可以一次绘制一条直线,也可一次绘制多条直线,其中 QLine或 QLineF 是2D 直线类。

QPainter绘制单条直线的方法 QPainter绘制多条直线的方法
drawLine(line:QLine) drawLines(lines:Sequence[QLineF])
drawLine(line:Union[QLineF,QLine]) drawLines(lintes:Sequence[QLine])
drawLine(pl:QPoint,p2:QPoint) drawLines(pointPairs:Sequence[QPointF])
drawLine(pl:Union[QPointF, QPoint],p2: Union[QPointF,QPoint]) drawLines(pointPairs:Sequence[QPoint])
drawLine(x1:int,y1:int,x2:int,y2:int) drawLines(pointPairs:Sequence[QPoint])

QLine和 QLineF 用于定义二维直线,绘制二维直线需要用两个点。

  • 用QLine 类定义直线实例的方法有
    • QLine()
    • QLine(QPoint,QPoint)
    • QLine(xl:int,yl;int,x2:int;y2:int),
  • 用QLineF 类定义直线实例的方法有
    • QLineF(QLine)
    • QLineF()
    • QLineF(Union[QPointF,QPoint],Union[QPointF, QPoint])
    • QLineF(xl: float,yl: float, x2: float,y2: float)。
  • 用QLine的 setLine(xl;int,yl:int,x2;int,y2; int)方法、setP1(QPoint)方法、setP2(QPoint)或setPoints(QPoint,QPoint)方法可以设置线两端的点。
    • QLineF 也有同样的方法,只需把参数 int 改成float,或QPoint改成QPointF。
绘制折线

绘制折线必须用两个点,即使两条折线的终点和起始点相同,每条折线也必须用两个点来定义。折线由多个折线段构成,绘制折线需要给出多个点,上个折线段的终点是下个折线段的起始点。QPainter绘制折线的方法如表所示。

QPainter绘制折线的方法 说明
drawPolyline(Sequence[QPointF])
drawPolyline(polygon: Union[QPolygon, Sequence[QPoint], QRect])
drawPolyline(Sequence[QPoint])
drawPolyline(Union[QPolygonF,Sequence[QPointF],QPolygon, QRectF])
QPainter 绘制多边形和凸多边形的方法

QPainter 绘制多边形和凸多边形的方法如表所示。

  • 使用这些方法时,需要给出多边形或凸多边形的顶点,系统会自动在起始点和终止点之间建立直线,使多边形封闭。

  • 参数fillRule是QtFillRule的举类型用于确定一个点是否在图形内部在内部的区域可以进行填充。filiRule可以取Qt.OddEvenFill或Qt.WindingFill,这两种填充规则如图所示。

    image-20230308132336777

    • Qt.OddEvenFill是奇偶填充规则,要判断一个点是否在图形中可以从该点向图形外引一条水平线,如果该水平线与图形的交点个数为奇数,那么该点在图形中。

    • Qt.WindingFil1是非零绕组填充规则要判断一个点是否在图形中可以从该点向图形外引一条水平线,如果该水平线与图形的边线相交,这个边线是顺时针绘制的,就记为1,是逆时针绘制的就记为-1,然后将所有数值相加,若结果不为 0,那么该点就在图形中。图形的绘制方向会影响填充的判断。

QPainter 绘制多边形的方法 说明
drawPolygon(Sequence[QPointF],Qt.FillRule) 使用填充规则fillRule绘制由给定点(QPointF)定义的多边形。
drawPolygon(Sequence[QPoint],Qt.FillRule) 使用填充规则fillRule绘制由给定点(QPoint)定义的多边形。
drawPolygon(polygon: Union[QPolygon, Sequence[QPoint], QRect], fillRule: Qt.FillRule = Qt.OddEvenFill)
drawPolygon(polygon: Union[QPolygonF,Sequence[QPointF],QPolygon,QRectF],fillRule: Qt.FillRule = Qt.OddEvenFill)
QPainter 绘制凸多边形的方法 说明
drawConvexPolygon(Sequence[QPointF])
drawConvexPolygon(Sequence[QPoint])
drawConvexPolygon(polygon:Union[QPolygon,Sequence[QPoint],QRect])
drawConvexPolygon(polygon: Union[QPolygonF,Sequence[QPointF], QPolygon, QRectF])

下面的程序用绘制多边形的方法绘制两个五角星,并分别采用奇偶填充规则和非零绕组填充规则进行填充,程序运行结果如图所示,

image-20230308133326289

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 13:24
# File_name: 05-绘制多边形的方法绘制两个五角星.py


from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPen, QPainter, QBrush
from PySide6.QtCore import QPointF, Qt
from math import cos, sin, pi
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 500)

def paintEvent(self, event):
painter = QPainter(self)

pen = QPen() # 钢笔
pen.setWidth(2) # 线条宽度
painter.setPen(pen) # 设置钢笔
bush = QBrush(Qt.SolidPattern)
painter.setBrush(bush)

r = 100 # 五角星的外接圆半径

x = self.width() / 4
y = self.height() / 2
p1 = QPointF(r * cos(-90 * pi / 180) + x, r * sin(-90 * pi / 180) + y)
p2 = QPointF(r * cos(-18 * pi / 180) + x, r * sin(-18 * pi / 180) + y)
p3 = QPointF(r * cos(54 * pi / 180) + x, r * sin(54 * pi / 180) + y)
p4 = QPointF(r * cos(126 * pi / 180) + x, r * sin(126 * pi / 180) + y)
p5 = QPointF(r * cos(198 * pi / 180) + x, r * sin(198 * pi / 180) + y)

# 绘制多边形
painter.drawPolygon([p1, p3, p5, p2, p4], Qt.FillRule.OddEvenFill)
offset = QPointF(self.width() / 2, 0)
painter.drawPolygon([p1 + offset, p3 + offset, p5 + offset, p2 + offset, p4 + offset], Qt.WindingFill)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

绘制矩形

QPainter 可以一次绘制一个矩形,也可以一次绘制多个矩形。

QPainter 绘制矩形的方法如表所示,其中drawRect(xl:int,yl;int,w:int,h:int)方法中xl和y1参数确定左上角的位置,w 和h参数确定宽度和高度。

QPainter绘制单个矩形的方法 QPainter绘制多个矩形的方法
drawRect(rect:QRect) drawRects(rectangles:Sequence[QRectF])
drawRect(rect: Union[QRectF,QRect]) drawRects(rectangles:Sequence[QRect])
drawRect(xl:int,yl:int,w:int,h:int)
绘制圆角矩形

圆角矩形是在矩形的基础上对4个角分别用一个圆进行倒圆角,其示意图如图所示。要绘制圆角矩形,除了需要设置绘制矩形的参数外,还需要设置椭圆的两个半径。

image-20230308133517851

QPainter 绘制椭圆的方法有

  • drawRoundedRect(rect: Union[QRectF,QRect]xRadius: float,yRadius: float, mode; Qt.SizeMode =Qt AbsoluteSize)
  • drawRoundedRect(x; int,y: int,w; int,h; int,xRadius; float,yRadius: float,mode: Qt.SizeMode = QtAbsoluteSize)
  • 其中参数 mode是 Qt.SizeMode 的枚举类型可以取 Qt.AbsoluteSize或Qt.RelativeSize,分别确定圆半径是绝对值还是相对于矩形边长的相对值。
绘制椭圆、扇形、弧和弦

一个椭圆有两个半径。确定一个椭圆有两种方法:

  • 一种是先确定一个矩形边界,在矩形内部作一个与矩形相切的内切椭圆
  • 另一种是先定义一个中心,再定义两个半径。

绘制椭圆示意图如图所示。

  • 如果矩形边界是正方形或者圆的两个半径相等,圆就变成了圆。

  • 扇形是椭圆的一部分,绘制扇形时除了确定椭圆的几何数据外,还需要确定扇形的起始角和跨度角。需要特别注意的是,起始角和跨度角都是用输人值的 1/16 计算,如要求起始角为45°,跨度角为60则需要输人的起始角为45*16,跨度角为60*16,例如 painter.drawPie(QRect(300,300,200,100),45 * 16,60*16)。

    image-20230308133947802

QPainter 绘制圆和扇形的方法如表所示

QPainter绘制椭圆的方法 QPainter 绘制扇形的方法
drawEllipse(center:[QPointF,QPoint],rx:int, ry: int) drawPie(QRect,a: int,alen:int)
drawEllipse(r:QRect) drawPie(rect:Union[QRectF,QRect],a: int,alen: int)
drawEllipse(r:Union[QRectF,QRect]) Q)7x53 drawPie(x;int,y:int,w:int,h;int,a: int, alen: int)
drawEllipse(x;int,y:int,w:int,h:int)
drawEllipse(center:QPainterPath.Element,rx: float,ry: float)

绘制弧和绘制弦的参数与绘制扇形的参数相同,只不过是从圆上截取的部分不同QPainter绘制弧和弦的方法如表所示。

QPainter绘制弧的方法 QPainter绘制弦的方法
drawArc(QRect,a: int,alen: int) drawChord(QRect,a; int,alen:int)
drawArc(rect: Union[QRectF,QRect],a: int, alen:int) drawChord(rect:Union[QRectF, QRect], a: int, alen: int)
drawArc(x:int,y;int,w:int,h;int,a: int,alen: int) drawChord(x;int,y:int,w:int,h:int,a: int,alen: int)
抗锯齿

在绘制几何图像和文字时,如果线条是斜线,对线条进行放大后会发现它呈现锯齿状为防止出现锯齿状需要对线条边缘进行模糊化处理。

  • 用QPainter 的setRenderHint(hint;QPainter, RenderHint,on; bool=True)或 setRenderHints(hints; QPainter.RenderHints.on;bool=True)方法可以设置是否进行抗锯齿处理,
  • 用testRenderHint(hint;QPainter.RenderHint)方法可以获取是否设置了抗锯算法其中枚举参数 QPainter.RenderHint可以取:
    • QPainter.Antialiasing(启用抗锯齿)
    • QPainter,TextAntialiasing(对文本进行抗锯齿)
    • QPainter.SmoothPixmapTransform(使用平滑的像素图像算法)
    • QPainter.LosslessImageRendering(用于PDF文档)。

绘制文本

可以在指定位置绘制文本,绘制文本时,通常需要先用setFont(QFont)方法设置QPainter的字体。

绘制文本的方法如表所示所绘文本默认是反锯齿的

QPainter绘制文本的方法 QPainter绘制文本的方法
drawStaticText(left: int,top: int, staticText: QStaticText) drawText(p:Union[QPointF,QPoint],s: str)
drawStaticText(topLeftPosition: Union[QPointF, QPoint, QPainterPath.Element], staticText:QStaticText) drawText(r: Union[QRectF,QRect],flags: int, text: str,br:Union[QRectF,QRect])
drawText(r:Union[QRectF,QRect],text: str, Qt.Alignment) drawText(p:QPoint,s:str)
drawText(x:int,y:int,w:int,h:int,flags: int, text: str,br:QRect) drawText(x:int,y: int,s:str)
drawText(r: QRect, flags: int, text: str,br: QRect) drawText(p: QPainterPath.Element,s: str)
  • 绘制文本可以用drawStaticText()方法该方法比较快且每次不用重新计算文本的排列位置。

    • QStaticText 是静态文本类,
      • 用QStaticText 类创建静态文本的方法是QStaticText()或 QStaticText(str)。
      • 可以用QStatciText 的 setText(str)方法设置文本
      • 用setTextFormat(Qt.TextFormat)方法设置静态文本的格式参数Qt.TextFormat可取:
        • Qt.PlainText、
        • Qt.RichText、
        • Qt.AutoText
        • Qt.MarkdownText;
      • 用setTextOption(QTextOption)方法设置选项;
      • 用setTextWidth(float)方法设置静态文本的宽度。
  • 绘制文本的方法中,flags 参数可取

    • Qt.AlignLeft
    • Qt.AlignRight
    • Qt.AlignHCenter
    • QtAlignJustify
    • Qt.AlignTop,
    • Qt.AlignBottom
    • Qt.AlignVCenter
    • Qt.AlignCenter
    • Qt.TextSingleLine
    • Qt.TextExpandTabs
    • Qt.TextShowMnemonic
    • QtTextWordWrap
    • 参数r是要绘制文本的矩形范围;
    • 参数 br 是指边界矩形(ounding rectangle),所绘文本应该包含在边界矩形中。
  • 如果所绘制的文本用当前的字体绘制时,给定的矩形范围不合适,可以用boundingRect(···)方法获取边界矩形。获取文本边界矩形的方法如表所示

    获取文本边界矩形的方法 返回值的类型
    boundingRect(rect:QRect,flags: int,texti str) QRect
    boundingRect(rect: Union[QRectF,QRect],flags:int,text: str) QRectF
    boundingRect(rect:Union[QRectF,QRect],text: str,Qt.Alignment) QRectF
    boundingRect(x: int,y:int,w:int,h: int,flags: int,text: str) QRect

绘图路径QPainterPath的用法

前文中绘制的几何图形比较简单,各个图形之间也是相互独立的,例如用line()或 lines()方法绘制的多个线条之间相互独立,即便是首尾相连,它们也不是封闭的,不能在其内部填充图案。

为了将简单的图形组合成复杂且封闭的图形,需要用到绘图路径 QPainterPath,前面介绍的绘图方法所绘制的图形都可以加入QPainterPath 中,构成QPainterPath的元素。

用QPainter 的drawPath(path; QPainterPath)方法或strokePath(path:QPainterPath,pen;Union[QPen,Qt.PenStyle,QColor])方法可以将绘图路径的图形绘制出来

用绘图路径绘制的图形不论是否封闭,都隐含是封闭的,可以在其内部进行填充QPainterPath是一些绘图命令按照先后顺序的有序组合创建一次后可以反复使用用QPainterPath类

创建绘图路径实例对象的方法如下所示其中startPoint是绘制路径的起始点,也可以用绘图路径的 moveTo(Union[QPointF,QPoint])或 moveTo(x:float;y:float)方法将绘图路径的当前点移到起始点

1
2
3
4
5
from PySide6.QtGui import QPainterPath

QPainterPath(self) -> None
QPainterPath(other: PySide6.QtGui.QPainterPath) -> None
QPainterPath(startPoint: Union[PySide6.QtCore.QPointF, PySide6.QtCore.QPoint, PySide6.QtGui.QPainterPath.Element]) -> None
绘图路径中与绘图有关的方法
QPainterPath的绘图方法及参数类型 说 明
moveTo(Union[QPointF,QPoint]) 将当前点移动到指定的点,作为下一个绘图单元的 起始点
moveTo(x:float,y:float) 将当前点移动到指定的点,作为下一个绘图单元的 起始点
currentPosition() 获取当前的起始点 QPointF
arcMoveTo(rect: Union[QRectF,QRect],angle: float) 将当前点移动到指定矩形框内的椭圆上,最后的 float是起始角度
arcMoveTo(x: float,y: float,w: float,h: float, angle: float) 将当前点移动到指定矩形框内的椭圆上,最后的 float是起始角度
lineTo(Union[QPointF, QPoint,QPainterPath.Element]) 在当前点与指定点之间绘制直线
lineTo(x: float,y: float) 在当前点与指定点之间绘制直线
cubicTo(ctrlPt1: Union[QPointF,QPoint, QPainterPath.Element], ctrlPt2: Union[QPointF, QPoint, QPainterPath, Element], endPt: Union[QPointF,QPoint, QPainterPath.Element]) 在当前点和终点间绘制三次贝塞尔曲线,前两个点 是中间控制点,最后一个点是终点
cubicTo(ctrlPt1x: float,ctrlPtly: float, ctrlPt2x: float, ctrlPt2y:float,endPtx: float,endPty:float) 在当前点和终点间绘制三次贝塞尔曲线,前两个点 是中间控制点,最后一个点是终点
quadTo(ctrlPt: Union[QPointF, QPoint, QPainterPath.Element],endPt: Union[QPointF, QPoint,QPainterPath.Element]) 在当前点和终点间添加二次贝塞尔曲线,第一个点 是控制点
quadTo(ctrlPtx: float, ctrlPty: float, endPtx: float,endPty: float) 在当前点和终点间添加二次贝塞尔曲线,第一个点 是控制点
arcTo(rect: Union[QRectF,QRect], startAngle: float,arcLength: float) 在矩形框内绘制圆弧,startAngle和 arcLength分别 是起始角和跨度角.
arcTo(x: float, y: float, w: float, h: float, startAngle: float,arcLength: float) 在矩形框内绘制圆弧,startAngle和 arcLength分别 是起始角和跨度角.
addEllipse(center: Union[QPointF,QPoint],rx: float,ry: float) 绘制封闭的椭圆
addEllipse(rect:Union[QRectF,QRect]) 绘制封闭的椭圆
addEllipse(x: float,y: float,w: float,h:float) 绘制封闭的椭圆
addPolygon(Union[QPolygonF, Sequence[QPointF],QPolygon,QRectF]) 绘制多边形
addRect(rect: Union[QRectF,QRect]) 绘制矩形
addRect(x: float,y: float,w; float,h;float) 绘制矩形
addRoundedRect(rect: Union[QRectF,QRect], xRadius: float,yRadius; float, mode: Qt.SizeMode=Qt.AbsoluteSize) 绘制圆角矩形
addRoundedRect(x: float,y; float,w: float,h: float, xRadius: float, yRadius: float, mode: Qt.SizeMode=Qt.AbsoluteSize) 绘制圆角矩形
addText(point: Union[QPointF, QPoint, QPainterPath.Element],f: Union[QFont,str, Sequence[str]],text: str) 绘制文本
addText(x:float,y: float,f:Union[QFont,str, Sequence[str]],text:str) 绘制文本
addRegion(region: :Union[QRegion,QBitmap, QPolygon,QRect]) 绘制QRegion的范围
closeSubpath() 由当前子路径首尾绘制直线,开始新的子路径的 绘制
connectPath(QPainterPath) 由当前路径的终点位置与给定路径的起始位置绘制 直线
addPath(QPainterPath) 将其他绘图路径添加进来
translate(dx: float,dy: float) 将绘图路径进行平移,dx和dy是x和y方向的移动 量,或用点表示
translate(offset: Union[QPointF, QPoint, QPainterPath.Element]) 将绘图路径进行平移,dx和dy是x和y方向的移动 量,或用点表示
绘图路径QPainterPath 与查询有关的方法
QPainterPath的查询方法 返回值的类型 说明
angleAtPercent(t: float) float 获取绘图路径长度百分比处的切向角
slopeAtPercent(t: float) float 获取斜率
boundingRect() QRectF 获取路径所在的边界矩形区域
capacity() int 返回路径中单元的数量
clear() None 清空绘图路径中的元素
contains(Union[QPointF,QPoint]) bool 如果指定的点在路径内部,则返回True
contains(QRectF) 6001 如果矩形区域在路径内部,则返回True
contains(QPainterPath) bool 如果包含指定的路径,则返回 True
controlPointRect() QRectF 获取包含路径中所有点和控制点构成的矩形
elementCount() int 获取绘图路径的单元数量
intersected(QPainterPath) QPainterPath 获取绘图路径和指定路径填充区域相交的 路径
united(QPainterPath) QPainterPath 获取绘图路径和指定路径填充区域合并的 路径
interseets(QRectF) bo01 获取绘图路径与矩形区域是否相交
intersects(QPainterPath) bool 获取绘图路径与指定路径是否相交
subtracted(QPainterPath) QPainterPath 获取减去指定路径后的路径
isEmpty() bool 获取绘图路径是否为空
length() float 获取绘图路径的长度
pointAtPercent(float) QPointF 获取百分比长度处的点
reserve(size:int) None 在内存中预留指定数量的绘图单元内存空间
setElementPositionAt(i; int,x; float,y: float) None 将索引是int的元素的x和y坐标设置成指 定值
setFillRule(Qt.FillRule) None 设置填充规则
simplified() QPainterPath 获取简化后的路径,如果路径元素有交叉或 重合,则简化后的路径没有重合
swap(QPainterPath) None 交换绘图路径
toReversed() QPainterPath 获取顺序反转后的绘图路径
toSubpathPolygons() List[QPolygonF] 将每个元素转换成QPolygonF
toSubpathPolygons(QTransform) List[QPolygonF] 将每个元素转换成QPolygonF
translated(dx: float,dy: float) QPainterPath 获取平动后的绘图路径,float是x方向和y 方向的移动量,或者用点来表示
translated(Union[QPointF,QPoint]) QPainterPath 获取平动后的绘图路径,float是x方向和y 方向的移动量,或者用点来表示
方法说明

路径是由多个图形构成的,每个图形中可能包括直线、贝塞尔曲线、弧、椭圆、多边形、矩形或文本。

  • 使用moveTo()方法把当前路径移到指定位置,作为绘图开始的起点位置,移动当前点会启用一个新的子路径,并自动封闭之前的路径
  • 绘制
    • 用lineTo()方法绘制直线,
    • 用arcTo()方法绘制弧,
    • 用quadTo()方法和 cubicTo()方法绘制二次和三次贝塞尔曲线,
    • 用addEllipse()方法绘制封闭的圆,
    • 用addPolygon()方法绘制多边形,
    • 用addRect()方法和addRoundedRect()方法绘制矩形。
    • 在添加直线、弧或贝塞尔曲线后,当前点移动到这些元素的最后位置。
    • 绘制弧时,弧的婴度角与钟表的 3 时方向相同,逆时针方向为正。
  • 路径中每个绘图步骤称为单元(element)
    • 比如 moveTo()lineTo()arcTo)都是单元,addRect() addPolygon()等都是用moveTo() lineTo()、arcTo()等绘制的。
    • 例如 addRect(100,50,200,200)由 movetTo(100,50)、lineTo(300,50)、lineTo(300,250)、lineTo(100,250)和 lineTo(100,50)共5个单元构成
  • 路径可以进行交、并、减和移动操作。
绘图路径OPainterPath的应用实例

作为应用实例,下面我们绘制一个太极图像,程序中使用非零绕组填充

image-20230308144310391

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 14:19
# File_name: 06-绘图路径QPainterPath 的应用实例.py


from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPen, QPainter, QPainterPath, QBrush
from PySide6.QtCore import QPointF, Qt
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 500)

def paintEvent(self, event):
path = QPainterPath() # 路径
self.center = QPointF(self.width() / 2, self.height() / 2)
r = min(self.width(), self.height()) / 3 # 外面大圆的半径
r1 = r / 7 # 内部小圆的半径

path.moveTo(self.center.x(), self.center.y() - r)
path.arcTo(self.center.x() - r, self.center.y() - r, 2 * r, 2 * r, 90, 360) # 外部大圆
path.arcTo(self.center.x() - r, self.center.y() - r, 2 * r, 2 * r, 90, -180) # 反向半圆

path.moveTo(self.center.x(), self.center.y() + r)
path.arcTo(self.center.x() - r / 2, self.center.y(), r, r, -90, 180) # 外部大圆
path.arcTo(self.center.x() - r / 2, self.center.y() - r / 2 - r / 2, r, r, 270, -180) # 反向半圆

path.moveTo(self.center.x() + r1, self.center.y() - r / 2)
path.arcTo(self.center.x() - r1, self.center.y() - r / 2 - r1, 2 * r1, 2 * r1, 0, 360) # 内部小圆

path.moveTo(self.center.x() + r1, self.center.y() + r / 2)
path.arcTo(self.center.x() - r1, self.center.y() + r / 2 - r1, 2 * r1, 2 * r1, 0, -360) # 内部小圆

path.setFillRule(Qt.FillRule.WindingFill) # 填充方式

painter = QPainter(self)
pen = QPen()
pen.setWidth(5)
pen.setColor(Qt.black)
painter.setPen(pen)

brush = QBrush(Qt.SolidPattern)
painter.setBrush(brush) # 设置画刷
painter.drawPath(path) # 设置绘制路径
super().paintEvent(event)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

填充

用QPainter 绘图时如果所绘制的图形是封闭的,且为QPainter设置了画刷,则系统自动在封闭的图形内填充画刷的图案,封闭的图形包括绘图路径、矩形、椭圆、多边形。

除此之外,还可以为指定的矩形范围填充图案,此时不需要有封闭的边界线QPainter的方法中用于填充的方法如表所示主要方法介绍如下

  • 用fillPath0)方法可以用画刷颜色渐变色给指定路径填充颜色用fillRect()方法可以给指定的矩形区域绘制填充颜色,这时无须封闭的空间,也不会绘制出轮廓;
  • 用eraseRect()方法可以擦除矩形区域的填充用setBackgroundMode(Qt.BGMode)方法设置背景的模式,其中参数QtBGMode可以取:
    • Qt.TransparentMode(透明模式)
    • Qt.OpaqueMode(不透明模式)
  • 用setBackground(Union[QBrush,QColor,Qt.GlobalColor,QGradient7)方法设置背景色,背景色只有在不透明模式下才起作用。
  • 用setBrushOrigin(Union[QPointF,QPoint]), setBrushOrigin(int, int)或 setBrushOrigin(QPoint)方法设置画刷的起始点,起始点会影响纹理、渐变色的布局。
QPainter的填充方法 说 明
fillPath(path; QPainterPath,brush: Union[QBrush, Qt.BrushStyle,Qt.GlobalColor, QColor,QGradient, QImage, QPixmap]) 为指定的路径填充颜色
fillRect(Union[QRectF, QRect], Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, str,QGradient, QImage,QPixmap]) 用画刷,颜色和渐变色填充指定的矩形 区域
fillRect(x; int,y:int,w: int,h:int,Union[QBrush,Qt.BrushStyle, Qt.GlobalColor,QColor, str, QGradient, QImage,QPixmap]) 用画刷,颜色和渐变色填充指定的矩形 区域
eraseRect(Union[QRectF,QRect]) 擦除指定区域的填充
eraseRect(x:int,y:int,w:int,h:int) 擦除指定区域的填充
setBackground(Union[QBrush,QColor, Qt.GlobalColor, QGradient]) 设置背景色
background() 获取背景画刷 QBrush
setBackgroundMode(Qt.BGMode) 设置背景模式
setBrushOrigin(Union[QPointF,QPoint, QPainterPath.Element]) 设置画刷的起始点
setBrushOrigin(x:int,y:int) 设置画刷的起始点
brushOrigin() 获取起始点QPoint

下面的程序绘制文字,用渐变色分别显示文字和背景色,并用定时器实现动态移动画刷的起始点,产生动画效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 15:01
# File_name: 07-填充.py


import sys
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPen, QPainter, QLinearGradient, QBrush
from PySide6.QtCore import Qt.QRect, QTimer


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(1000, 300)
self.__text = "狂拽炫酷吊炸天"
self.__start = 0
self.__rect = QRect(0, 0, self.width(), self.height())
self.timer = QTimer(self)
self.timer.timeout.connect(self.timeout)
self.timer.setInterval(10)
self.timer.start()

def paintEvent(self, event):
painter = QPainter(self)

font = painter.font()
font.setFamily("黑体")
font.setBold(True)
font.setPointSize(50)
painter.setFont(font)

linear = QLinearGradient(self.__rect.topLeft(), self.__rect.bottomRight()) # 字体渐变
linear.setColorAt(0, Qt.red)
linear.setColorAt(0.5, Qt.yellow)
linear.setColorAt(1, Qt.green)

linear2 = QLinearGradient(self.__rect.left(), 0, self.__rect.right(), 0) # 背景渐变
linear2.setColorAt(0.4, Qt.darkBlue)
linear2.setColorAt(0.5, Qt.white)
linear2.setColorAt(0.6, Qt.darkBlue)

brush = QBrush(linear) # 字体画刷
brush2 = QBrush(linear2) # 背景画刷
pen = QPen() # 钢笔
pen.setBrush(brush) # 设置钢笔画刷
painter.setPen(pen)
painter.setBackgroundMode(Qt.OpaqueMode) # 背景模式不透明
painter.setBackground(brush2) # 设置背景画刷
painter.setBrushOrigin(self.__start, self.__rect.top()) # 设置画刷的起始点

self.__rect = painter.drawText(self.rect(), Qt.AlignCenter, self.__text) # 绘制文字

def timeout(self): # 定时器槽函数
if self.__start > self.__rect.width() / 2:
self.__start = int(- self.__rect.width() / 2)
self.__start = self.__start + 5
self.update()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

绘制图像

除了可以直接绘制几何图形外,QPainter 还可以把QPixmapQImage和QPicture图像直接绘制在绘图设备上。

绘制 QPixmap 图像的方法如表所示,可以将图像按照原始尺寸显示,也可以缩放图像到一个矩形区域中显示,还可以从原图像上截取一部分绘制到一个矩形区域。

用drawPixmapFragments(fragments; List[QPainter, PixmapFragment], fragmentCount:int,pixmap: Union[QPixmap,Qlmage,str], hints: QPainter, PixmapFragmentHints)方法可以截取图像的多个区域,并对每个区域进行缩放、旋转操作

  • 其中参数 hints 只能取QPainter.OpaqueHint ;
  • 参数 QPainter,PixmapFragment 的创建方法是QPainter.PixmapFragment, create(pos; QPointF, sourceRect; QRectF,scaleX = 1,scaley = 1.rotation =0,opacity = 1)
    • 其中 pos 是图像绘制地点,
    • sourceRect 是截取的图像的部分区域,
    • scaleX和scaleY 是缩放比例,
    • rotation 是旋转角度,
    • opacity 是不透明度值
QPainter 绘制 QPixmap 图像的方法 说 明
drawPixmap(p: Union[QPointF,QPoint,QPainterPath.Element],pm:Union[QPixmap,QImage,str]) 指定绘图设备上的一个点作为左上角,按 照图像原始尺寸显示
drawPixmap(x:int,y:int,pm:Union[QPixmap,QImage, str]) 指定绘图设备上的一个点作为左上角,按 照图像原始尺寸显示
drawPixmap(r:QRect,pm:Union[QPixmap,Qlmage, str]) 指定绘图设备上的矩形区域,以缩放尺寸 方式显示
drawPixmap(x:int,y:int,w:int,h:int, pm:Union[QPixmap,QImage,str]) 指定绘图设备上的矩形区域,以缩放尺寸 方式显示
drawPixmap(p:Union[QPointF, QPoint, QPainterPath.Element],pm:Union[QPixmap,QImage,str],sr:Union[QRectF,QRect]) 指定绘图设备上的一个点和图像的矩形区 域,裁剪显示图像
drawPixmap(x:int,y:int,pm:Union[QPixmap,QImage, str],sx:int,sy:int,sw:int,sh:int) 指定绘图设备上的一个点和图像的矩形区 域,裁剪显示图像
drawPixmap(targetRect: Union[QRectF,QRect],pixmap: Union[QPixmap, QImage, str], sourceRect: Union[QRectF,QRect]) 指定绘图设备上的矩形区域和图像的矩形 区域,裁剪并缩放显示图像
drawPixmap(x:int,y: int,w:int,h:int, pm: Union[QPixmap,QImage,str],sx: int,sy:int,sw:int,sh:int) 指定绘图设备上的矩形区域和图像的矩形 区域,裁剪并缩放显示图像
drawTiledPixmap(QRect, Union[QPixmap,QImage, str], pos: QPoint) 以平铺样式绘制图片
drawTiledPixmap(rect: Union[QRectF, QRect],pm: Union[QPixmap, QImage, str], offset: Union[QPointF, QPoint,QPainterPath.Element]) 以平铺样式绘制图片
drawTiledPixmap(x:int,y: int,w:int, h: int, Union[QPixmap,QImage,str],sx:int=0,sy:int=0) 以平铺样式绘制图片
drawPixmapFragments(fragments: List[QPainter.PixmapFragment], fragmentCount: int, pixmap: Union[QPixmap, QImage, str], hints: QPainter.PixmapFragmentHints) 绘制图像的多个部分,可以对每个部分进 行缩放、旋转操作

绘制 QImage 图像的方法如表所示。可以将图像按照原始尺寸显示,也可以缩放图像到一个矩形区域中显示,还可以从原图像上截取一部分绘制到一个矩形区域。

其中flags 参数是 Qt.ImageConversionFlags 枚举值,可取

  • Qt.AutoColor
  • Qt.ColorOnly
  • Qt.MonoOnly
QPainter绘制QImage图像的方法 说明
drawImage(p: Union[QPointF, QPoint, QPainterPath, Element],image:Union[QImage,str]) 在指定位置,按图像实际尺寸显示
drawImage(r: Union[QRectF,QRect],image:Union[QImage,str]) 在指定矩形区域内,图像进行缩放显示
drawImage(p: Union[QPointF, QPoint, QPainterPath.Element],image:Union[Qlmage,str], sr: Union[QRectF, QRect], flags: Qt.ImageConversionFlags=Qt.AutoColor) 在指定位置,从图像上截取一部分显示
drawImage(x: int,y: int,image: Union[QImage, str],sx:int=0,sy:int=0,sw:int=-1,sh: int= -1,flags: Qt.ImageConversionFlags= Qt.AutoColor) drawImage(targetRect:Union[QRectF, QRect],
image: Union[QImage, str], sourceRect: Union[QRectF,QRect],flags: Qt.ImageConversionFlags= Qt.AutoColor) - 从图像上截取一部分,以缩放形式显示在指定 的矩形区域内

对于QPicture 图像,只能在绘图设备的指定点上按照原始尺寸进行绘制。

绘制QPicture 图像的方法有 drawPicture(p;Union[QPointF,QPoint,QPainterPath,Element]picture: Union[QPicture,int])和 drawPicture(x; int,y: int,picture: Union[QPictureint])

下面的程序从磁盘图片文件上创建QPixmap然后以QPixmap作为绘图设备直接在图片上绘制一个矩形和一个椭圆,并在矩形和椭圆之间填充黑色最后在窗口上绘制出图像。把图形先绘制到QPixmap或QImage图像中,然后再把QPixmap或QImage图像绘制到窗体上,可以避免出现屏幕闪烁现象。

image-20230308154426968

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 15:30
# File_name: 08-绘制QPicture 图.py


from PySide6.QtWidgets import QApplication, QWidget, QGraphicsWidget
from PySide6.QtGui import QPainter, QPixmap, QPainterPath, QBrush
from PySide6.QtCore import QRectF, Qt
import sys, os


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

# self.resize(600, 500)
self.__pixmap = QPixmap("../../Resources/Images/正方形.png")

def paintEvent(self, event):
painter = QPainter() # 未确定绘图设备
rect = QRectF(0, 0, self.__pixmap.width(), self.__pixmap.height()) # 获取图片的矩形

path = QPainterPath() # 绘图路径
path.addRect(rect) # 添加矩形
path.addEllipse(rect) # 添加椭圆
path.setFillRule(Qt.OddEvenFill) # 设道填充方式
brush = QBrush(Qt.SolidPattern) # 画刷
brush.setColor(Qt.black) # 画刷颜色

painter.begin(self.__pixmap) # 以QPixmap作为绘图设备
painter.setBrush(brush) # 设置画刷
painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿
painter.drawPath(path) # 在QPixmap上绘图
painter.end() # 结束绘图

# 保存图像
# if not os.path.exists("new.png"):
# self.__pixmap.save("new.png")

painter.begin(self) # 以窗口作为位图设备
painter.drawPixmap(self.rect(), self.__pixmap) # 在窗口上绘制图像
painter.end() # 结束绘图


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

裁剪区域QRegion

QPainter 中有关裁剪区域的方法

当所绘图形比较大时,若只想显示绘图上的一部分区域的内容,其他区域的内容不显示,就需要使用裁剪区域。

用QPainter 设置裁剪区域的方法如表所示其中参数op是Qt.ClipOperation 的枚举值,可以取:

  • Qt.NoClipQt.ReplaceClip(替换裁剪区域)
  • Qt.IntersectClip(与现有裁区域取交集)
QPainter设置裁剪区域的方法 说明
setClipping(bool) 设置是否启用裁剪区域
hasClipping() 获取是否有裁剪区域
setClipPath(path: QPainterPath, op: :Qt.ClipOperation=Qt.ReplaceClip) 用路径设置裁剪区域
setClipRect(Union[QRectF, QRect], op: Qt.ClipOperation=Qt.ReplaceClip) 用矩形框设置裁剪区域
setClipRect(x: int,y: int,w: int,h: int, op: Qt.ClipOperation=Qt.ReplaceClip) 用矩形框设置裁剪区域
setClipRegion(Union[QRegion,QBitmap,QPolygon, QRect],op: Qt.ClipOperation=Qt.ReplaceClip) 用QRegion设置裁剪区域
clipBoundingRect() 获取裁剪区域QRectF
clipPath() 获取裁剪区域绘图路径 QPainterPath
clipRegion() 获取裁剪区域 QRegion
QRegion的方法

QRegion类专门用于定义裁剪区域,QWidget 的 repaint()方法可以接受 QRegion参数,限制刷新的范围。用QRegion 类创建裁剪区域实例的方法如下,其中t是QRegion.RegionType枚举类型,可以取 :

  • QRegion.Rectangle
  • QRegion.Ellipse
1
2
3
4
5
6
7
8
from PySide6.QtGui import QRegion

QRegion(self) -> None
QRegion(bitmap: Union[PySide6.QtGui.QBitmap, str]) -> None
QRegion(pa: Union[PySide6.QtGui.QPolygon, Sequence[PySide6.QtCore.QPoint], PySide6.QtCore.QRect], fillRule: PySide6.QtCore.Qt.FillRule = Instance(Qt.OddEvenFill)) -> None
QRegion(r: PySide6.QtCore.QRect, t: PySide6.QtGui.QRegion.RegionType = Instance(PySide6.QtGui.QRegion.RegionType.Rectangle)) -> None
QRegion(region: Union[PySide6.QtGui.QRegion, PySide6.QtGui.QBitmap, PySide6.QtGui.QPolygon, PySide6.QtCore.QRect]) -> None
QRegion(x: int, y: int, w: int, h: int, t: PySide6.QtGui.QRegion.RegionType = Instance(PySide6.QtGui.QRegion.RegionType.Rectangle)) -> None

QRegion 的常用方法如表所示主要方法介绍如下

QRegion的方法及参数类型 返回值类型 说明
boundingRect() QRect 获取边界
contains(QPoint) bool 获取是否包含指定的点
contains(QRect) bool 获取是否包含矩形
intersects(Union[QRegion, QBitmap, QPolygon, QRect]) bool 获取是否与区域相交
isEmpty() bool 获取是否为空
isNull() bool 获取是否无效
setRects(rect:QRect,num:int) None 设置多个矩形区域
rectCount() int 获取矩形区域的数量
begin()、cbegin() QRect 获取第一个非重合矩形
end()、cend() QRect 获取最后一个非重合矩形
intersected(Union[QRegion, QBitmap,QPolygon, QRect]) QRegion 获取相交区域
subtracted(Union[QRegion, QBitmap,QPolygon, QRect]) QRegion 获取减去区域后的区域
united(Union[QRegion,QBitmap,QPolygon,QRect]) QRegion 获取合并后的区域
xored(Union[QRegion,QBitmap,QPolygon,QRect]) QRegion 获取异或区域
translate(dx: int,dy:int) QRegion 获取平移后的区域
1ranslated(QPoint) QRegion 获取平移后的区域
swap(other:Union[QRegion,QBitmap, QPolygon, QRect]) None 交换区域
translate(dx:int,dy:int) None 平移区域
translate(p: QPoint) None 平移区域
  • QRegion可以进行交、减并和异或运算,这些运的示意图如图所示

image-20230308155714887

  • 用setRects(Sequence[QRect])方法可以设置多个矩形区域,多个矩形之间不能相互交叉,处于同一层的矩形必须有相同的高度,而不能连在一起,多个矩形可以合并成一个矩形。多个矩形首先按 值以升序排列,其次按 x值以升序排列。
QRegion 的应用实例

下面的程序将一个图像绘制到窗口中,只显示两个矩形和两个椭圆形区域内的图像,程序运行结果如图所示。

image-20230308160857526

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 15:58
# File_name: 09- QRegion 的应用实例.py


from PySide6.QtWidgets import QApplication, QWidget, QGraphicsWidget
from PySide6.QtGui import QPainter, QPixmap, QPainterPath, QBrush, QRegion
from PySide6.QtCore import QRect, Qt
import sys, os


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 500)
self.__pixmap = QPixmap("../../Resources/Images/正方形.png")

def paintEvent(self, event):
painter = QPainter(self) # 未确定绘图设备
painter.setClipping(True)

rect_1 = QRect(self.width() / 20, self.height() / 10, self.width() / 10 * 4, self.height() / 10 * 3)
rect_2 = QRect(self.width() / 20, self.height() / 10 * 5, self.width() / 10 * 4, self.height() / 10 * 3)
rect_3 = QRect(self.width() / 20 * 11, self.height() / 10, self.width() / 10 * 4, self.height() / 10 * 3)
rect_4 = QRect(self.width() / 20 * 11, self.height() / 10 * 5, self.width() / 10 * 4, self.height() / 10 * 3)

region_1 = QRegion(rect_1) # 矩形剪切区域
region_2 = QRegion(rect_2) # 矩形剪切区域
region_3 = QRegion(rect_3, t=QRegion.Ellipse) # 椭圆形剪切区域
region_4 = QRegion(rect_4, t=QRegion.Ellipse) # 椭圆形剪切区域

region = region_1.united(region_2) # 剪切区域并运算
region = region.united(region_3) # 剪切区域并运算
region = region.united(region_4) # 剪切区域并运算

painter.setClipRegion(region) # 在窗口上绘制图像
painter.drawPixmap(self.rect(), self.__pixmap)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

坐标变换QTransform

前面介绍的绘图都是在窗口坐标系下进行的,窗口坐标系的原点在屏幕的左上角,x轴水平向右,y轴竖直向下。使用窗口坐标系经常会不太方便,例如绘制一个对称的多边形时,需要计算出多边形的顶点坐标,这样比较麻烦,如果能把坐标系的原点移到对称多边形的中心,在移动后的坐标系中计算顶点坐标就比较简单了。

用QPainter 提供的变换坐标系方法进行坐标系变换

PySide6 提供了两种变换坐标系的方法

  • 一种方法是使用QPainter 提供的变换坐标系的方法
  • 另外一种方法是使用QTransform类。

QPainter 提供的变换坐标系的方法如表所示,可以对坐标系进行平移、缩放、旋转和错切。

对于错切 shear(sx,sy)方法的理解为,设(x0,y0)是变换前的一个点的坐标,则错切后的坐标是(sx*yo+x0,sy* x+y0)

变换坐标系的方法 说 明
translate(Union[QPointF, QPoint]) 平移坐标系
translate(dx: float,dy: float) 平移坐标系
rotate(float) 旋转坐标系
scale(sx:float,sy: float) 缩放坐标系
shear(sh: float,sv: float) 错切坐标系
resetTransform() 重置坐标系
save() 保存当前绘图状态
restore() 恢复绘图状态

下面的程序首先建立一个myPainterTransform类它继承自QWidget在该类中采用坐标变换的方法,重绘前面用到的太极图,并通过参数控制是否对太极图进行旋转、缩放和平移,这个 myPainterTransform 类相当于自定义的控件。在主程序类中,建立了四个myPainterTransform类的实例对象第一个能够旋转第二个能够缩放第三个能够平动第四个错切不动。

image-20230308165607059

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 16:18
# File_name: 10-用QPainter 提供的变换坐标系方法进行坐标系变换.py


from PySide6.QtWidgets import QApplication, QWidget, QSplitter, QHBoxLayout
from PySide6.QtGui import QPen, QPainter, QPainterPath, QBrush, QPalette, QTransform
from PySide6.QtCore import QPointF, Qt.QTimer
import sys


class myPainterTransform(QWidget): # 用坐标变换的方法创建太极图像
def __init__(self, rotational=False, scaled=False, translational=False, sheared=False, parent=None):
super().__init__(parent)

palette = self.palette()
palette.setColor(QPalette.Window, Qt.darkYellow)

self.setPalette(palette) # 设置窗口背景
self.setAutoFillBackground(True)
self.__rotational = rotational # 获取输人的参数值
self.__scaled = scaled # 获取输人的参数值
self.__translational = translational # 获取输人的参数值
self.__sheared = sheared # 获取输人的参数值

self.__rotation = 0 # 旋转角度
self.__scale = 1 # 缩放系数
self.__translation = 0 # 平移量
self.__sx = 0 # 错切系数
self.__sy = 0 # 错切系数

self.timer = QTimer(self)
self.timer.timeout.connect(self.timeout)
self.timer.setInterval(10)
self.timer.start() # 定时器

def paintEvent(self, event):
self.center = QPointF(self.width() / 2, self.height() / 2)
painter = QPainter(self)
painter.translate(self.center) # 将坐标系移动到中心位置

pen = QPen()
pen.setWidth(3)
pen.setColor(Qt.black)
painter.setPen(pen)

path = QPainterPath() # 路径
r = min(self.width(), self.height()) / 3 # 外部大圆的半径
r1 = r / 7 # 内部小圆的半径

path.moveTo(0, -r)
path.arcTo(-r, -r, 2 * r, 2 * r, 90, 360) # 外部大圆
path.arcTo(-r, -r, 2 * r, 2 * r, 90, -180) # 反向半圆

path.moveTo(0, r)
path.arcTo(-r / 2, 0, r, r, -90, 180) # 内部半圆
path.arcTo(-r / 2, -r, r, r, 270, -180) # 内部半圆

path.moveTo(r1, -r / 2) # 内部小圆
path.arcTo(-r1, -r / 2 - r1, 2 * r1, 2 * r1, 0, 360)

path.moveTo(r1, r / 2) # 内部小圆
path.arcTo(-r1, r / 2 - r1, 2 * r1, 2 * r1, 0, -360)

path.setFillRule(Qt.WindingFill) # 填充方式
brush = QBrush(Qt.SolidPattern)
painter.setBrush(brush) # 设置画刷

painter.rotate(self.__rotation) # 坐标系旋转
painter.scale(self.__scale, self.__scale) # 坐标系缩放

painter.translate(self.__translation, 0) # 坐标系平移
if self.__sheared:
painter.shear(self.__sx, self.__sy)

painter.drawPath(path) # 绘制路径
super().paintEvent(event)

def timeout(self):
if self.__rotational: # 设置坐标系的旋转角度值参数
if self.__rotation < - 360:
self.__rotation = 0
self.__rotation = self.__rotation - 1

if self.__scaled: # 设置坐标系的缩放比例参数
if self.__scale > 2:
self.__scale = 0.2
self.__scale = self.__scale + 0.005

if self.__translational: # 设置坐标系的平移量参数
if self.__translation > self.width() / 2 + min(self.width(), self.height()) / 3:
self.translation = - self.width() / 2 - min(self.width(), self.height()) / 3

self.translation = self.__translation + 1

self.update()

def setShearFactor(self, sx=0, sy=0):
self.__sx = sx
self.__sy = sy


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUi()
self.resize(800, 600)

def setupUi(self):
h = QHBoxLayout(self) # 布局
splitter_1 = QSplitter(Qt.Horizontal)
splitter_2 = QSplitter(Qt.Vertical)
splitter_3 = QSplitter(Qt.Vertical)
h.addWidget(splitter_1)
splitter_1.addWidget(splitter_2)
splitter_1.addWidget(splitter_3)

taiji_1 = myPainterTransform(rotational=True) # 第一个太极图,能够旋转
taiji_2 = myPainterTransform(scaled=True) # 第二个太极图,能够缩放
taiji_3 = myPainterTransform(translational=True) # 第三个太极图,能够平动
taiji_4 = myPainterTransform(sheared=True) # 第四个太极图,错切

taiji_4.setShearFactor(0.4, 0.2) # 设置错切系数
splitter_2.addWidget(taiji_1)
splitter_2.addWidget(taiji_2)

splitter_3.addWidget(taiji_3)
splitter_3.addWidget(taiji_4)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

用QTransform方法进行坐标系变换

采用坐标变换 QTransform可以进行更复杂的变换。

QTransform 是一个3X3的阵,用QTransform类创建变换矩阵的方法如下所示其中 hij参数是矩阵的元素值,类型都是 float。

1
2
3
4
5
6
from PySide6.QtGui import QTransform

QTransform(self) -> None
QTransform(h11: float, h12: float, h13: float, h21: float, h22: float, h23: float, h31: float, h32: float, h33: float) -> None
QTransform(h11: float, h12: float, h21: float, h22: float, dx: float, dy: float) -> None
QTransform(other: PySide6.QtGui.QTransform) -> None
  • 参数h11和h22是沿x轴和y轴方向的缩放比例;
  • h31和32是沿x轴和y轴方向的位移dx和d;
  • h21和h12是沿x轴和轴方的错切:
  • h13和h23是x轴和y轴方向的投影;
  • h33 是附加投影系数,通常取 1

对于二维空间中的一个坐标(x,y),可用(x,y,k)表示,其中k是一个不为0的缩放比例系数。当k-1时,坐标可以表示成(x,y,1),通过变换矩阵,可以得到新的坐标(x,y,1),

  • 用变换矩阵可以表示成

    image-20230308171221321

  • 对于沿着x和y方向的平移可以表示成

    image-20230308171338838

  • 对于沿着x和y方向的缩放可以表示成

    image-20230308171432561

  • 对于绕z轴旋转θ角可以表示成

    image-20230308171805643

  • 对于错切可以表示成

    image-20230308171853824

如果要进行多次不同的变换,可以将以上变换矩阵依次相乘,得到总的变换矩阵。以上是针对二维图形的变换,这些方法也可推广到三维变换

QTransform的常用方法如表所示

QTransform的方法及参数类型 返回值的类型 说明
rotate(a:float, axis: Qt.Axis = Qt.ZAxis) QTransform 获取以度表示的旋转矩阵,axis可取 Qt.XAxis,Qt.YAxis 或 Qt.ZAxis
rotateRadians(a: float,axis:Qt.Axis= Qt.ZAxis) QTransform 获取以弧度表示的旋转矩阵
scale(sx: float,sy: float) QTransform 获取缩放矩阵
shear(sh:float,sv: float) QTransform 获取错切矩阵
translate(dx: float,dy: float) QTransform 获取平移矩阵
dx()、dy() float 获取平移量
setMatrix(m11: float,m12: float,m13: float, m21: float, m22: float, m23: float, m31: float, m32: float, m33:float) None 设置矩阵的各个值
m11()、m12()、m13()、m21()、m22()、 m23()、m31()、m32()、m33() float 获取矩阵的各个值
transposed() QTransform 获取转置矩阵
isInvertible() bool 获取是否可逆
inverted() Tuple[Tuple,bool] 获取逆矩阵
isIdentity() bool 获取是否是单位矩阵
isAffine() bool 获取是否是放射变换
isRotating() bool 获取是否只是旋转变换
isScaling() bool 获取是否只是缩放变换
is Translating() bool 获取是否只是平移变换
adjoint() QTransform 获取共轭矩阵
determinant() float 获取矩阵的秩
reset() None 重置矩阵,对角线值为1,其他全部 为0
map(x:float,y: float) Tuple[float,float] 变换坐标值,即坐标值与变换矩阵 相乘
map(Union[QPointF,QPoint]) QPointF 变换点
map(Union[QLineF,QLine]) QLineF 变换线
map(Union[QPolygon, Sequence[QPoint],QRect]) QPolygon 变换多点到多边形
map(Union[QPolygonF,Sequence[QPointF],QPolygon.QRectF]) QPolygonF 变换多点到多边形
map(Union[QRegion, QBitmap, QPolygon,QRect]) QRegion 变换区域
map(p: QPainterPath) QPainterPath 变换路径
mapRect(Union[QRectF,QRect]) QRectF 变换矩形
mapToPolygon(QRect) QPolygon 将矩形变换到多边形
[static]fromScale(sx:float,sy: float) QTransform 由缩放量获取变换矩阵
[static]fromTranslate(dx: float, dy: float) QTransform 由平移量获取变换矩阵
  • QPainter 用setTransform(QTransform, combine = False)或 setWorldTransform(QTransform;combine=False)方法设置变换矩阵

    • 参数 combine表示是否在现有的变换上叠加新的变换矩阵,如果是 False 则设置新的变换矩阵;
  • 用transform()方法获取变换矩阵;

  • 用resetTransform()方法重置变换矩阵包括 window 和 viewport 的设置;

  • 用combinedTransform()方法获取 window、viewport 和 world 的组合变换矩阵;

  • 用deviceTransform(方法获取从逻辑坐标到设备坐标的变换矩阵。

下面的程序在新坐标系中绘制一个五角星。

窗口坐标系的原点在屏幕的左上角,从左到右是x轴,从上到下是轴。在屏幕坐标系下绘制几何图形时通常不方便。

下面的程序先利用translate()方法将坐标系的原点平移到屏幕的中心位置,再利用rotate()方法将坐标系沿着x轴旋转180,此时坐标系的y轴竖直向上,这就是我们通常意义上的坐标系的方向。

在绘制图形时,几何点位置直接在新坐标系中计算即可。

image-20230308172817166

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 17:21
# File_name: 11-用QTransform方法进行坐标系变换.py


import sys, math
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QTransform
from PySide6.QtCore import QPointF, Qt


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 500)

def paintEvent(self, event):
transform = QTransform()
transform.translate(self.width() / 2, self.height() / 2) # 沿着x轴旋转 180,轴向上
transform.rotate(180, Qt.Axis.XAxis) # 原点平移到窗口中心位置

painter = QPainter(self)
painter.setTransform(transform) # 设置变换
r = 100 # 五角星的外接圆半径

points = list()
for i in range(5):
x = r * math.cos((90 + 144 * i) * math.pi / 180)
y = r * math.sin((90 + 144 * i) * math.pi / 180)
points.append(QPointF(x, y))

painter.drawPolygon(points) # 绘制多边形


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

视口、逻辑窗口

除了用坐标变换进行绘图外,还可以把绘图设备的一部分区域定义成逻辑坐标,在逻辑坐标中绘制图形

  • 例如图(a)所示的屏幕窗口中有个矩形区域,在窗口坐标系 o‘x’y‘ 中表示为 QRect(100,100,30,200),如果把逻辑坐标系o’x’y定义在矩形区域的左上角,矩形区域的宽度和高度都定义成 100,则矩形区域在逻辑坐标系 o‘x’y‘ 中可以表示成 QRect(0.0,100,100),如图(b)所示。
  • 同样,如果把逻辑坐标系 o’xy 定义在矩形区域的中心,宽度和高度仍定义成 100,且y轴向上,则矩形区域可以表示成 QRect(-50,50,100,-100).如图(c)所示。

image-20230308173039230

  • 定义视口需要用QPainter 的 setViewport(viewport:QRect)方法或 setViewport(x:int, y:int, w:int, h:int)方法
  • 定义窗口的逻辑坐标需要用setWindow(window:QRect)方法或者 setWindow(x:int, y:int, w:int, h:int)方法。
    • 例如上图中的窗口,用painter.setViewport(100,100,300,200)定义视口,用painter.setWindow(0,0,100,100)或painter.setWindow(-50,50,100,100)定义窗口的逻辑坐标。
    • 如果要把坐标系的原点移到屏幕的左下角,x轴向左,y轴向上,则需要用setViewport(0,0,self.width(),self.height())方法定义视口,用setWindow(0,self.height(),self.width(),-self.height())方法定义逻辑窗口

下面的程序先在窗口中心建立一个逻辑窗口,逻辑坐标系的原点在中心位置,x 轴向左,y轴向上,绘制五角星,再将整个窗口定义成逻辑窗口,逻辑坐标系的原点在窗口的左下角,x轴向左,y轴向上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 17:32
# File_name: 12-视口、逻辑窗口.py


import sys, math
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter
from PySide6.QtCore import QPointF, QRect


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

# self.resize(600, 500)

def paintEvent(self, event):
painter = QPainter(self)
rect = QRect(int(self.width() / 2) - 200, int(self.height() / 2) - 100, 400, 200)
painter.drawRect(rect)
painter.setViewport(rect)
painter.setWindow(-100, 100, 200, -200)

r = 100 # 五角星的外接圆半径

points = list()
for i in range(5):
x = r * math.cos((90 + 144 * i) * math.pi / 180)
y = r * math.sin((90 + 144 * i) * math.pi / 180)
points.append(QPointF(x, y))

painter.drawPolygon(points) # 绘制多边形

painter.resetTransform() # 重置变换
painter.setViewport(0, 0, self.width(), self.height()) # 整个窗口是视口
painter.setWindow(0, self.height(), self.width(), - self.height()) # 窗口左下角为原点

painter.drawPolygon(points) # 在窗口左下角绘制多边形


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

图形合成

图形合成是指当绘制新图形时,绘图设备上已经存在旧图形,对新图形和旧图形进行处理的方法。

图形合成是基于像素,将旧图形的颜色值和 Alpha 通道的值与新图形的颜色值和Alpha 通道的值进行合成处理。

  • 图形合成的处理使用QPainter 的 setCompositionMode(mode:QPainter.CompositionMode)方法设置,

  • 用compositionMode()方法获取合成模式其中参数 mode是QPainter,CompositionMode 的举值,常用的几个取值如表所示,默认值是QPainter.CompositionMode_SourceOver。

    QPainter.CompositionMode的常用取值 说明
    QPainter.CompositionMode_SourceOver 这是默认模式。源的alpha用于混合目标顶部的像素。
    QPainter.CompositionMode_Source 输出是源像素。(这意味着基本的复制操作,当源像素不透明时,与SourceOver相同)。
    QPainter.CompositionMode_Destination 输出是目标像素。这意味着混合没有效果。此模式与CompositionMode_Source相反。
    QPainter.CompositionMode_DestinationOver 目标的alpha用于将其混合在源像素的顶部。此模式与CompositionMode_SourceOver相反。
    QPainter.CompositionMode_SourceIn 输出是源,其中alpha减去目标的alpha。
    QPainter.CompositionMode_DestinationIn 输出是目的地,其中alpha减少了源的alpha。此模式与CompositionMode_SourceIn相反。
    QPainter.CompositionMode_SourceOut 输出是源,其中alpha减少目标的倒数。
    QPainter.CompositionMode_DestinationOut 输出是目的地,其中alpha减少了源的倒数。此模式与CompositionMode_SourceOut相反。
    QPainter.CompositionMode_SourceAtop 源像素在目标像素的顶部混合,源像素的alpha减去目标像素的alpha。
    QPainter.CompositionMode_DestinationAtop 目标像素在源的顶部混合,目标像素的alpha值减去目标像素的alpha值。此模式与CompositionMode_SourceAtop相反。
    QPainter.CompositionMode_Clear 目标中的像素被清除(设置为完全透明),与源无关。
    QPainter.CompositionMode_Xor 源(其alpha与目标alpha的倒数减小)与目标(其alpha减小源alpha的倒数)合并。CompositionMode_Xor与按位Xor不同。
    QPainter.CompositionMode_Plus 源像素和目标像素的alpha和颜色都添加在一起。
    QPainter.CompositionMode_Multiply 输出是源颜色乘以目标颜色。将颜色与白色相乘会使颜色保持不变,而将颜色与黑色相乘会产生黑色。
    QPainter.CompositionMode_Screen 源颜色和目标颜色被反转,然后相乘。用白色屏蔽颜色会产生白色,而用黑色屏蔽颜色会使颜色保持不变。
    QPainter.CompositionMode_Overlay 根据目标颜色倍增或屏蔽颜色。目的地颜色与源颜色混合,以反映目的地的明度或暗度。
    QPainter.CompositionMode_Darken 选择源颜色和目标颜色中较深的颜色。
    QPainter.CompositionMode_Lighten 选择源颜色和目标颜色中的较浅颜色。
    QPainter.CompositionMode_ColorDodge 目标颜色变亮以反映源颜色。黑色源颜色保持目标颜色不变。
    QPainter.CompositionMode_ColorBurn 目标颜色变暗以反映源颜色。白色源颜色保持目标颜色不变。
    QPainter.CompositionMode_HardLight 根据源颜色倍增或屏蔽颜色。光源颜色将使目标颜色变亮,而暗光源颜色将变暗目标颜色。
    QPainter.CompositionMode_SoftLight 根据源颜色使颜色变暗或变亮。类似于CompositionMode_HardLight。
    QPainter.CompositionMode_Difference 从较亮的颜色中减去较暗的颜色。使用白色绘制将反转目标颜色,而使用黑色绘制将保持目标颜色不变。
    QPainter.CompositionMode_Exclusion 类似于CompositionMode_Difference,但对比度较低。使用白色绘制将反转目标颜色,而使用黑色绘制将保持目标颜色不变。
    QPainter.RasterOp_SourceOrDestination 对源像素和目标像素执行逐位OR运算(src OR dst)。
    QPainter.RasterOp_SourceAndDestination 对源像素和目标像素执行逐位AND运算(src AND dst)。
    QPainter.RasterOp_SourceXorDestination 对源像素和目标像素执行逐位XOR运算(src XOR dst)。
    QPainter.RasterOp_NotSourceAndNotDestination 对源像素和目标像素((NOT src)and(NOT dst))执行逐位NOR操作。
    QPainer.RasterOp_NotSource或NotDestination 对源像素和目标像素执行逐位”与非”运算((NOT src)OR(NOT dst))。
    QPainter.RasterOp_NotSourceXorDestination 执行逐位操作,其中源像素被反转,然后与目标像素进行异或运算((NOT src)XOR dst)。
    QPainter.RasterOp_NotSource 在源像素反转的情况下执行逐位操作(NOT src)。
    QPainter.RasterOp_NotSourceAndDestination 执行逐位操作,其中源被反转,然后与目标进行”与”运算((NOT src)and dst)。
    QPainter.RasterOp_SourceAndNotDestination 执行逐位操作,其中源与反转的目标像素进行”与”运算(src AND(NOT dst))。
    QPainter.RasterOp_NotSourceOrDestination 执行逐位操作,其中源被反转,然后与目标进行”或”运算((NOT src)OR dst)。
    QPainter.RasterOp_ClearDestination 目标中的像素被清除(设置为0),与源无关。
    QPainter.RasterOp_SetDestination 目标中的像素设置(设置为1)与源无关。
    QPainter.RasterOp_NotDestination 执行目标像素反转(NOT dst)的逐位操作。
    QPainter.RasterOp_SourceOrNotDestination 执行逐位运算,其中源与反转的目标像素进行”或”运算(src OR(NOT dst))。
    • 这几种取值的效果如图所示其中Source表示新绘制的图形,Destination 表示旧图形。

      image-20230308175426672

下面所示绘图程序先绘制一个图片,再用绘图路径添加矩形和一个椭圆,在矩形和椭圆之间填充黑色。采用QPainter.CompositionMode_SourceOver 合成方式将两个图形合成后的效果如图所示。

image-20230308175150289

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 17:43
# File_name: 13-图形合成实例.py


import sys
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPixmap, QPainterPath, QBrush
from PySide6.QtCore import QRectF, Qt


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 500)
self.__pixmap = QPixmap("../../Resources/Images/正方形.png")

def paintEvent(self, event):
painter = QPainter(self)

painter.drawPixmap(self.rect(), self.__pixmap) # 绘制图片

rect = QRectF(0, 0, self.width(), self.height()) # 获取窗口的矩形
path = QPainterPath() # 绘图路径
path.addRect(rect) # 添加短形
path.addEllipse(rect) # 添加椭圆
path.setFillRule(Qt.FillRule.OddEvenFill) # 设置填究方式

brush = QBrush(Qt.SolidPattern) # 画刷
brush.setColor(Qt.black)
painter.setBrush(brush) # 设登画刷

painter.setCompositionMode(QPainter.CompositionMode_SourceOver) # 设置图像合成方式
painter.drawPath(path)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

Graphics/View绘图

Graphics/View绘图框架介绍

Graphics/View 绘图框架类似于前面介绍的Model/View 机制。Graphics 指QGraphicsScene(场景)类,它是不可见的,相当于一个容器,在它里面放置各种图项(QGraphicsItem)并对放置的图项进行管理;View 指QGraphicsView 控件,QGraphicsScene 中的绘图项通过 QGraphicsView 控件显示出来,同一个 QGraphicsScene可以用多个QGraphicsView 显示

Graphics/View 框架结构主要包含三个主要的类:QGraphicsScene QGraphicsView和各种QGraphicsItem。QGraphicsScene(场景)本身不可见,但又是存储和管理2D图项的容器,场景没有自己的视觉外观,只负责管理图项,必须通过与之相连的 QGraphicsView 控件来显示图项及与外界进行交互操作。QGraphicsScene主要提供图项的操作接口,传递事件和管理各个图项的状态,提供无变换的绘制功能(如打印)。QGraphicsView 提供一个可视的窗口,用于显示场景中的图项。QGraphicsItem是场景中图项的基类图项有自定义的图项(继承自QGraphicsItem 的子类),还有标准的图项,例如矩形(QGraphicsRectItem)多边形(QGraphicsPolygonItem)、椭圆(QGraphicsEllipseItem)、路径(QGraphicsPathItem)线条(GraphicsLineltem)和文本(QGraphicsTextItem)等。读者可以把 QGraphicsScene理解成电影胶卷,把QGraphicsView 理解成电影放映机,而把图项理解成电影胶卷中的人物、树木、建筑物等。

QPainter采用面向过程的描述方式绘图,而 Graphics/View 采用面向对象的描述方式绘图。Graphics/View 框架中的每一个图项都是一个独立的元素,可以对图项进行操作,图项支持鼠标操作,可以对图项进行按下、移动、释放、双击、滚轮滚动和右键菜单操作,还支持键盘输人和拖放操作。Grphics/View 绘图时首先创建一个场景,然后创建图项对象(如直线对象、矩形对象),再使用场景的 add()丽数,将图项对象添加到场景中,最后通过视图控件进行显示。对于复杂的图像来说,如果其中包含大量的直线、曲线、多边形等对象,管理图项对象比管理 QPainter 的绘制过程语句要容易,并且图项对象更符合面向对象的思想,图形的重复使用性更好。

Graphics/View坐标系

Graphics/View 坐标系基于笛卡儿坐标系,图项在场景中的位置和几何形状通过 x坐标和y坐标表示。当使用没有变换的视图观察场景时,场景中的一个单位对应屏幕上的一个像素。
Graphics/View 架构中有三种坐标系统,分别是图项坐标、场景坐标和视图坐标。场景坐标类似于 QPainter 的逻辑坐标,一般以场景的中心为原点;视图标是窗口界面的物理坐标,其左上角为坐标原点,图项坐标是局部逻辑坐标,通常以图项的中心为原点。Graphics/View 提供了三个坐标系统之间的转换函数。

图项坐标、场景坐标和视图坐标

图项存在于自己的本地坐标上,图项的坐标系通常以图项中心为原点,图项中心也是所有坐标变换的原点,图项坐标方向是 x轴正方向向右,y 轴正方向向下。

创建自定义图项时,需要注意图项的坐标,QGraphicsScene 和 QGraphicsView 会完成所有的变换。

  • 例如,如果接收到一个鼠标按下或拖人事件,所给的事件位置是基于图项坐标系的。如果某个点位于图项内部,使用图项上的点作为 QGraphicsItem.contains()虚函数的参数,函数会返回True。类似地,图项的边界矩形和形状也基于图项坐标系。
  • 图项的位置是图项的中心点在其父图项坐标系统的坐标,场景可以理解成顶层图项,子图项的坐标与父图项的坐标相关,如果子图项无变换,则子图项坐标和父图项坐标之间的区别与它们的父图项的坐标相同。例如,如果一个无变换的子图项精确地位于父图项的中心点,则父子图项的坐标系统是相同的。
  • 如果子图项的位置是(100,0),子图项上的点(0,100)就是父图项上的点(100,100)。即使图项的位置和变换与父图项相关,子图项的坐标也不会被父图项的变换影响,虽然父图项的变换会隐式地变换子图项。例如,即使父图项被翻转和缩放,子图项上的点(0,100)仍旧是父图项上的点(100,100)。
  • 如果调用QGraphicsItem类的 paint()函数重绘图项,应以图项坐标系为基准场景坐标是所有图项的基础坐标系统。场景坐标系统描述了顶层图项的位置,并且构成从视图到场景的所有场景事件的基础。每个图项在场景上都有场景坐标和边界矩形。场景坐标的原点在场景中心,坐标方向是x轴正方向向右,轴正方向向下。视图坐标是窗口控件的坐标,视图坐标的单位是像素,QGraphicsView 的左上角是(00)。所有鼠标事件、拖拽事件最开始都使用视图坐标,为了和图项交瓦,需要转换为场景坐标。
坐标变换函数

在Graphics/View框架中,经常需要在不同种坐标间进行变换:从视图到场景,从场景到图项,从图项到图项。Graphics/View 框架中的坐标变换函数如下

  • QGraphicsView.mapToScene()视图到场景
  • QGraphicsView.mapFromScene()场景到视图
  • QGraphicsItemmapFromScene()场景到图项
  • QGraphicsItem.mapToScene()图项到场景
  • QGraphicsItem.mapToParent()子图项到父图项
  • QGraphicsItem.mapFromParent()父图项到子图项
  • QGraphicsItem.mapToItem()本图项到其他图项
  • QGraphicsItem,mapFromItem()其他图项到本图项

在场景中处理图项时,经常需要在场景到图项、图项到图项、视图到场景间进行坐标和图形转换。

  • 当在 QGraphicsView 的视口中单击鼠标时,应该通过调用QGraphicsView.mapToScence()与 QGraphicsScene,itemAt()函数来获知光标下是场景中的哪个图项;
  • 如果想获知一个图项在视口中的位置,应该先在图项上调用QGraphicsItemmapToScene()函数,然后调用QGraphicsView,mapFromScene()函数;
  • 如果想获知在一个视图中有哪些图项,应该把 QPainterPath 传递到 mapToScene()函数,然后再把映射后的路径传递到QGraphicsScene, items()函数。
  • 可以调用QGraphicsItem,mapToScene()函数与QGraphicsItem,mapFromScene()函数在图项与场景之间进行坐标与形状的映射,也可以在子图项与其父图项之间通过QGraphicsItem,mapToParent()与QGraphicsItem.mapFromItem()函数进行映射。
  • 所有映射函数可以包括点、矩形、多边形路径。视图与场景之间的映射也与此类似。对于视图与图项之间的映射,应该先从视图映射到场景,然后再从场景映射到图项。

视图控件QGraphicsVicw

视图控件QGraphicsView 用于显示场景中的图项,当场景超过视图区域时,视图会提供滚动条。

视图控件QGraphicsView 继承自 QAbstractScrollArea,视图控件根据场景的尺寸提供滚动区,当视图尺寸小于场景尺寸时会提供滚动条。

用QGraphicsView 类创建视图控件对象的方法如下所示其中parent是继承自QWidget 的窗口或控件;QGraphicsScene是场景实例对象,用于设置视图控件中的场景。

1
2
3
4
from PySide6.QtWidgets import QGraphicsView

QGraphicsView(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QGraphicsView(scene: PySide6.QtWidgets.QGraphicsScene, parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
视图控件QGraphicsView的常用方法

视图控件的方法较多,一些常用方法如表所示

QGraphicsView的常用方法及参数类型 说:明
setScene(scene:QGraphicsScene) 设置场景
scene() 获取场景QGraphicsScene
setSceneRect(rect:Union[QRectF,QRect]) 设置场景在视图中的范围
setSceneRect(x: float,y: float,w: float,h: float) 设置场景在视图中的范围
sceneRect() 获取场景在视图中的范围 QRectF
setAlignment(alignment: Qt.Alignment) 设置场景全部可见时的对齐方式
setBackgroundBrush(brush:Union[QBrush,Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage,QPixmap]) 设置视图背景画刷
setForegroundBrush(brush: Union[QBrusb, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage,QPixmap]) 设置视图前景画刷
drawBackground(painter:QPainter,rect:Union[QRectF,QRect]) 重写该函数,在显示前景和图项前绘制背景
drawForeground(painter: QPainter,rect: Union[QRectF,QRect]) 重写该函数,在显示背景和图项后绘制前景
centerOn(pos: :Union[QPointF, QPoint.QPainterPath.Element]) 使某个点位于视图控件中心
centerOn(x:float,y: float) 使某个点位于视图控件中心
centerOn(item: QGraphicsItem) 使某个图项位于视图控件中心
ensureVisible(rect: Union[QRectF,QRectJ.xmargin:int=50,ymargin: int=50) 确保指定的矩形区域可见,可见时按指定的边距显 示;如不可见,滚动到最近的点
ensureVisible(x: float.y:float,w: float,h: float.xmargin:int=50,ymargin: int=50) 确保指定的矩形区域可见,可见时按指定的边距显 示;如不可见,滚动到最近的点
ensureVisible(QGraphicsItem,xmargin:int=50, ymargin: int=50) 确保指定的图项可见
fitInView(rect: Union[QRectF, QRect], aspectRadioMode: Qt.AspectRatioMode = Qt.IgnoreAspectRatio) 以适合方式使矩形区域可见
fitInView(x:float,y: float,w: float,h: float, aspectRadioMode: Qt.AspectRatioMode = Qt.IgnoreAspectRatio) 以适合方式使矩形区域可见
fitInView(item: QGraphicsItem,aspectRadioMode: Qt.AspectRatioMode=Qt.IgnoreAspectRatio) 以适合方式使图项可见
render(painter: QPainter,target: Union[QRectF, QRect], source: QRect, aspectRatioMode = Qt.KeepAspectRatio) 从source(视图)把图像复制到target(其他设备如 QImage)上
resetCachedContent() 重置缓存
rubberBandRect() 获取用鼠标框选的范围 QRect
setCacheMode(mode: QGraphicsView.CacheMode) 设置缓存模式 .
setDragMode(mode; QGraphicsView.DragMode) 设置鼠标拖拽模式
setInteractive(allowed:bool) 设置是否是交互模式
isInteractive() 获取是否是交互模式
setOptimizationFlag(flag: QGraphicsView.OptimizationFlag,enabled: bool=True) 设置优化显示标识
setOptimizationFlags(flags: QGraphicsView.OptimizationFlags) 设置优化显示标识
setRenderHint(hint: QPainter.RenderHint, enabled: bool=True) 恋雯豆济 设置提高绘图质量标识
setRenderHints(hints:QPainter.RenderHints) 设置提高绘图质量标识
setResizeAnchor(QGraphicsView.ViewportAnchor) 设置视图控件改变尺寸时的锚点
resizeAnchor() 获取锚点
setRubberBandSelectionMode(Qt.ItemSelectionMode) 设置用鼠标框选模式
setTransform(matrix: QTransform,combine: bool=False) 用变换矩阵变换视图
transform() 获取变换矩阵 QTransform
isTransformed() 获取是否进行过变换
resetTransform() 重置变换
setTransformationAnchor(QGraphicsView.ViewportAnchor) 设置变换时的锚点
setViewportUpdateMode(QGraphicsView.ViewportUpdateMode) 设置刷新模式
[slot]updateScene(rects: Sequence[QRectF]) 更新场景
[slot]updateSceneRect(rect: Union[QRectF, QRect]) 更新场景
[slot]invalidateScene(rect: Union[QRectF, QRect], layers: QGraphicsScene.SceneLayers= QGraphicsScene.AllLayers) 使指定的场景区域进行更新和重新绘制,相当于对 指定区域进行 update()操作
setupViewport(QWidget) 重写该函数,设置视口控件
scale(sx: float, sy: float) 缩放
rotate(angle: float) 旋转角度,瞬时针方向为正
shear(sh: float,sv:float) 错切
translate(dx: float,dy:float) 平移

视图控件获取图项的方法如表所示

QGraphicsView 获取图项的方法 返回值的类型
itemAt(pos:QPoint) QGraphicsItem
itemAt(x:int,y:int) QGraphicsItem
items() List[QGraphicsItem]
items(pos: QPoint) List[QGraphicsItem]
items(x:int,y:int) List[QGraphicsItem]
items(x: int, y: int, w: int,h: int, mode = Qt.IntersectsItemShape) List[QGraphicsItem]
items(rect: QRect, mode: Qt.ItemSelectionMode = Qt.IntersectsItemShape) List[QGraphicsItem]
items(polygon: Union[QPolygon,Sequence[QPoint],QRect], mode: Qt.ItemSelectionMode=Qt.IntersectsItemShape) List[QGraphicsItem]
items(QPainterPath, mode: Qt.ItemSelectionMode = Qt.IntersectsItemShape) List[QGraphicsItem]887:590

视图控件中点的坐标与场景坐标互相转换的方法如表所示

场景到视图的坐标变换方法 返回值类型
mapFromScene(Union[QPointF, QPoint]) QPoint
mapFromScene(QRectF) QPolygon
mapFromScene(polygon: Union[QPolygonF,Sequence[QPointF], QPolygon,QRectF]) QPolygon
mapFromScene(path:QPainterPath) QPainterPath
mapFromScene(x: float.y: float) QPoint
mapFromScene(x: float,y: float, w:float,h: float) QPolygon
mapToScene(point:QPoint) QPointF
mapToScene(rect: QRect) QPolygonF
mapToScene(Union[QPolygon, Sequence[QPoint],QRect]) QPolygonF
mapToScene(QPainterPath) QPainterPath
mapToScene(x:int,y: int) QPointF
mapToScene(int,int,int,int) QPolygonF

主要方法介绍如下。

  • 给视图控件设置场景,可以在创建视图对象时设置,也可以用setScene(QGraphicsScene)方法设置;用scene()方法获取场景。
  • 用setSceneRect(rect; Union[QRectF,QRect])方法或 setSceneRect(x: float,y:float,w;float,h;float)方法设置场景在视图中的范围,用sceneRect()方法获取场景在视图中的范围,当场景的面积超过视图所显示的范围时,可用滚动条来移动场景。
  • 用setAlignment(Qt.Alignment)方法设置场景在视图控件全部可见时的对齐方式Qt.Alignment 可以取以下值,默认是 Qt.AlignCenter
    • Qt.AlignLeft
    • Qt.AlignRight
    • Qt.AlignHCenter
    • Qt.AlignJustify
    • Qt.AlignTop,
    • Qt.AlignBottom
    • Qt.AlignVCenter
    • Qt.AlignBaseline
    • Qt.AlignCenter
  • 创建视图控件的子类,并重写 drawBackground(QPainter,QRectF)函数可以在显示前景和图项之前绘制背景;
    • 重写 drawForeground(QPainter;QRectF)函数,可以在显示背景和图项之后绘制前景。
    • 场景分为背景层、图项层和前景层三层,前面的层会挡住后面的层。
  • 用setCacheMode(mode:QGraphicsView.CacheMode)方法可以设置缓存模式,参数 mode可取:
    • QGraphicsView.CacheNone(没有缓存)
    • QGraphicsView.CacheBackground(缓存背景)
  • 用setInteractive(bool)方法设置视图控件是否是交互模式在交互模式下可以接受鼠标键盘事件;
  • 用isInteractive()方法可以获取是否是交互模式用setDragMode(mode:QGraphicsViewDragMode)方法设置在视图控件中按住鼠标左键选择图项时的拖拽模式,参数 mode 可取:
    • QGraphicsView.NoDrag(忽略鼠标事件)
    • QGraphicsView.ScrollHandDrag(在交互或非交互模式下,光标变成手的形状,拖动鼠标会移动整个场景)
    • QGraphicsView.RubberBandDrag(在交互模式下可以框选图项)。
  • 用setRubberBandSelectionMode(QtItemSelectionMode)方法设置框选图项时,图项是否能被选中,其中参数 Qt ItemSelectionMode可以取:
    • QtContainsItemShapeQt.IntersectsItemShape
    • Qt.ContainsItemBoundingRect
    • Qt.IntersectsItemBoundingRect
  • 用setOptimizationFlag(flag;QGraphicsView.OptimizationFlag,enabled: bool=True)方法设置视图控件优化显示标识,参数 lag可以取:
    • QGraphicsView.DontSavePainterState(不保存绘图状态)
    • QGraphicsView.DontAdjustForAntialiasing(不调整反锯齿)
    • QGraphicsView.IndirectPainting(间接绘制)。
  • 用scale(sx; float,sy:float)方法、rotate(angle; float)方法、shear(sh; float;sv:float)方法和translate(dx:floatdy: flat)方法可以对场景进行缩放、旋转、错切和平移,
  • 用setTransform(matrix;QTransform;combine:bool=False)方法可以用变换矩阵对场景进行变换。
  • 用setResizeAnchor(QGraphicsViewViewportAnchor)方法设置视图尺寸发生改变时的错点;
  • 用setTransformationAnchor(QGraphicsViewViewportAnchor)方法设置对视图进行坐标变换时的锚点,锚点的作用是定位场景在视图控件中的位置。其中QGraphicsView.ViewportAnchor可取:
    • QGraphicsView.NoAnchor(没有锚点,场景位置不变)
    • QGraphicsView.AnchorViewCenter(场景在视图控件的中心点作为锚点)
    • QGraphicsView.AnchorUnderMouse(光标所在的位置作为错点)。
    • 如果场景在视图控件中全部可见将使用对齐设置 setAlignment(alignment:QtAlignment)的参数
  • 用setViewportUpdateMode(QGraphicsView.ViewportUpdateMode)方法设置视图刷新模式,参数 QGraphicsView,ViewportUpdateMode 可以取:
    • QGraphicsView.FullViewportUpdate
    • QGraphicsView.MinimalViewportUpdate
    • QGraphicsView.SmartViewportUpdate
    • QGraphicsView.BoundingRectViewportUpdate
    • QGraphicsView.NoViewportUpdate;
  • 可用槽函数 updateScene(rects; Sequence[QRectF])updateSceneRect(rect;Union[QRectF,QRect])或 invalidateScene(rect; UnionQGraphicsScene.SceneLayers = QGraphicsScene.[QRectF,QRect],layers:AllLayers)方法只刷新指定的区域,参数 layers 可以取:
    • QGraphicsScene.ItemLayer
    • QGraphicsScene.BackgroundLayer
    • QGraphicsScene.ForegroundLayer
    • QGraphicsScene.AllLayers
  • 用itemAt()方法可以获得光标位置处的一个图项,如果有多个图项,则获得最上面的图项;
    • 用items()方法可以获得多个图项列表,图项列表中的图项按照z值从顶到底的顺序排列。
    • 可以用矩形、多边形或路径获取其内部的图项,例如 items(QRect,mode=Qt、IntersectsItemShape)方法,参数 mode可取:
      • Qt.ContainsItemShape(图项完全在选择框内部)
      • Qt.IntersectsItemShape(图项在选择框内部和与选择框相交)
      • Qt.ContainsItemBoundingRect(图项的边界矩形完全在选择框内部)
      • Qt.IntersectsItemBoundingRect(图项的边界矩形完全在选择框内部和与选择框交叉)
  • 用mapFromScene()方法可以把场景中的一个点坐标转换成视图控件的坐标
    • mapToScene()方法可以把视图控件的一个点转换成场景中的坐标。
  • 由于QGraphicsView 继承自QWidget,因此 QGraphicsView 提供了拖拽功能Graphics/View框架也为场景图项提供拖拽支持。
    • 当视图控件接收到拖拽事件GraphicsView框架会将拖拽事件翻译成 QGraphicsSceneDragDropEvent 事件时再发送到场景,场景接管事件,再把事件发送到光标下接受拖拽的第一个图项。为了开启图项拖拽功能,需要在图项上创建一个 QDrag 对象。
  • 用setViewport(QWidget)方法可以设置视口的控件,如果不设置,会使用默认的控件。如果要使用OpenGL渲染,则需设置 setViewport(QOpenGLWidget)。
视图控件QGraphicsView信号

视图控件QGraphicsView只有一个信号 rubberBandChanged(viewportRect:QRect,fromScenePoint:QPointF,toScenePoint:QPointF),当框选的范围发生改变时发送信号。

视图控件QGraphicsView的应用实例

下面的程序首先建立视图控件的子类,创建自定义信号,信号的参数是单击鼠标或移动鼠标时光标在视图控件的位置,并重写了鼠标单击、移动事件和背景函数,然后在场景中建立一个矩形和一个圆用鼠标可以拖动矩形和圆,并在状态栏上显示鼠标拖动点的视图坐标、场景坐标和图项坐标。

image-20230308212554836

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/6 23:23
# File_name: 01- 视图控件QGraphicsView的应用实例.py


import sys
from PySide6.QtWidgets import QApplication, QWidget, QGraphicsScene, QGraphicsView, QVBoxLayout, QStatusBar, QGraphicsRectItem, QGraphicsItem, QGraphicsEllipseItem
from PySide6.QtCore import Qt.Signal, QPoint, QRectF


class myGraphicsView(QGraphicsView): # 视图控件的子类
point_position = Signal(QPoint) # 自定义信号,参数是光标在视图中的位置

def __init_(self, parent=None):
super().__init__(parent)

def mousePressEvent(self, event): # 鼠标单击事件
self.point_position.emit(event.position()) # 发送信号,参数是光标位置
super().mousePressEvent(event)

def mouseMoveEvent(self, event): # 鼠标移动事件
self.point_position.emit(event.position())
super().mouseMoveEvent(event) # 发送信号,参数是光标位置

def drawBackground(self, painter, rectF):
painter.fillRect(rectF, Qt.gray) # 重写背景函数,设置背景颜色


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupUI()

def setupUI(self):
self.graphicsView = myGraphicsView() # 视图窗口
self.statusbar = QStatusBar() # 状态栏
v = QVBoxLayout(self)
v.addWidget(self.graphicsView)
v.addWidget(self.statusbar)
rectF = QRectF(-200, - 150, 00, 300)
self.graphicsScene = QGraphicsScene(rectF) # 创建场景

self.graphicsView.setScene(self.graphicsScene) # 视图窗口设置场景
rect_item = QGraphicsRectItem(rectF) # 以场景为坐标创建矩形

rect_item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) # 标识
self.graphicsScene.addItem(rect_item) # 在场景中添加图项
rectF = QRectF(-40, -40, 80, 80)
ellipse_item = QGraphicsEllipseItem(rectF) # 以场景为坐标创建椭圆
ellipse_item.setBrush(Qt.green) # 设置画刷

ellipse_item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) # 标识
self.graphicsScene.addItem(ellipse_item) # 在场景中添加图项
self.graphicsView.point_position.connect(self.mousePosition) # 信号与槽的连接

def mousePosition(self, point): # 槽函数
template = "view坐标:{},{} scene坐标:{},{} item坐标:{},{}"
point_scene = self.graphicsView.mapToScene(point) # 视图中的点映射到场景中
item = self.graphicsView.itemAt(point) # 获取视图控件中的图项

# item = self.graphicsScene.itemAt(point_scene, self.graphicsView.transform()) # 场景中图项

if item:
point_item = item.mapFromScene(point_scene) # 把场景坐标转换为图项坐标
string = template.format(point.x(), point.y(), point_scene.x(), point_scene.y(), point_item.x(), point_item.y())

else:
string = template.format(point.x(), point.y(), point_scene.x(), point_scene.y(), "None", "None")
self.statusbar.showMessage(string) # 在状态栏中显示坐标信息


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

场景QGraphicsScene

场景 QGraphicsScene是图项的容器,用于存放和管理图项。

QGraphicsScene 继承自QObject,用QGraphicsScene 类创建场景实例对象的方法如下,其中parent 是继承自QObiect 的实例对象,QRetQRectF 定义场景的范围。

用场景范围来确定视图的默认可滚动区域,场景主要使用它来管理图形项索引。如果未设置或者设置为无效的矩形则sceneRect()方法将返回自创建场景以来场景中所有图形项的最大边界矩形即当在场景中添加或移动图形项时范围会增大,但不会减小。

1
2
3
4
5
from PySide6.QtWidgets import QGraphicsScene

QGraphicsScene(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QGraphicsScene(sceneRect: Union[PySide6.QtCore.QRectF, PySide6.QtCore.QRect], parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QGraphicsScene(x: float, y: float, width: float, height: float, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
场景 QGraphicsScene 的常用方法
场景中添加和删除图项的方法如表所示
QGraphicsScene 中添加和移除图项的方法 返回值的类型 说明
addItem(QGraphicsItem) None 添加图项
addEllipse(rect:Union[QRectF,QRect],pen:Union[QPen,Qt.PenStyle,QColor],brush: Union[QBrush, Qt.BrushStyle, Qt.GlobalColor,QColor, QGradient, QImage,QPixmap]) QGraphicsEllipseItem 添加椭圆
addEllipse(x: float,y: float,w: float,h: float,pen, brush) QGraphicsEllipseItem 添加椭圆
addLine(line: Union[QLineF,QLine],pen) QGraphicsLineItem 添加线
addLine(xl: float,yl:float,x2: float,y2: float,pen) QGraphicsLineItem 添加线
addPath(path:QPainterPath,pen,brusb) QGraphicsPathItem 添加绘图路径
addPixmap(pixmap:Union[QPixmap,QImage,str]) QGraphicsPixmapItem 添加图像
addPolygon(polygon:Union[QPolygonF, Sequence[QPointF],QPolygon,QRectF],pen,brush) QGraphicsPolygonItem 添加多边形
addRect(rect: Union[QRectF,QRect],pen,brush) QGraphicsRectItem 添加矩形
addRect(x: float, y: float,w: float, h: float, pen, brush) . QGraphicsRectItem 添加矩形
addSimpleText(text: str,font; Union[QFont,str]) QGraphicsSimpleTextItem 添加简单文字
addText(text: str,font:Union[QFont,str]) QGraphicsTextItem 添加文字
addWidget(QWidget,wFlags:Qt.WindowFlags) QGraphicsProxyWidget 添加图形控件
removeItem(QGraphicsItem) None 移除图项
[slot]clear() None 清空所有图项
场景获取图项的方法如表所示
QGraphicsScene 获取图项的方法及参数类型 返回值的类型
itemAt(pos: Union[QPointF, QPoint, QPainterPath.Element].deviceTransform: QTransform) QGraphiesItem
itemAt(x: float,y: float.deviceTransform: QTransform) QGraphicsItem
jtems(order:Qt.SortOrder=Qt.DescendingOrder) List[QGraphicsItem]
items(path: QPainterPath, mode: Qt.ItemSelectionMode = Qt.IntersectsItemShape,order,deviceTransform) List[QGraphiesItemJ .
items(polygon: Union[QPolygonF,Sequence[QPointF],QPolygon,QRectF], mode.order,deviceTransform) List[QGraphicsItem]
items(pos: Union[QPointF, QPoint, QPainterPath.Element],mode, order, deviceTransform) List[QGraphiesItem]
items(rect: Union[QRectF,QRect],mode,order,deviceTransform) List[QGraphicsItem]
items(x: float,y: float,w: float,h: float, mode,order,deviceTransform) List[QGraphicsItem]
场景的其他常用方法如表所示
QGraphicsScene的其他常用方法及参数类型 说 明
setSceneRect(rect:Union[QRectF,QRect]) 设置场景范围
setSceneRect(x:float,y:float,w: float,h: float) 设置场景范围
sceneRect() 获取场景范围 QRectF
width()、height() 获取场景的宽度和高度
collidingItems(QGraphicsItem,mode=Qt.IntersectsItemShape) 获取碰撞的图项列表 List[QGraphicsltem]
createItemGroup(Sequence[QGraphicsItem]) 创建组,返回QGraphicsItemGroup
destroyItemGroup(QGraphicsItemGroup) 打散图项组
hasFocus() 获取场景是否有焦点,有焦点时可以接受键盘 事件
clearFocus() 使场景失去焦点
[slot]invalidate(rect: Union[QRectF, QRect], layers =QGraphicsScene.AllLayers) 刷新指定的区域
invalidate(x:float,y: float,w: float,h: float, layers=QGraphicsScene.AllLayers) 刷新指定的区域
[slot]update(rect:Union[QRectF,QRect]) 更新区域
update(x:float,y: float,w: float.h: float) 更新区域
isActive() 场景用视图显示且视图活跃时返回True
itemsBoundingRect() 获取图项的矩形区域 QRectF
mouseGrabberItem() 获取光标抓取的图项 QGraphicsltem
render(QPainter, target=QRectF(),source=QRectF(),mode=Qt.KeepAspectRatio) 将指定区域的图形复制到其他设备的指定区 域上
selectedItems() 获取选中的图项列表 List[QGraphicsltem]
setActivePanel(item; QGraphicsItem) 将场景中的图项设置成活跃图项
activePanel() 获取活跃的图项
setActiveWindow(widget:QGraphicsWidget) 将场景的视图控件设置成活跃控件
setBackgroundBrush(Union[QBrush, QColor, Qt.GlobalColor,QGradient]) 设置背景画刷
setForegroundBrush(Union[QBrush,QColor,Qt.GlobalColor,QGradient]) 设置前景画刷
drawBackground(QPainter,QRectF) 重写该函数,绘制背景
drawForeground(QPainter,QRectF) 重写该函数,绘制前景
backgroundBrush()、foregroundBrush() 获取背景画刷、获取前景画刷QBrush
setFocus(focusReason=Qt.OtherFocusReason) 使场景获得焦点
setFocusItem(QGraphicsltem,focusReason: Qt.FocusReason=Qt.OtherFocusReason) 使某个图项获得焦点
focusItem() 获取有焦点的图项
setFocusOnTouch(bool) 在平板电脑上通过手触碰获得焦点
focusNextPrevChild(next:bool) 查找一个新的图形控件,以使键盘焦点对准 Tab 键和Shift+ Tab键,如果可以找到则返回 true;否则返回false。如果next为true则此函 数向前搜索,否则向后搜索
setItemIndexMethod(QGraphicsScene.ItemIndexMethod) 设置图项搜索方法
setBspTreeDepth(int) 设置 BSP 树的搜索深度
setMinimumRenderSize(float) 图项变换后,尺寸小于设置的尺寸时不渲染
setSelectionArea(path: QPainterPath,deviceTransform) 将绘图路径内的图项选中,外部的图项取消选 中。对于需要选中的图项,必须标记为 QGraphicsItem.ItemIsSelectable
setSelectionArea(path: QPainterPath, selectionOperation: Qt.ItemSelectionOperation = Qt.ReplaceSelection, mode: Qt.ItemSelectionMode = Qt.IntersectsItemShape, deviceTransform: QTransform =Default(QTransform)) 将绘图路径内的图项选中,外部的图项取消选 中。对于需要选中的图项,必须标记为 QGraphicsItem.ItemIsSelectable
selectionArea() 获取选中区域内的绘图路径QPainterPath
[slot]clearSelection() 取消选择
setStickyFocus(enabled:bool) 单击背景或者单击不接受焦点的图项时,是否 失去焦点
setFont(QFont) 设置字体
setPalette(QPalette) 设置调色板
setStyle(QStyle) 设置风格
views() 获取场景关联的视图控件列表
[slot]advance() 调用图项的advance()方法,通知图项可移动
主要方法介绍如下
  • 场景中添加从 QGraphicsItem 继承的子类的方法是 addItem(QGraphicsItem)。

    • 另外还可以添加一些标准的图项,用addEllipse()、addLine() addPath() addPixmap()、addPolygon()、addRect()addSimpleText()addText()和 addWidget()方法可以添加椭圆、直线、绘图路径、图像、多边形、矩形、简单文本、文本和控件,并返回图项。
    • 其中用addWidget(QWidget,Qt.WindowType)方法可以将一个控件以代理控件的方法添加到场景中,并返回代理控件,按照添加顺序,后添加的图项会在先添加图项的前端;
    • 用removeItem(QGraphicsItem)方法可以从场景中移除图项用clear()方法可以移除所有的图项。
  • 用itemAt(pos: Union[QPointF, QPoint, QPainterPath, Element], deviceTransform :QTransform)或itemAt(x: float,y:float,deviceTransform:QTransform)方法可以获得某个位置处z值最大的图项,参数 QTransform 表示变换矩阵可以取graphicsView.transform()。

    • 用items()方法可以获得某个位置的图项列表,例如items(QPoint,mode,order,QTransform),
      • 其中参数 mode 是 Qt ItemSelectionMode类型值,可以取:
        • QtContainsItemShape(完全包含)
        • Qt.IntersectsItemShape(完全包含和交叉)
        • Qt.ContainsItemBoundingRect(完全包含边界矩形)
        • Qt.IntersectsItemBoundingRect(完全包含矩形边界和交叉边界);
      • order 是指图项z值的顺序,可以取以下值,默认是Qt.DescendingOrder。
        • Qt.DescendingOrder(降序)
        • Qt.AscendingOrder(升序)
  • 用collidingItems(QGraphicsItem,mode=Qt.IntersectsItemShape)方法可以获取与指定图项产生碰撞的图项列表,参数 mode可以取:

    • QContainsItemShape
    • Qt.IntersectsItemShape
    • Qt.ContainsltemBoundingRect
    • Qt.IntersectsltemBoundingRect。
  • 用createItemGroup(Sequence[QGraphicsItem])方法可以将多个图项定义成组并返回QGraphicsItemGroup 对象

    • 可以把组内的图项当成一个图项进行操作内的图项可以同时进行缩放平移和旋转操作。
  • 可以用QGraphicsItemGroup的ddToGroup(QGraphicsItem)方法添加图项

    • 用removeFromGroup(QGraphicsItem)方法移除图项。
    • 用setSceneRect(rect; Union[QRectF,QRect])或 setSceneRect(x: float,y: float,w:float,h:float)方法设置场景的范围,用sceneRect()方法获取场景范围
  • 用setItemIndexMethod(QGraphicsScene ItemIndexMethod)方法设置在场景中搜索图项位置的方法,其中QGraphicsScene.ItemIndexMethod 可取:

    • QGraphicsScene BspTreeIndex(BSP树方法,适合静态场景)
    • QGraphicsScene.Nolndex(适合动态场景)。
    • BSP(binary space partitioning)树是二维空间分制树方法,又称为二叉法。用setBspTreeDepth(int)方法设置 BSP树的搜索深度
  • 场景分为背景层图项层和前景层,

    • QGraphicsScene.BackgroundLayer

    • QGraphicsScene.ItemLayer

    • QGraphicsScene.ForegroundLayer

      分别用以上值表示,这三层可用QGraphicsScene.AllLayers 表示。

    • 用invalidate(rect: Union[QRectF,QRect],layers:QGraphicsScene.SceneLayers = QGraphicsScene.AllLayers)方法或invalidate(x; float,y: float, w; float, h: float, layers; QGraphicsScene.SceneL ayers =QGraphicsScene.AllLayers)方法将指定区域的指定层设置为失效后再重新绘制,以达到更新指定区域的目的,

      • 也可用视图控件的 invalidateScene(rect:Union[QRectF,QRect],QGraphicsScene.SceneLayer)方法达到相同的目的。
      • 也可以用update(rect: Union[QRectF, QRect])或 update(x: float,y: float, w; float,h;float)方法更新指定的区域。
  • Graphics/View 框架通过染函数 QGraphicsScene.render()和 QGraphicsView.render()支持单行打印。

    • 场景和视图的染函数的不同在于 QGraphicsScene.render()使用场景坐标,QGraphicsView.render()使用视图坐标。
    • 用addWidget(QWidget,Qt.WindowType)方法可以将一个控件或窗口嵌人到场景中,如QLineEdit、QPushButton;或是复杂的控件如 QTableWidget,甚至是主窗口该方法返回 QGraphicsProxyWidget,或先创建一个QGraphicsProxyWidget 实例手动嵌入控件。
    • 通过QGraphicsProxyWidget,Graphics/View 框架可以深度整合控件的特性,如光标、提示、鼠标、平板和键盘事件、子控件、动画、下拉框、Tab 顺序
    • 用setFont(QFont)setPalette(QPalette)或 setStype(QStyle)方法为视图控件设置字体、调色板和风格。
  • 用setActivePanel(item:QGraphicsItem)方法激活场景中的图项,参数若是None场景将停用任何当前活动的图项。

    • 如果场景当前处于非活动状态,则图项将保持不活动状态,直到场景变为活动状态为止。

    • 用setActiveWindow(widget;QGraphicsWidget)方法激活场景中的视图控件,参数如是None,场景将停用任何当前活动的视图控件。

场景QGraphicsScene 的信号

场景QGraphicsScene的信号如表所示

QGraphicsScene 的信号及参数类型 说明
changed(region: List[QRectF]) 场景中的内容发生改变时发送信号,参数包含场景 矩形的列表,这些矩形指示已更改的区域
focusltemChanged(newFocusltem: QGraphicsltem, oldFocusltem: QGraphicslten1,reason:Qt.FocusReason) 图项的焦点发生改变,或者焦点从一个图项转移到 另一个图项时发送信号
sceneRectChanged(rect:QRectF) 场景的范围发生改变时发送信号
selectionChanged() 场景中选中的图形发生改变时发送信号

图项QGraphicsltem

QGraphicsItem类是 QGraphicsScene 中所有图项的基类用于编写自定义图项,包括定义图项的几何形状、碰撞检测、绘图实现,以及通过其事件处理程序进行图项的交互,继承自QGraphicsItem 的类有:

  • QAbstractGraphicsShapelfem
  • QGraphicsEllipseltem
  • QGraphicsItemGroup
  • QGraphicsLineltem
  • QGraphicsPathItem
  • QGraphicsPixmapItem
  • QGraphicsPolygonItem
  • QGraphicsRectItem
  • QGraphicsSimpleTextItem。

图项支持鼠标拖放、滚轮右键菜单按下释放、移动、双击以及键盘等事件,进行分组和碰撞检测,还可以给图项设置数据

用QGraphicsItem类创建图项实例对象的方法如下,其中parent是QGraphicsItem的实例,在图项间形成父子关系。

1
2
3
from PySide6.QtWidgets import QGraphicsItem

QGraphicsItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
图项的常用方法如表所示
QGraphicsItem的方法及参数类型 说一明
paint(painter:QPainter,option: QStyleOptionGraphicsItem,widget: QWidget=None) 重写该函数,绘制图形
boundingRect() 重写该函数,返回边界矩形QRectF
itemChange(change: QGraphicsIten.GraphicsltemChange,value:Any) 重写该函数,以便在图项的状态发生改变时做出 响应
advance(phase) 重写该函数,用于简单动画,由场景的advance()调 用。phase=0时通知图项即将运动,phase=1时可 以运动
setCacheMode(mode: QGraphicsItem, CacheMode,cacheSize:QSize=Default(QSize)) 设置图项的级冲模式
childItems() 获取子项列表 List[QGraphicsItem]
childrenBoundingRect() 获取子项的边界矩形
clearFocus() 清除焦点
collides Withltem(other: QGraphicsltem, mode: Qt.ItemSelectionMode=Qt.IntersectsltemShape) 获取是否能与指定的图项发生碰撞
collides WithPath(path:QPainterPath,mode:Qt.ItemSelectionMode= Qt.IntersectsItemShape) 获取是否能与指定的路径发生碰撞
collidingItems(mode= Qt.IntersectsItemShape) 获取能发生碰撞的图项列表
contains(Union[QPointF,QPoint]) 获取图项是否包含某个点
grabKeyboard()、ungrabKeyboard() 接受、不接受键盘的所有事件
grabMouse()、ungrabMouse() 接受、不接受鼠标的所有事件
isActive() 获取图项是否活跃
isAncestorOf(QGraphicsItem) 获取图项是否是指定图项的父辈
isEnabled() 获取是否激活
isPanel() 获取是否面板
isSelected() 获取是否被选中
isUnderMouse() 获取是否处于光标下
parentItem() 获取父图项
resetTransform() 重置变换
scene() 获取图项所在的场景
sceneBoundingRect() 获取场景的范围
scenePos() 获取在场景中的位置 QPointF
sceneTransform() 获取变换矩阵 QTransform
setAcceptDrops(bool) 设置是否接受鼠标释放事件
setAcceptedMouseButtons(Qt.MouseButton) 设置可接受的鼠标按钮
setActive(bool) 设置是否活跃
setCursor(Union[QCursor,Qt.CursorShape]) 设置光标形状
unsetCursor() 重置光标形状
setData(key:int,value:Any) 给图项设置数据
data(key:int) 获取图项存储的数据
setEnabled(bool) 设置图项是否激活
setFlag(QGraphicsItem.GraphicsItemFlag, enabled=True) 设置图项的标识
setFocus(focusReason=Qt.OtherFocusReason) 设置焦点
setGroup(QGraphicsItemGroup) 将图项加入到组中
group() 获取图项所在的组
setOpacity(opacity: float) 设置不透明度
setPanelModality(QGraphicsItem.PanelModality) 设置面板的模式
setParentItem(QGraphicsltem) 设置父图项
setPos(Union[QPointF,QPoint]) setPos(x: float,y: float) 设置在父图项坐标系中的位置
setX(float)、setY(float) 设置在父图项中的x和y坐标
pos() 获取图项在父图项中的位置 QPointF
x()、y() 获取×坐标、获取y坐标
setRotation(angle:float) 设置沿z轴顺时针旋转角度(°)
setScale(scale:float) 设置缩放比例系数
moveBy(dx:float,dy: float) 设置移动量
setSelected(selected:bool) 设置是否选中
setToolTip(str) 设置提示信息
setTransform(QTransform,combine=False) 设置矩阵变换
setTransformOriginPoint(origin: Union[QPointF, QPoint]) 设置变换的中心点
setTransformOriginPoint(ax:float,ay:float) 设置变换的中心点
set Transformations(Sequence[QGraphicsTransform]) 设置变换矩阵
transform() 获取变换矩阵 QTransform
transformOriginPoint() 获取变换原点QPointF
setVisible(bool) 设置图项是否可见
show()、hide() 显示图项、隐藏图项,子项也隐藏
isVisible() 获取是否可见
setZValue(float) 设置z值
zValue() 获取z值
shape() 重写该函数,返回图形的绘图路径 QPainterPath,用于碰撞检测等
stackBefore(QGraphicsItem) 在指定的图项前插入
isWidget() 获取图项是否是图形控件 QGraphicsWidget
isWindow() 获取图形控件的窗口类型是否是Qt.Window
window() 获取图项所在的图形控件 QGraphicsWidget
topLevelWidget() 获取顶层图形控件 QGraphicsWideet
topLevelItem() 获取顶层图项(没有父图项)
update(rect: Union[QRectF, QRect]= Default(QRectF)) 更新指定的区域
update(x: float, y: float, width: float,height: float) 更新指定的区域
在图项场景间的映射方法如表所示
从其他图顶映射
图项坐标的映射方法及参数类型 返回值类型
mapFromltem(item:QGraphicsltem,path:QPainterPath) QPainterPath
mapFromItem(item; QGraphicsltem, point:Union[QPointF,QPoint]) QPointF
mapFromItem(item: QGraphicsItem,polygon:Union[QPolygonF, Sequence[QPointF],QPolygon,QRectF]) QPolygonF
mapFromItem(item; QGraphiesltem.rect: Union[QRectF.QRect]) QPolygonF
napFromItem(item;QGraphicsltem,xi float,y: float) QPointF
mapFromItem(item, QGraphicsltem,xi float,y: float,w: float,h: float) QPolygonF
mapRectFromItem(item;QGraphicsltem,rect, Union[QRectF,QRect]) QRectF
mapRectFromItem(item: QGraphicsltem,x; float,y; float,w: float,h: float) / QRectF
从父图项映射
图项坐标的映射方法及参数类型 返回值类型
mapFromParent(path: QPainterPath) QPainterPath
mapFromParent(point:Union[QPointF,QPoint]) QPointF
mapFromParent(polygon:Union[QPolygonF, Sequence[QPointF], QPolygon,QRectF]) QPoIygonF
mapFromParent(rect:Union[QRectF,QRect]) QPolygonF
mapFromParent(x:float,y:float) QPointF
mapFromParent(x:float,y: float,w: float,h: float) QPolygonF
mapRectFromParent(rect: Union[QRectF,QRect]) QRectF
mapRectFromParent(x:float,y:float,w: float,h: float) QRectF
从场景映射
图项坐标的映射方法及参数类型 返回值类型
mapFromScene(path: QPainterPath) QPainterPath
mapFromScene(point: Union[QPointF,QRoint]) QPointF
mapFromScene(polygon: Union[QPolygonF, Sequence[QPointF], QPolygon,QRectF]) QPolygonF
mapFromScene(rect:Union[QRectF,QRect]) QPolygonF
mapFromScene(x: float,y:float) QPointF
mapFromScene(x: float,y:float,w: float,h: float) QPolygonF
mapRectFromScene(rect;Union[QRectF,QRect]) QRectF
mapRectFromScene(x: float,y: float,w: float,h:float) QRectF
映射到父图项
图项坐标的映射方法及参数类型 返回值类型
mapToParent(path:QPainterPath) QPainterPath .
mapToParent(point:Union[QPointF,QPoint]) QPointF
mapToParent(polygon: Union[QPolygonF,Sequence[QPointF], QPolygon,QRectF]) QPolygonF
mapToParent(rect:Union[QRectF,QRect]) QPolygonF
mapToParent(x:float,y:float) QPointF
mapToParent(x: float,y: float,w: float,h;float) QPolygonF
mapRectToParent(rect:Union[QRectF,QRect]) QRectF
mapRectToParent(x: float,y;float,w; float,h:float) QRectF
映射到场景
图项坐标的映射方法及参数类型 返回值类型
mapToScene(x: float,y: float) QPointF
mapToScene(x:loat.y: float.w: float,h: loat) QPolygonP
mapRect ToScene(rect: Union[QReetF,QRect]) QRectF
mapRect ToScene(x:float,y: float.w: float.h: float) QRectF
mapToScene(path: QPainterPath) QPainterPath
mapToScene(point:Union[QPointF,QPoint]) QPointF
mapToScene(polygon: Union[QPolygonF, Sequence[QPointF], QPolygon,QRectF]) QPolygonF
mapToScene(rect:Union[QRectF,QRect]) QPolygonF
主要方法介绍如下
  • 用户需要从QGraphicsItem 类继承并创建自己的子图项类,需要在子类中重写paint(painter: QPainter, option: QStyle(ptionGraphicsItem, widget:QWidget 一None)函数和 boundingRect()函数

    • boundingRect()函数的返回值是图项的范围QRectF。
    • paint()函数会被视图控件调用需要在paint()函数中用QPainter绘制图形图形是在图项的局部坐标系中绘制的。
      • QPainter 的钢笔宽度初始值是1,
      • 画刷的颜色是QPalette.window,
      • 线条的颜色是 QPalette text,
      • QStyleOptionGraphicsItem 是绘图选项,
      • QWidget 是指将绘图绘制到哪个控件上如果为 None,则绘制到缓存上
    • boundingRect()函数需要返回QRectF,用于确定图项的边界。paint()中绘制的图形不能超过边界矩形
  • 用setFlag(QGraphicsItem.GraphicsItemFlag,enabled=True)方法设置图项的标志,其中参数QGraphicsItemGraphicsItemFlag 可取的值如表所示

    QGraphicsltem.GraphicsltemFlag的取值 说 明
    QGraphicsItem.ItemIsMovable 可移动
    QGraphicsItenm.ItemlsSelectable 可选择
    QGraphicsItem.ItemIsFocusable 可获得键盘输入焦点、鼠标按下和释放事件
    QGraphicsItem.ItemClipsToShape 剪切自己的图形,在图项之外不能接收鼠标拖放和 悬停事件
    QGraphicsItem.ItemClipsChildrenToShape 剪切子类的图形,子类不能在该图项之外绘制
    QGraphicsItem.ItemIgnoresTransformations 忽略来自父图项或视图控件的坐标变换,例如文字 可以保持水平或竖直,文字比例不缩放
    QGraphicsItem.ItemIgnoresParentOpacity 使用自己的透明设置,不使用父图项的透明设置
    QGraphicsltem ItermDoesntPropagateOpacityIoChildren 图项的透明设置不影响其子图项的透明值
    QGraphicsItem.ItemStacksBehindParent 放置于父图项的后面而不是前面
    QGraphicsltem,ItemHasNoContents 图项中不绘制任何图形,调用paint()方法也不起任 何作用
    QGraphicsItem.ItemSendsGeometryChanges 该标志使itemChange()函数可以处理图项几何形 状的改变,例如ItemPositionChange、 ItemScaleChange、ItemPositionHasChanged、Item TransformChange、ItemTransformHasChanged、 ItemRotationChange、 ItemRotationHasChanged、 ItemScaleHasChanged、Item TransformOriginPointChange、ItemTransformOriginPointHasChanged
    QGraphicsItem.ItemAcceptslnputMethod 图项支持亚洲语言
    QGraphicsItem.ItemNegativeZStacksBehindParent 如果图项的z值是负值,则自动放置于父图项的后 面,可以用setZValue()方法切换图项与父图项的 位置
    QGraphicsItem.ItemIsPanel 图项是面板,面板可被激活和获得焦点,在同一时间 只有一个面板能被激活,如果没有面板,则激活所有 非面板图项
    QGraphicsItem.ItemSendsScenePositionChanges 该标志是itemChange()函数可以处理图项在视图控 件中的位置变化事件ItemScenePositionHasChanged
    QGraphicsItem.ItemContainsChildrenInShape 该标志说明图项的所有子图项在图项的形状范围内 绘制,这有利于图形绘制和碰撞检测。与 ItemContainsChildrenInShape标志相比,该标志不是 强制性的
  • 重写itemChange(change:QGraphicsItem,GraphicsItemChange,value: Any)函数可以在图项的状态发生改变时及时做出反应,用于代替图项的信号,

    • 其中 value 值根据状态change确定,状态参数cange的取值是QGraphicsItem.GraphicsItemChange的枚举值,可取值如表所示。

    • 需要注意的是要使itemChange()函数能处理几何位置改变的通知,需要首先通过 setFlag()方法给图项设置QGraphicsItem,ItemSendsGeometryChanges标志,另外也不能在itemChange()函数中直接改变几何位置,否则会陷入死循环。

      QGraphIcsItem.GraphIcsltemChange的取值 说明
      QGraphIcsItem.ItemEnabledChange 3 图项的激活状态(setEnable())即将改变时发送通 知。ItemChange()函数中的参数 value是新状态, value=True 时表明图项处于激活状态,value= False时表明图项处于失效状态。原激活状态可 用IsEnabled()方法获得
      QGraphIcsItem.ItemEnabledHasChanged 13 图项的激活状态已经改变时发送通知, ItemChange()函数中的参数 value 是新状态
      QGraphIcsItem.ItemPosItIonChange 0 图项的位置(setPos()、moveBy())即将改变时发 送通知,参数 value是相对于父图项改变后的位置 QPoIntF,原位置可以用pos()获得
      QGraphIcsItem.ItemPosItIonHasChanged 9 图项的位置已经改变时发送通知,参数value是相 对于父图项改变后的位置QPoIntF,与pos()方法 获取的位置相同
      QGraphIcsltem.ItemTransformChange 8 图项的变换矩阵(setTransform())即将改变时发 送通知,参数 value 是变换后的矩阵 QTransform, 原变换矩阵可以用transform()方法获得
      QGraphIcsltem.ItemTransformHasChanged 10 图项的变换矩阵已经改变时发送通知,参数value 是变换后的矩阵QTransform,与transform()方法 获得的矩阵相同
      QGraphIcsltem.ItemRotatIonChange 28 图项即将产生旋转(setRotatIon())时发送通知,参 数 valIe是新的旋转角度,原旋转角可用rotatIon() 方法获得
      QGraphIcsltem.ltemRotatIonHasChanged 29 图项已经严生旋转时发送通知,参数 value 是新的 旋转角度,与rotatIon()方法获得的旋转角相同
      QGraphIcslterm.ItemScaleChange . 30 图项即将进行缩放(setScale())时发送通知,参数 value是新的缩放系数,原缩放系数可用scale()方 法获得
      QGraphIcsItem.ItemScaleHasChanged 31 图项已经进行了缩放时发送通知,参数 value 是新 的缩放系数
      QGraphIcsItem.ItemTransformrIgInPoIntChange 32 图项变换原点(setTransformOrIgInPoInt())即将 改变时发送通知,参数 value 是新的点 QPoIntF。 原变换原点可用transformOrIgInPoInt()方法获得
      QGraphIcsItem.ItemTransformOrIgInPoIntHnsChanged 33 图项变换原点已经改变时发送通知,参数 value是 新的点 QPoIntF,原变换原点可用transformOrIgInPoInt()方法获得
      QGraphIcsItem.ItemSelectedChange 4 图项选中状态即将改变(setSelected())时发送通 知,参数value是选中后的状态(True或False),原 选中状态可用IsSelected()方法获得
      QGraphIcsltem.ItemSelectedHasChanged 14 图项的选中状态已经改变时发送通知,参数value 是选中后的状态
      QGraphIesItem.ItemVIsIbleChange 2 图项的可见性(setVIsIble())即将改变时发送通 知,参数value是新状态,原可见性状态可用IsVIsIble()方法获得
      QGraphIcsltem.ItenVIsIbleHasChanged 12 图项的可见性已经改变时发送通知,参数value是 新状态
      QGraphIcsltem.ItemParentChange 5 图项的父图项(setParentItem())即将改变时发送 通知,参数value是新的父图项QGraphIcsIten,原 父图项可用parentItem()方法获得
      QGraphIcsltem.ItemParentHasChanged 15 图项的父图项已经改变时发送通知,参数value是 新的父图项
      QGraphIcsltem.ItemChIldAddedChange 6 图项中即将添加子图项时发送通知,参数value是 新的子图项,予图项有可能还没完全构建
      QGraphIesItem.ItemChIldRemovedChange 7 图项中已经添加子图项时发送通知,鑫数value是 新的子图项
      QCIraphIcsltem.ItemSceneChange 11 图项即将加入到场景(addItem())中或即将从场 景中移除(removeltem())时发送通知、鑫数value 是新场景城None(移除时)原场景可用scene()方 法获得
      QGraphIcsItem.ItemSceneHasChanged 16 图项已经加人到场景中或即将从场景中移除时发 送通知,参数 value 是新场景或 None(移除时)
      QGraphIcsItem.ItemCursorChange 17 图项的光标形状(setCursor())即将改变时发送通 知,参数 value 是新光标QCursor,原光标可用cursor()方法获得
      QGraphIcsItem.ItemCursorHasChanged 18 图项的光标形状已经改变时发送通知,参数 value 是新光标 Qcursor
      QGraphIcsItem.Item ToolTIpChange 19 图项的提示信息(setToolTIp())即将改变时发送 通知,参数value是新提示信息,原提示信息可用toolTIp()方法获得:
      QGraphIcsItem.ItemToolTIpHasChanged 20 图项的提示信息已经改变时发送通知,参数 value 是新提示信息
      QGraphIcsItem.ItemFlagsChange 21 . 图项的标识(setFlags())即将改变时发送通知,参 数 value是新标识信息值
      QGraphIcsItem.ItemFlagsHaveChanged 22 图项的标识即将发生改变时发送通知,参数 value 是新标识信息值
      QGraphIcsItem.ItemZValueChange 23 图项的z值(setZValue())即将改变时发送通知, 参数 value 是新的z值,原z值可用zValue()方法 获得
      QGraphIcsItem.ItemZValueHasChanged 24 图项的z值即将改变时发送通知,参数 value是新 的z值
      QGraphIcsItem.ItemOpacItyChange 25 图项的不透明度(setOpacIty())即将改变时发送 通知,参数value是新的不透明度,原不透明度可 用opacIty()方法获得
      QGraphIcsItem.ItemOpacItyHasChanged 26 图项的不透明度已经改变时发送通知,参数 value 是新的不透明度
      QGraphIcsItem.ItemScenePosItIonHasChanged 27 图项所在的场景的位置已经发生改变时发送通 知,参数 value 是新的场景位置,与 scenePos()方 法获得的位置相同
  • 用setCacheMode(mode: QGraphicsItem,CacheMode,cacheSize; QSize= Default(QSize))方法设置图项的缓冲模式,可以加快染速度。参数 mode 可取:

    • QGraphicsItem.NoCache时(默认值)没有缓冲每次都调用paint()方法重新绘制;
    • QGraphicsItem.ItemCoordinateCache ,为图形项的逻辑(本地)坐标启用缓存,第一次绘制该图形项时,它将自身呈现到高速缓存中,然后对于以后的每次显示都重新使用该高速缓存;
    • QGraphicsItem.DeviceCoordinateCache ,对绘图设备的坐标启用缓存,此模式适用于可以移动但不能旋转缩放或剪切的图项
  • 场景中有多个图项时,根据图项的z值确定哪个图项先绘制,值越大会越先绘制先绘制的图项会放到后绘制的图项的后面。

    • 用setZValue(float)方法设置图项的z值,用zValue()方法获取z值。
    • 用场景的addItem()方法添加图项时图项的初始值都是0.0,这时图项依照添加顺序来显示。
    • 如果一个图项有多个子项,则会先显示父图项,再显示子图项。可以用stackBefore(QGraphicsItem)方法将图项放到指定图项的前面
  • 用setPos(x,y)、setX(x)和 setY(y)方法设置图项在父图项中的位置。

    • pos()方法返回图项在父图项中的坐标位置,如果图项的父图项是场景,则返回其在场景中的坐标位置。
    • 除 pos()外的其他函数,返回的坐标值都是在图项自己的局部坐标系中的值。
  • 用setVisible(bool)方法可以显示或隐藏图项

    • 也可以用show()或 hide()方法显示或隐藏图项,
    • 如果图项有子图项,隐藏图项后,其子图项也隐藏。
  • 用setEnable(bool)方法可以设置图项是否激活,激活的图项可以接受键盘和鼠标事件,如果图项失效,其子项也会失效。

  • 用setData(key:int,value: Any)方法可以给图项设置一个任意类型的数据,

    • 用data(key:int)方法获取图项的数据
  • 碰撞检测需要重写 shape()函数来返回图项的精准轮廓,

    • 可以使用默认的collidesWithItem(QGraphicsItem,mode=Qt.IntersectsItemShape)值定义外形,
    • 如果图项的轮廓很复杂碰撞检测会消耗较长时间。
    • 也可重写 collidesWithItem()函数,提供一个新的图项和轮廓碰撞方法。
  • 用setPanelModality(QGraphicsItemPanelModality)方法设置图项的面板模式,

    • 图项是面板时会阻止对其他面板的输人,但不阻止对子图项的输人,参数QGraphicsItem,PanelModality 可以取:
      • QGraphicsItem,NonModal(默认值,不阻止对其他面板的输人)
      • QGraphicsItemPanelModal(阻止对父辈面板的输人)
      • QGraphicsItem.SceneModal(阻止对场景中所有面板的输入)
  • 用mapFromItem()方法或mapRectFromItem()方法可以从其他图项映射坐标

    • 用mapToItem()方法或 mapRectToItem()方法可以把坐标映射到其他图项坐标系中,
    • 用mapFromParent()方法或mapRectFromParent()方法可以映射父图项的坐标,
    • 用mapToParent()方法或 mapRectToParent()方法可以把图项坐标映射到父图项坐标系中,
    • 用mapFromScene()方法或 mapRectFromScene()方法可以从场景中映射坐标,
    • 用mapToScene()方法或 mapRectToScene()方法可以把坐标映射到场景坐标系中。
  • 图项的事件有:

    • contextMenuEvent()
    • focusInEvent()
    • focusOutEvent()
    • hoverEnterEvent()
    • hoverMoveEvent()
    • hoverLeaveEvent()
    • inputMethodEvent()
    • keyPressEvent()
    • keyReleaseEvent()
    • mousePressEvent()
    • mouseMoveEvent()
    • mouseReleaseEvent()
    • mouseDoubleClickEvent()
    • dragEnterEvent()
    • dragLeaveEvent()
    • dragMoyeEvent()
    • dropEvent()
    • wheelEvent()
    • sceneEvent(QEvent)
    • 用installSceneEventFilter(QGraphicsItem)方法给事件添加过滤器
    • 用sceneEventFilter(QGraphicsItem,QEvent)方法处理事件,并返回 bool型数据;
    • 用removeSceneEventFilter(QGraphicsItem)方法移除事件过滤器。
  • 可以通过 QGraphicsItemsetAcceptDrops()方法设置图项是否支持拖拽功能,还需要重写QGraphicsItem 的以下函数:

    • dragEnterEvent()
    • dragMoveEvent()
    • dropEvent()
    • dragLeaveEvent()
  • 创建继承自QGraphicsItem 的图项,图项可以设置自已的定时器,在 timerEvent()事件中控制图项的运动。通过调用QGraphicsScene,advance()函数来推进场景,再调用QGraphicsItemadvance()函数进行动画播放。

标准图项

除了可以自定义图项外,还可以往场景中添加标准图项,标准图项有 :

  • QGraphicsLineItem
  • QGraphicsRectItem
  • QGraphicsPolygonltem
  • QGraphicsEllipseltem
  • QGraphicsPathItem
  • QGraphicsPixmapItem
  • QGraphicsSimpleTextItem
  • QGraphicsTextItem
  • 分别用场景的
    • addLine()
    • addRect()
    • addPolygon()
    • addEllipse()
    • addPath()
    • addPixmap()
    • addSimpleText()
    • addText()

直接往场景中添加这些标准图项并返回指向这些场景的变量;也可以先创建这些标准场景的实例对象,然后用场景的addItem()方法将标准图项添加到场景中。这些标准图项的继承关系如图所示,它们直接或间接继承自QGraphicsItem,因此也会继承QGraphicsItem 的方法和属性

image-20230308230809303

直线图项 QGraphicsLineItem

用QGraphicsLineltem 创建直线对象的方法如下所示,其中 parent 是继承自QGraphicsItem的实例对象

1
2
3
4
5
from PySide6.QtWidgets import QGraphicsLineItem

QGraphicsLineItem(line: Union[PySide6.QtCore.QLineF, PySide6.QtCore.QLine], parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsLineItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsLineItem(x1: float, y1: float, x2: float, y2: float, parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None

QGraphicsLineItem 的主要方法是设置直线和钢笔

  • 用setLine(line;Union[QLineFQLine])和 setLine(xl:float;yl; float;x2;float,y2: float)方法设置直线,
  • 用setPen(pen:Union[QPen,Qt.PenStyle,QColor])方法设置钢笔,用line()方法获取线条 QLineF,
  • 用pen()方法获取钢笔 QPen。
矩形图项 QGraphicsRectItem

用QGrphicsRectItem 创建矩形对象的方法如下所示,其中 parent 是继承自QGraphicsItem 的实例对象。

1
2
3
4
5
from PySide6.QtWidgets import QGraphicsLineItem

QGraphicsLineItem(line: Union[PySide6.QtCore.QLineF, PySide6.QtCore.QLine], parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsLineItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsLineItem(x1: float, y1: float, x2: float, y2: float, parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None

QGraphicsRectItem 的主要方法有:

  • setRect(rect; Union[QRectF,QRect])
  • setRect(x:float,y: float, w: float, h: float)
  • rect()
  • setPen(pen: Union[QPen, Qt.PenStyle.QColor])
  • pen()
  • setBrush(brush; Union[QBrush, Qt.BrushStyle, QColor,Qt.GlobalColor;QGradient,QImage,QPixmap])
  • brush()
多边形图项OGraphicsPolygonItem

用QGraphicsPolygonItem 创建多边形对象的方法如下所示

1
2
3
4
from PySide6.QtWidgets import QGraphicsPolygonItem

QGraphicsPolygonItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsPolygonItem(polygon: Union[PySide6.QtGui.QPolygonF, Sequence[PySide6.QtCore.QPointF], PySide6.QtGui.QPolygon, PySide6.QtCore.QRectF], parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None

QGraphicsPolygonItem 的主要方法有:

  • setPolygon(polygon: Union[QPolygonF.Sequence[QPointF],QPolygon, QRectF])
  • polygon()
  • setFillRule(Qt.FillRule)
  • fllRule()
  • setPen(pen: Union[QPen, Qt.PenStyle, Color])
  • pen()
  • setBrush(brush: Union[QBrush,Qt.BrushStyle, QColor, Qt.GlobalColor, QGradient,QImage,QPixmap])
  • brush()
椭圆图项OGraphicsEllipseItem

QGraphicsEllipseItem 可以创建椭圆圆和扇形对象创建扇形时需要指定起始角和跨度角,起始角和跨度角需乘以16表示角度。

用QGraphicsEllipseItem类创建椭圆的方法如下所示。

1
2
3
4
5
from PySide6.QtWidgets import QGraphicsEllipseItem

QGraphicsEllipseItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsEllipseItem(rect: Union[PySide6.QtCore.QRectF, PySide6.QtCore.QRect], parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsEllipseItem(x: float, y: float, w: float, h: float, parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None

QGraphicsEllipseltem 的主要方法有:

  • setRect(rect: Union[QRectF,QRect])
  • setRect(x: float,y: float, w; float, h; float)
  • rect()
  • setSpanAngle(angle: int)
  • spanAngle()
  • setStartAngle(angle; int)
  • startAngle()
  • setPen(pen; Union[QPen, Qt.PenStyle,QColor])
  • pen()
  • setBrush(brush; Union[QBrush, Qt.BrushStyle, QColor, Qt.GlobalColor;QGradient,QImage,QPixmap])
  • brush()
路径图项QGraphicsPathItem

QGraphicsPathItem用QPainterPath 绘图路径绘制图项。

用QGraphicsPathItem 创建图项的方法如下所示

1
2
3
4
from PySide6.QtWidgets import QGraphicsPathItem

QGraphicsPathItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsPathItem(path: PySide6.QtGui.QPainterPath, parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None

QGraphicsPathItem 的主要方法有:

  • setPath(path:QPainterPath)
  • path()
  • setPen(pen;Union[QPen, Qt.PenStyle, QColor])
  • pen()
  • setBrush(brush; Union[QBrush, Qt.BrushStyle,QColor,Qt.GlobalColor,QGradient,QImage,QPixmap])
  • brush()
图像图项OGraphicsPixmapItem

QGraphicsPixmapltem 用于绘制图像。用QGraphicsPixmapItem 创建图项的方法如下所示。

1
2
3
4
from PySide6.QtWidgets import QGraphicsPixmapItem

QGraphicsPixmapItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsPixmapItem(pixmap: Union[PySide6.QtGui.QPixmap, PySide6.QtGui.QImage, str], parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None

QGraphicsPixmapItem 的主要方法有:

  • setOffset(offset: Union[QPointF,QPoint,QPainterPath, Element])
  • setOffset(x: float, y: float)
  • offset()
  • setPixmap(pixmap:Union[QPixmap;QImage, str])
  • pixmap()
  • setShapeMode(QGraphicsPixmapItem.ShapeMode)
  • setTransformationMode(Qt.TransformationMode),图像绘制位置在(0,0)点。
  • 用setOffset()方法可以设置偏位置;
  • 用setTransformationMode(Qt.TransformationMode)方法设置图像是否光滑变换其中参数 Qt.TransformationMode可以取:
    • Qt.FastTransformation(快速变换)
    • Qt.SmoothTransformation(光滑变换);
  • 用setShapeMode(QGraphicsPixmapItem.ShapeMode)方法设置计算形状的方法,其中参数QGraphicsPixmapItem.ShapeMode 可取:
    • QGraphicsPixmapItem,MaskShape(通过调用QPixmap,mask()方法计算形状)
    • QGraphicsPixmapItemBoundingRectShape(通过轮廓确定形状)
    • QGraphicsPixmapItem.HeuristicMaskShape(通过调用QPixmap.createHeuristicMask()方法确定形状)
纯文本图项QGraphicsSimpleTextItem

QGraphicsSimpleTextItem用于绘制纯文本可以设置文本的轮廓和填充颜色。用QGraphicsSimpleTextItem创建图项的方法如下

1
2
3
4
from PySide6.QtWidgets import QGraphicsSimpleTextItem

QGraphicsSimpleTextItem(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None
QGraphicsSimpleTextItem(text: str, parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None) -> None

QGraphicsSimpleTextItem 的主要方法有:

  • setText(str),text()
  • setFont(font: Union[QFont,str,Sequence[str]])/ font(),
  • 用setPen(pen)方法绘制文本的轮廓
  • 用setBrush(brush)方法设置文本的填充色
文本图项 QGraphicsTextItem

用QGraphicsTextltem 可以绘制带格式和可编辑的文本,还可以有超链接。用QGraphicsTextItem 创建图项实例的方法如下所示。
QGraphicsTextItem(paren; QGraphicsItem = None)QGraphicsTextItem(text;str, parent;QGraphicsItem None)

QGraphicsTextItem 的常用方法有 :

  • adjastSize()(调整到合适的尺寸)
  • openExternalLinks()
  • setDefaultTextColor(Union[QColor, Qt.GlobalColor,QGradient])
  • setDocument(QTextDocument)
  • setFont(QFont)
  • setHtml(str)
  • toHtml()
  • setOpenExternalLinks(bool)
  • setPlainText(str)
  • toPlainText()
  • setTabChangesFocus(bool)
  • setTextCursor(QTextCursor)
  • setTextInteractionFlags(Qt.TextInteractionFlag)
  • setTextWidth(float)
  • 其中 setTextInteractionFlags(Qt.TextInteractionFlag)方法设置文本是否可以交互操作,参数 Qt.TextInteractionFlag 可以取:
    • Qt.NoTextInteraction
    • Qt.TextSelectableByMouse
    • Qt.TextSelectableByKeyboard
    • Qt.LinksAccessibleByMouse
    • Qt.LinksAccessibleByKeyboard
    • Qt.TextEditable
    • Qt.TextEditorInteraction
      • 指 Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard | Qt.TextEditable)
      • Qt.TextBrowserInteraction(指 Qt.TextSelectableByMouse | Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard)。

QGraphicsTextItem 的信号有 linkActivated(link)和 linkHovered(link),分别在单击超链接和光标在超链接上悬停时发送信号。与其他标准图项不同的是,QGraphicsTextItem 还具有鼠标和键盘事件。

代理控件和图形控件

场景中除了可以直接添加图项外,也可以添加常用的控件,甚至是对话框.场景中的控仙也可以进行布局。

代理控件QGraphicsProxyWidget

前面介绍过,通过场景的 addWidget(QWidget,wFlags:Qt.WindowFlags)方法可以把一个控件或窗口加人到场景中,并返回代理类控件 QGraphicsProxyWidget。

代理类控件可以将QWidget类控件加入到场景中,可以先创建QGraphicsProxyWidget 控件,然后用场景的addItem(QGraphicsProxyWidget)方法把代理控件加人到场景中。

代理控件QGraphicsProxyWidget 继承自图形控件 QGraphicsWidget,它们之间的继承关系如图所示。

image-20230308235906098

用QGraphicsProxyWidget 类创建代理实例对象的方法如下,其中parent 是QGraphicsItem的实例

1
2
3
from PySide6.QtWidgets import QGraphicsProxyWidget

QGraphicsProxyWidget(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None, wFlags: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

QGraphicsProxyWidget 中添加控件的方法是 setWidget(QWidget),QWidget 不能有WA_PaintOnScreen 属性,也不能是包含其他程序的控件,例如QOpenGLWidget 和QAxWidget控件。

用widget()方法可以获取代理控件中的控件。代理控件和其内部包合的控件在状态方面保持同步,例如可见性、激活状态、字体、调色板、光标形状、窗口标题、几何尺寸、布局方向等

下面是一个代理控件的实例,程序运行界面如图所示。单击”选择图片文件”按钮弹出打开文件对话框,选择图片文件后显示图片,图片所在的窗口用代理控件定义成图项程序中对图片所在的图项进行了错切变换。

image-20230309001345787

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/9 0:00
# File_name: 02-代理控件QGraphicsProxyWidget实例.py.py


import sys, os
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QGraphicsProxyWidget, QGraphicsScene, QGraphicsView, QFrame, QPushButton, QFileDialog
from PySide6.QtGui import QPainter, QTransform, QPixmap
from PySide6.QtCore import Qt.QRect


class myFrame(QFrame): # 创建QFrame的子类
def __init__(self, parent=None):
super().__init__(parent)

self.fileName = ""

def paintEvent(self, event): # 重写painterEvent,完成绘图
if os.path.exists(self.fileName):
pix = QPixmap(self.fileName)
painter = QPainter(self)
rect = QRect(0, 0, self.width(), self.height())
painter.drawPixmap(rect, pix)

super().paintEvent(event)


class myPixmapWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(600, 400)

self.frame = myFrame() # 自定义QFrame的实例
self.button = QPushButton("选择图片文件") # 按钮实例
self.button.clicked.connect(self.button_clicked) # 按钮信号与槽函数的连接
v = QVBoxLayout(self) # 布局
v.addWidget(self.frame)
v.addWidget(self.button)

# 按钮的槽函数
def button_clicked(self):
fileName, filter = QFileDialog.getOpenFileName(self, caption="打开图片", dir="../../Resources", filter="图片(*.png *.bmp *.jpg *.jpeg)")
self.frame.fileName = fileName
self.frame.update()


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

pix = myPixmapWidget() # 绘图窗口
view = QGraphicsView() # 视图控件
scene = QGraphicsScene() # 场景
view.setScene(scene) # 在视图中设置场景
proxy = QGraphicsProxyWidget(None, Qt.Window) # 创建代理控件
proxy.setWidget(pix) # 代理控件设置控件
proxy.setTransform(QTransform().shear(1, -0.5)) # 错切变换
scene.addItem(proxy) # 在场景中添加图项
v = QVBoxLayout(self) # 布局
v.addWidget(view)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

图形控件QGraphicsWidget

图形控件 QGraphicsWidget 的继承关系如图所示,

image-20230309231433109

它继承自QGraphicsObject 和QGraphicsLayoutItem,间接继承自 QObject和 QGraphicsItem,因此它可以直接添加到场景中。

QGraphicsWidget 是图形控件的基类,继承QGraphicsWidget 的类有

  • QGraphicsProxyWidget
  • QtCharts.QChart
  • QtCharts.QLegend
  • QtCharts.QPolarChart

QWidget 继承自 QObject 和QPaintDevice。QGraphicsWidget和QWidget 有很多相同点但也有些不同点。

在 QGraphicsWidget 中可以放置其他代理控件和布局,因此QGraphicsWidget 可以作为场景中的容器使用。用QGraphicsWidget类创建图形控件的方法如下,其中 parent是QGraphicsItem 的实例。

1
2
3
4
from PySide6.QtWidgets import QGraphicsWidget

QGraphicsWidget(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None,
wFlags: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

图形控件QGraphicsWidget 的常用方法如表所示,其中:

  • 用setAttribute(attribute:Qt.WidgetAttribute,on: bool=True)方法设置窗口的属性,参数 attribute可以取:
    • Qt.WA_SetLayoutDirection
    • Qt.WA_RightToLeft、
    • Qt.WA_SetStyle、
    • Qt.WAResized
    • Qt.WA_SetPalette
    • Qt.WA_SetFont
    • Qt.WAWindowPropagation。
  • 图形控件QGraphicsWidget 中通常需要用设置布局方法 setLayout(layout;QGraphicsLayout),在布局中添加图项或代理控件。
QGraphicsWidget 的方法及参数类型 说 明
setAttribute(attribute: Qt.WidgetAttribute,on: bool= True) 设置属性
testAttribute(attribute: Qt.WidgetAttribute) 测试是否设置了某种属性
itemChange(change: QGraphicsltem.GraphicsItemChange, value: Any) 重写该函数,作为信号使用。关于该函数的使 用详见6.2.5节的内容
paint(painter: QPainter,option: QStyleOptionGraphicsItem, widget:QWidget=None) 重写该函数,绘制图形
boundingRect() 重写该函数,返回边界矩形QRectF
shape() 重写该函数,返回路径QPainterPath
setLayout(layout:QGraphicsLayout) 设置布局
layout() 获取布局
setLayoutDirection(direction: Qt.LayoutDirection) 设置布局方向
setAutoFillBackground(enabled:bool) 设置是否自动填充背景
setContentsMargins(margins:Union[QMarginsF, QMargins]) 设置窗口内的控件到边框的最小距离
setContentsMargins(left: float, top: float, right: float, bottom: float) 设置窗口内的控件到边框的最小距离
sctFocusPolicy(policy:Qt.FocusPolicy) 设置获取焦点的策略
sctFont(font: Union[QFont,str,Sequence[str]]) 设置字体
serGeometry(rect:Union[QRectF,QRect]) 设置工作区的位置和尺寸
setGeometry(x: float,y: float,w: float,h: float) 设置工作区的位置和尺寸
setPalette(palette:Union[QPalette, Qt.GlobalColor, QColor]) 设置调色板
setStyle(style: QStyle) 设置风格
[static]setTabOrder(first: QGraphicsWidget, second: QGraphicsWidget) .设置按Tab键获取焦点的顺序
setWindowFlags(wFlags: Qt.WindowFlags) 设置窗口标识
setWindowFrameMargins s(Union[QMarginsF, QMargins]) 设置边框距 比图,超强实空。
setWindowFrameMargins(float, float, float, float) 设置边框距 比图,超强实空。
setWindowTitle(title:str) 设置窗口标题
rect() 获取图形控件的窗口范围 QRectF
resize(QSizeF) 调整窗口尺寸·
resize(float,float) 调整窗口尺寸·
size() 获取尺寸 QSizeF
focusWidget() 获取焦点控件 QGraphicsWidget
isActiveWindow() 获取是否是活跃控件
updateGeometry() 刷新图形控件
addAction(QAction)、 addActions(-Sequence[QAction]) 图形控件中添加动作
insertAction(before:QAction,action:QAction) 图形控件中插入动作,图形控件的动作可以作 为右键快捷菜单使用
insertActions(before: QAction, actions: Sequence[QAction]) 图形控件中插入动作,图形控件的动作可以作 为右键快捷菜单使用
actions() 获取动作列表List[QAction]
removeAction(action:QAction) 移除动作
[slot]close() 关闭窗口,成功则返回True

QGraphicsWidget 的信号有

  • geometryChanged()和 layoutChanged(),当几何尺寸和布局发生改变时发送信号
  • 另外QGraphicsWidget 从QGraphicsObject 继承的信号有
    • opacityChanged()
    • parentChanged()
    • rotationChanged()
    • scaleChanged()
    • visibleChanged()
    • xChanged()
    • yChanged()
    • zChanged()

图形控件的布局

图形控件可以添加布局,图形控件的布局有 3种分别为QGrphicsLinearLayout、QGraphicsGridLayout 和 QGraphicsAnchorLayout;它们都继承自QGraphicsLayoutItem。

线性布局OGraphicsLinearLayout

线性布局 QGraphicsLinearLayout 类似于 QHLayoutBox或 QVLayoutBox,布局内的图形控件线性分布。

用QGraphicsLinearLayout创建线性布局的方法如下,其中parent是QGraphicsLayoutItem 的实例;Qt.Orientation 确定布局的方法可以取 QHorizontal或Qt.Vertical,默认是水平方向。

1
2
3
4
from PySide6.QtWidgets import QGraphicsLinearLayout

QGraphicsLinearLayout(orientation: PySide6.QtCore.Qt.Orientation, parent: Union[PySide6.QtWidgets.QGraphicsLayoutItem, NoneType]= None) -> None
QGraphicsLinearLayout(parent: Union[PySide6.QtWidgets.QGraphicsLayoutItem, NoneType]= None) -> None

QGraphicsLinearLayout 的主要方法如表所示。

  • 用图形控件的setLayout(QGraphicsLayout)方法可以添加二个布局,
  • 用addItem(QGraphicsLayoutItem)方法可以添加图形控件,
  • 用insertItem(index,QGraphicsLayoutItem)方法在指定索引处插人图形控件,
  • 用addStretch(stretch=1)方法可以添加空间拉伸系数,
  • 用insertStretch(index,stretch=1)方法插人空间拉伸系数
  • 用setStretchFactor(QGraphicsLayoutItem,int)方法设置图项或布局的拉伸系数,
  • 用setOrientation(QtOrientation)方法设置布局的方向。
QGraphicsLinearLayout的方法及参数类型 说明
addItem(item: QGraphicsLayoutItem) 添加图形控件、代理控件或布局
insertItem(index:int, item:QGraphicsLayoutItem) 根据索引插入图形控件或布局
addStretch(stretch: int=1) 在末尾添加拉伸系数
insertStretch(index: int,stretch:int=1) 根据索引插入拉伸系数
count() 获取弹性控件和布局的个数
setAlignment(QGraphicsLayoutItem,Qt.Alignment) 设置图形控件的对齐方式
setGeometry(rect:Union[QRectF,QRect]) 设置布局的位置和尺寸
setItemSpacing(index:int,spacing:float) 根据索引设置间距
setOrientation(Qt.Orientation) 设置布局方向
setSpacing(spacing:float) 设置图形控件之间的间距
setStretchFactor(item: QGraphicsLayoutItem,stretch: int) 设置图形控件的拉伸系数
stretchFactor(item:QGraphicsLayoutItem) 获取控件的拉伸系数
itemAt(index:int) 根据索引获取图形控件或布局
removeAt(index:int) 根据索引移除图形控件或布局
removeltem(item:QGraphicsLayoutltem) 移除指定的图形控件或布局

下面的程序在 QGraphicsWidget 中添加线性布局在布局中添加了两个 QLabel和两个 QPushButton。

image-20230309232358243

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/9 23:10
# File_name: 02-线性布局QGraphicsLinearLayout.py


import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QGraphicsProxyWidget, QGraphicsScene, QGraphicsView, QPushButton, QGraphicsWidget, QGraphicsLinearLayout, QLabel
from PySide6.QtCore import Qt


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(500, 500)

view = QGraphicsView() # 视图控件
scene = QGraphicsScene() # 场景
view.setScene(scene) # 视图中设置场景

v = QVBoxLayout(self) # 布局
v.addWidget(view)

widget = QGraphicsWidget()
widget.setFlags(QGraphicsWidget.ItemIsMovable | QGraphicsWidget.ItemIsSelectable)
scene.addItem(widget)
linear = QGraphicsLinearLayout(Qt.Vertical, widget) # 线性竖直布局
label1 = QLabel("MyLabel 1")
label2 = QLabel("MyIabel2")
button1 = QPushButton("MyPushbutton 1")
button2 = QPushButton("MyPushbutton 2")

p1 = QGraphicsProxyWidget()
p1.setWidget(label1)

p2 = QGraphicsProxyWidget()
p2.setWidget(label2)

p3 = QGraphicsProxyWidget()
p3.setWidget(button1)

p4 = QGraphicsProxyWidget()
p4.setWidget(button2)

linear.addItem(p1)
linear.addItem(p2)
linear.addItem(p3)
linear.addItem(p4)

linear.setSpacing(10)
linear.setStretchFactor(p3, 1)
linear.setStretchFactor(p4, 2)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

格栅布局 QGraphicsGridLayout

格栅布局QGraphicsGridLayout与 QGridLayout 类似,由多行和多列构成,一个图形控件可以占用一个节点,也可以占用多行和多列。

用QGraphicsGridLayout创建格棚市局的方法如下所示,其中parent是 QGraphicsLayoutItem 的实例或图形控件。

1
2
3
from PySide6.QtWidgets import QGraphicsGridLayout

QGraphicsGridLayout(parent: Union[PySide6.QtWidgets.QGraphicsLayoutItem, NoneType]= None) -> None

QGraphicsGridLayout 的常用方法如表示:

可以添加和移除图形控件及布局,可以设置列宽度、行高度、列之间的间隙和行之间的间隙,及行或列的拉伸系数。

QGraphicsGridLayout的方法及参数类型 说 明
addltem(item: QGraphicsLayoutltem,row: int, column: int,alignment: Qt.Alignment =Default(Qt.Alignment)) 在指定的位置添加图形控件
addItem(item: QGraphicsLayoutltem,row: int, column: int, rowSpan: int, columnSpan: int, alignment: Qt.Alignment) 添加图形控件,可占据多行多列
rowCount()、columnCount() 获取行数、获取列数
count() 获取图形控件和布局的个数
itemAt(row: int,column:int) 获取指定行和列处的图形控件或布局
itemAt(index:int) 根据索引获取图形控件或布局
removeAt(index: int) 根据索引移除图形控件或布局
removeItem(QGraphicsLayoutItem) 移除指定的图形控件或布局
setGeometry(rect:Union[QRectF,QRect]) 设置控件所在的区域
setAlignment(QGraphicsLayoutItem,Qt.Alignment) 设置控件的对齐方式
setRowAlignment(row: int, alignment: Qt.Alignment) 设置行对齐方式
setColumnAlignment(column:int, alignment: Qt.Alignment) 设置列对齐方式
setRowFixedHeight(row: int,height:float) 设置行的固定高度
setRowMaximumHeight(row:int,height: float) 设置行的最大高度 32LdG5
setRowMinimumHeight(row:int,height:float) 设置行的最小高度
setRowPreferredHeight(row:int,height: float) 设置指定行的高度
setRowSpacing(row: int,spacing:float) 设置指定行的间距
setRowStretchFactor(row:int,stretch: int) 设置指定行的拉伸系数
setColumnFixedWidth(column:int,width:float) 设置列的固定宽度
setColumnMaximumWidth(column:int,width:float) 设置列的最大宽度
setColumnMinimumWidth(column:int,width:float) 设置列的最小宽度
setColumnPreferredWidth(column:int,width:float) 设置指定列的宽度:
setColumnSpacing(column:int, spacing:float) 设置指定列的间隙
setColumnStretchFactor(column:int,stretch:int) 设置指定列的拉伸系数
setSpacing(spacing: float) 设置行、列之间的间隙
setHorizontalSpacing(spacing: float) 设置水平间隙
setVerticalSpacing(spacing:float) 设置竖直间隙
锚点布局OGraphicsAnchorLayout

锚点布局可以设置两个图形控件之间的相对位置,可以是两个边对齐,也可以是两个点对齐。

用QGraphicsAnchorLayout 创建铺点布局的方法如下,其中参数 parent 是QGraphicsLayoutItem 实例。

1
2
3
from PySide6.QtWidgets import QGraphicsAnchorLayout

QGraphicsAnchorLayout(parent: Union[PySide6.QtWidgets.QGraphicsLayoutItem, NoneType]= None) -> None

QGraphicsAnchorLayout 的方法中

  • 用addAnchor(firstItem;QGraphicsLayoutItem;firstEdge: Qt.AnchorPoint, secondItem;QGraphicsLayoutItem, secondEdge: Qt.AnchorPoint)方法将第 1个图形控件的某个边与第 2个图形控件的某个边对齐,其中Q.AnchorPoint 可以取:
    • Qt.AnchorLeft
    • Qt.AnchorHorizontalCenter
    • Qt.AnchorRight
    • Qt.AnchorTop
    • Qt.AnchorVerticalCenter
    • Qt.AnchorBottom
  • 用addCornerAnchors(firstItem:QGraphicsLayoutItem, first(orner: Qt.(Corner, secondltem; QGraphicsLayoutItem , secondCorner :Qt.Corner)方法可以让第1个控件的某个角点与第2个控件的某个角点对齐,其中QCorner可以取:
    • Qt.TopLeftCorner
    • Qt.TopRightCorner
    • Qt.BottomLeftCorner
    • Qt.BottomRightCorner;
  • 用addAnchors(firstItem; QGraphicslayoutItem, secondltem: QGraphicsLayoutItemorientations:Qt Orientations=Qt.Horizontal QtVertical)方法可以使两个控件在某个方向上尺寸相等。
  • 另外用setHorizontalSpacing(spacing; float)setVerticalSpacing(spacing:[loat)或 setSpacing(spacing:[loat)方法可以设置控件之间在水平和竖直方向的间距,
  • 用itemAt(index:int)方法可以取图形控件,用removeAt(index:int)方法可以移除图形控件,用count()方法可以获取图形控件的数量

图形效果

在图项和视图控件的视口之间可以添加渲染通道,实现对图项显示效果的特殊设置。

图形效果 QGraphicsEffect 类是图形效果的基类,图形效果类有:

  • QGraphicsBlurEffect(模糊效果)
  • QGraphicsColorizeEffect(变色效果)
  • QGraphicsDropShadowEffect(阴影效果)
  • QGraphicsOpacityEffect(透明效果)

用图项的 setGraphicsEffect(QGraphicsEffect)方法设置图项的图形效果。

创建这 4 种效果的方法如下所示,其中 parent 是指继承自 QObject 的实例。

1
2
3
4
5
6
from PySide6.QtWidgets import QGraphicsBlurEffect, QGraphicsColorizeEffect, QGraphicsDropShadowEffect, QGraphicsOpacityEffect

QGraphicsBlurEffect(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QGraphicsColorizeEffect(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QGraphicsDropShadowEffect(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QGraphicsOpacityEffect(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
图形效果的常用方法

QGraphicsBlurEffect、 QGraphicsColorizeEffect、QGraphicsDropShadowEffect 和QGraphicsOpacityEffect 的常用方法如表所示

  • QGraphicsBlurEffect
图形效果的方法及参数类型 说明
setEnabled(enable: bool) 设置激活图形效果
[slot]setBlurHints(hints: QGraphicsBlurEffect.BlurHints) 设置模糊提示
[slot]setBlurRadius(blurRadius:float) 设置模糊半径
blurHints() 获取模糊提示
blurRadius() 获取模糊半径
  • QGraphicsColorizeEffect
图形效果的方法及参数类型 说明
[slot]setColor(Union[QColor,Qt.GlobalColor, str]) 设置着色用的颜色
[slot]setStrength(strength:float) 设置着色强度
color() 获取着色用的颜色
strength() 获取着色强度
  • QGraphicsDropShadowEffect
图形效果的方法及参数类型 说明
[slot]setBlurRadius(blurRadius:float) 设置模糊半径
[slot]setColor(Union[QColor, Qt.GlobalColor, str]) 设置引用颜色
[slot]setOffset(d: float) 设置阴影的x和y偏 移量
[slot]setOffset(dx: float,dy:float) 设置阴影的x和y偏 移量
[slot]setOffset(ofs: Union[QPointF,QPoint]) 设置阴影的位移量
[slot]setXOffset(dx: float) 设置阴影的x偏移量
[slot]setYOffset(dy:float) 设置阴影的y偏移量
blurRadius() 获取模糊半径
color() 获取阴影颜色QColor
offset() 获取阴影的偏移量
xOffset() 获取阴影的x偏移量
yOffset() 获取阴影的y偏移量
  • QGraphicsOpacityEffect
图形效果的方法及参数类型 说明
[slot]setOpacity(opacity: float) 设置不透明度
[slot]setOpacityMask(Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor,QGradient, QTmage,QPixmap]) 设置遮掩面刷
opacity() 获取不透明度
opacityMass() 获取遮掩画刷 QBrush

主要方法介绍如下

  • 模糊效果是使图项变得模糊不清,可以隐藏一些细节。在一个图项失去焦点,或将注意力移到其他图项上时可以使用模糊效果。

    • QGraphicsBlurEffect 的模糊效果是通过设置模糊半径和模糊提示实现的。

    • QGraphicsBlurEffect 主要有槽函数setBlurRadius(blurRadius;float),setBlurHints(QGraphicsBlurEffect, BlurHint).

    • 其中模糊半径默认为5个像聚,模糊半径越大图像越模糊;

    • 模糊提示QGraphicsBlurEffect,BlurHint 可以取:

      • QGraphicsBlurEffect.PerformanceHint(主要考虑染性能)
      • QGraphicsBlurEffect,QualityHint(主要考虑染质量)
      • QGraphicsBlurEffect,AnimationHint(用于染动画)。
  • 变色效果是用另外一种颜色给图项着色

    • QGraphicsColorizeEffect 的变色效果是通过设置新颜色和着色强度来实现的,默认的着色是浅蓝色(QColor(0,0,192))
    • QGraphicsColorizeEffeet 主要有槽函数 setColor(Union[QColor,Qt.GlobalColor, str])和 setStrength(strength: float)
  • 阴影效果能给图项增加立体效果

    • QGraphicsDropShadowEffect 的阴影效果需要设置背景色、模糊半径和阴影的偏移量。默认的阴影颜色是灰色(QColor(63,63,63.180)),默认的模糊半径是 1,偏移量是8个像素,方向是右下
    • QGraphicsDropShadowEffect 主要有槽函数
      • setBlurRadius(blurRadius float)
      • setColor(Union[QColor, Qt.GlobalColor,str])
      • setOffset(dx: float,dy: float)
      • setOffset(ofs: Union[QPointF,QPoint])
  • 透明效果可以使人看到图项背后的图形

    • QGraphicsOpacityEffect 的透明效果需要设置不透明度。
    • QGraphicsOpacityEffect 有函数:
      • setOpacity(opacity: float)
      • setOpacityMask(Union[QBrush,Qt.BrushStyle, Qt.GlobalColor,QColor.QGradient,QImage,QPixmap])
    • setOpacity(opacity:float)用于设置不透明度opacity 的值在 0.0~1.0之间,00表示完全透明,10表示完全不透明,默认值为0.7;
    • setOpacityMask()用于设置部分透明。
图形效果的信号

图形效果的信号如表所示

图形效果 图形效果的信号及参数类型 说明
QGraphicsBlurEffect blurRadiusChanged(radius: float) 模糊半径发生改变时发送信号
QGraphicsBlurEffect blurHintsChanged(hints: QGraphicsBlurEffect.BlurHints) 模糊提示发生改变时发送信号
QGraphicsColorizeEffect colorChanged(color:QColor) 颜色发生改变时发送信号
QGraphicsColorizeEffect strengthChanged(strength: float) 强度发生改变时发送信号
QGraphicsDropShadow Effect blurRadiusChanged(blurRadius:float) 模糊半径发生改变时发送信号
QGraphicsDropShadow Effect colorChanged(color:QColor) 阴影颜色发生改变时发送信号
QGraphicsDropShadow Effect offsetChanged(offset: QPointF) 阴影偏移量发生改变时发送信号
QGraphicsOpacityEffect opacityChanged(opacity:float) 不透明度发生改变时发送信号
QGraphicsOpacityEffect opacityMaskChanged(mask:QBrush) 遮掩画刷发生改变时发送信号

数据读写和文件管理

在程序运行时会生成各种各样的数据,如果数据量少,可以直接将其保存在内存中,算结束时清空内存并把结果保存到文件中;

如果在计算中生成大量的中间数据,则需要把数据写到临时文件中,计算结束时把临时文件删除。

为保存数据,可以用Python 提供的open()函数打开或新建文件进行文本文件的读写

对于大量的有固定格式的数据(例如用科学计数法表示的数据)可以用PySide6 提供的以数据流的方式读写文本数据二进制数据和原生数据的方法和函数,以及对临时文件进行管理和监控的函数,很方便地对数据进行读写和对文件进行管理。

数据读写的基本方法

把计算过程中的数据保存下来或者读取已有数据是任何程序都需要进行的工作PySide6 把文件当作输入输出设备,可以把数据写到设备中,或者从设备中读取数据,从而达到读写数据的目的。

可以利用QFile类调用QIODevice类的读写方法直接进行读写

或者把QFile类和QTextStream类结合起来用文本流(text stream)的方法进行文本数据的读写

还可以把 QFile类和QDataStream 类结合进来,用数据流(data stream)的方法进行二进制数据的读写。

QIODevice类

QIODevice 类是抽象类,是执行读数据和写数据类(如 QFile QBuffer)的基类它提供读数据和写数据的接口。

QIODevice类在 QtCore 模块中。直接或间接继承自 QIODevice,与本地读写文件有关的类有

  • QBuffer
  • QFile
  • QFileDevice
  • QProcess
  • QSaveFileQTemporaryFile

这些类之间的继承关系如图所示。另外还有网络方面的读写类

  • QAbstractSocket
  • QLocalSocket
  • QNetworkReply
  • QSslSocket
  • QTcpSocket
  • QUdpSocket

image-20230310133920454

QIODevice类提供读写接口但是不能直接使用QIODevice 类进行数据的读写而是使用子类QFile或QBuffer 的继承自QIODevice 的读写方法来进行数据读写。

在一些系统中将所有的外围设备都当作文件来处理,因此可以读写的类都可以当作设备来处理。QIODevice的常用方法如表所示,主要方法介绍如下。

QIODevice的方法及参数类型 返回值的类型 说明
open(QIODeviceBase. OpenMode) bool 打开设备,成功则返回True
isOpen() bool 获取设备是否已经打开
setOpenMode(QIODeviceBase.OpenMode) None 打开设备后,重新设置打开模式
close() None 关闭设备
setTextModeEnabled(bool) None 设置是否是文本模式
read(maxlen; int) QByteArray 读取指定数量的字节数据
readAl]() QByteArray 读取所有数据
readLine(maxlen:int=0) QByteArray 按行读取 ASCII数据
getChar(c: bytes) bool 读取一个字符,并存储到c中
ungetChar(c; str) None 将字符重新存储到设备中
peek(maxlen;int) QByteArray 读取指定数量的字节
write(data:Union[QByteArray,bytes]) int 写入字节数组,返回实际写入的字节 数量
writeData(data: bytes,len: int) int 写人字节串,返回实际写人的宇节数量
putChar(c:str) bool 写人一个字符,成功则返回True
setCurrentReadChannel(int) None 设置当前的读取通道
setCurrentWriteChannel(int) None 设置当前的写入通道
currentReadChannel() int 获取当前的读取通道
currentWriteChannel() int 获取当前的写入通道
readChannelCount() int 获取读取数据的通道数量
writeChannelCount() int 获取写入数据的通道数量
canReadLine() bool 获取是否可以按行读取
QIODevice的方法及参数类型 返回值的类型 说明
bytesToWrite() int 获取缓存中等待写人的字节数量
bytesAvailable() None 获取可读取的字节数量
setErrorString(str) None 设置设备的出错信息
errorString() Str 获取设备的出错信息
isReadable() bool 获取设备是否是可读的
isSequential() bool 获取设备是否是顺序设备
isTextModeEnabled() bool 获取设备是否能以文本方式读写
isWritable() bool 获取设备是否可写人
atEnd() bool 获取是否已经到达设备的末尾
seek(pos: int) bool 将当前位置设置到指定值
pos() int 获取当前位置 .
reset() bool 重置设备,回到起始位置,成功则返回 True;如果设备没有打开则返回 False
startTransaction() None 对随机设备,记录当前位置;对顺序设 备,在内部复制读取的数据以便恢复数据
rollbackTransaction() None 回到调用startTransaction()的位置
commitTransaction() None 对顺序设备,放弃记录的数据
isTransactionStarted() bool 获取是否开始记录位置
size() int 获取随机设备的字节数或顺序设备的 bytesAvailable()值
skip(int) int 跳过指定数量的字节,返回实际跳过的 字节数
waitForBytesWritten(msecs:int) bool 对于缓存设备,该方法需要将数据写到 设备中或经过msecs毫秒后返回值
waitForReadyRead(msecs:int) bo01 当有数据可以读取前或经过msecs 毫秒 前会阻止设备的运行
  • 读写设备分为两种,一种是随机设备(random-access device),另一种是顺序设备(sequential device),

    • 用isSequential()方法可以判断设备是否是顺序设备。
      • QFile和QBuffer 是随机设备
      • QTcpSocket 和QProcess 是顺序设备
    • 。随机设备可以获取设备指针的位置,将指针指向指定的位置,从指定位置读取数据;而顺序设备只能依次读取数据。
      • 随机设备可以用seek(pos:int)方法定位,
      • 用pos()方法获取位置
  • 读取数据的方法有

    • read(maxlen:int)、

    • readAll()、

    • readData(data: bytes,maxlen:int)、

    • readLine(maxlen: int=0)

    • readLineData(data: bytes,maxlen: int),

    • getChar(c:bytes)

    • peek(maxlen:int)

    • read(maxlen:int)表示读取指定长度的数据

      • readLine(maxlen:int=0)表示读取行参数maxlen 表示允许读取的最大长度,若为0表示不受限制。
  • 写人数据的方法有

    • write(QByteArray)

    • writeData(bytes)

    • putChar(c:str)

    • getChar(c;bytes)和 putChar(c;str)只能读取和写人一个字符

    • 如果要继承 QIODevice 创建自己的读写设备需要重写 readData()和 writeData()函数。

  • 一些顺序设备支持多通道读写,这些通道表示独立的数据流

    • 可以用setCurrentReadChannel(int)方法设置读取通道
    • 用setCurrentWriteChannel(int)方法设置写人通道
    • 用currentReadChannel()方法和currentWriteChannel()方法获取读取和写入通道

字节数组QByteArray

在利用QIODevice 的子类进行读写数据时通常返回值或参数是 QByteArray类型的数据。Q

  • ByteArray 用于存储二进制数据,至于这些数据到底表示什么内容(字符串数字图片或音频等),完全由程序的解析方式决定。
  • 如果采用合适的字符编码方式(字符集),字节数组可以恢复成字符串,字符串也可以转换成字节数组。
  • 字节数组会自动添加”\0”作为结尾,统计字节数组的长度时,不包含末尾的0”。

用QByteArray创建字节数组的方法如下,其中c只能是一个字符,例如”a”,size指c的个数,例如 QByteArray(5,a”)表示”aaaaa”

1
2
3
4
5
6
7
8
from PySide6.QtCore import QByteArray

QByteArray(self) -> None
QByteArray(arg__1: bytearray) -> None
QByteArray(arg__1: bytes) -> None
QByteArray(arg__1: bytes, size: int = -1) -> None
QByteArray(arg__1: Union[PySide6.QtCore.QByteArray, bytes]) -> None
QByteArray(size: int, c: int) -> None
  • 用Python的 str(QByteArrayencoding=”utf-8”)函数可以将 QByteArray 数据转换成Python的字符串型数据。
  • 用QByteArray 的append(str)方法可以将 Pthon 的字符串添加到QByteArray 对象中,同时返回包含字符串的新QByteArray 对象。

QByteArray的常用方法如表所示,一些需要说明的方法介绍如下:

  • QByteArray 对象用resize(size:int)方法可以调整数组的尺寸
  • 用size()方法可以获取字节数组的长度,用”[]”操作符或at(iint)方法读取数据。
  • 用append(Union[QByteArray,bytes])或 append(c:str)方法可以在末尾添加数据,
  • 用prepend(Union[QByteArraybytes])方法可以在起始位置添加数据
  • 用静态方法 fromBase64(Union[QByteArray,bytes],options = QByteArray.Base64Encoding)可以把 Base64 编码数据解码
  • 用toBase64(options:QByteArray.Base64Option)方法可以转换成 Base64 编码其中参数options 可以取:
    • QByteArray.Base64UrlEncoding
    • QByteArray.KeepTrailingEqualsBase64Encoding
    • QByteArray.QByteArray. OmitTtailingEquals
    • QByteArray.IgnoreBase64DecodingErrors
    • QByteArray.AbortOnBase64DecodingErrors。
  • 用setNum(float,format=’g’,precision=6)方法或 number(float,format=’gprecision=6)方法可以将浮点数转换成用科学计数法表示的数据
    • 其中格式format可以取eEfg、`G``
      • ``e表示的格式如[-]9.9e[+ | -]999`
      • E表示的格式如[-]9.9E[+ | -]999
      • f表示的格式如[-]9.9
      • g表示视情况选择ef
      • G表示视情况选择WF
QByteArray的方法及参数类型 返回值的类型 说明
append(Union[QByteArray,bytes]) QByteArray 在末尾追加数据
append(c: str)、append(count:int,c:str) QByteArray 在末尾追加文本数据
append(s: bytes,len:int) QByteArray 在末尾追加数据
at(i:int) Str 根据索引获取数据
chop(n:int) None 从尾部移除n个字节
chopped(len:int) QByteArray 获取从尾部移除len个字节后的字 节数组
clear() bool 清空所有字节
contains(Union[QByteArray,bytes]) bo01 获取是否包含指定的字节数组
contains(c: str) bool 获取是否包含指定的字符
count(Union[QByteArray,bytes]) int 获取包含的字节数组的个数
count()、size() int 获取长度
data() bytes 获取字节串
endsWith(Union[QByteArray,bytes]) bool 获取末尾是否是指定的字节数组
endsWith(c: str) bool 获取末尾是否是指定的字符
startsWith(Union[QByteArray,bytes]) bool 获取起始是否是指定的字节数组
fill(str,size=-1) QByteArray 使数组的每个数据为指定的字符, 将长度调整成size
[static]fromBase64(Union[QByteArray, bytes],options=QByteArray.Base64Encoding) QByteArray 从Base64编码中解码
[static]fromBase64 Encoding(Union[bytes, QByteArray],options) QByteArray 从Base64编码中解码
[static]fromHex(Union[QByteArray, bytes]) QByteArray 从十六进制数据中解码
[static]fromPercentEncoding(Union[QByteArray,bytes].percent: str=’%’) QByteArray 从百分号编码中解码
[static]fromRawData(data:bytes,size: int) QByteArray 用前size个原生字节构建字节数组
indexOf(Union[QByteArray,bytes],from_ =0) int 获取索引
indexO{(str,from_:int=0) int 获取索引
insert(int,Union[QByteArray,bytes]) QByteArray 根据索引在指定位置插人字节数 组,返回值是插入后的字节数组
insert(i: int,c: str) QByteArray 在指定位置插人文本数据
insert(i:int,count:int,c:str) QByteArray 同上,count是指数据的份数
isEmpty() 6001 AS 是否为空,长度为0时返回 True, QByteArray(“”).isEmpty()的值 是 False
isNull() bool 内容为空时返回 True,QByteArray(“”).isNull()的值是 False
isLower() bool 全部是小写字母时返回True
isUpper() bool 全部是大写字母时返回True
lastlndexOf(Union[QByteArray, bytes], {rom_=-1) int 获取最后索引值
lastIndexO{(str.from_=-1) int 同上
length() int 获取长度,与 size()相同
mid(int,length=-1) QByteArray 从指定位置获取指定长度的数据
[static]number(float,format=’g’, precision=6) QByteArray 将浮点数转换成科学计数法数据
[static]number(int,base=10) QByteArray 将整数转换成base进制数据
prepend(Union[QByteArray,bytes]) QByteArray 在起始位置添加数据
remove(index:int,len:int) QByteArray 从指定位置移除指定长度的数据
repeated(times: int) QByteArray 获取重复times次后的数据
replace(index: int, len: int, Union[QByteArray,bytes]) QByteArray 从指定位置用数据替换指定长度 数据
replace(before: Union[QByteArray,bytes], after: Union[QByteArray,bytes]) QByteArray 用数据替换指定的数据
resize(size:int) None 调整长度,如果长度小于现有长度, 则后面的数据会被丢弃
setNurn(float,format=’g’,precision=6) QByteArray 将浮点数转换成科学计数法数据
setNum(int,base=10) QByteArray 将整数转换成指定进制的数据
split(sep:str) ListCQByteArrayJ 用分割符将字节数组分割成列表
squeeze() None 释放不存储数据的内存

Python3中新添加了字节串 bytes 数据类型其功能与QByteArray的功能类似。

如果一个字符串前面加b,就表示是 bytes类型的数据例如 b"hello"

bytes 数据和字符串的对比如下:

  • 字节是计算机的语言,字符串是人类的语言,它们之间通过编码表形成对应关系。

  • 字符串由若干个字符组成,以字符为单位进行操作;bytes 由若干个字节组成,以字节为单位进行操作。

  • bytes 和字符申除了操作的数据单元不同之外,它们支持的所有方法都基本相同。

  • bytes 和字符串都是不可变序列,不能随意增加和删除数据

  • 用xx=bytes(“hello”, encoding=’ut-8’)方法可以将字符”hello”转换成bytes

  • 用yy=str(xx, encoding=’utf-8)方法可以将 bytes 转换成字符串。

  • bytes 也是一个类用bytes()方法可以创建一个空 bytes 对象,

    • 用bytes(int)方法可以创建指定长度的 bytes 对象,
    • 用decode(encoding=’utf-8’)方法可以对数据进行解码,bytes 的操作方法类似于字符串的操作方法。
  • Python中还有一个与 bytes类似但是可变的数组 bytearray;

    • 其创建方法和字符串的转换方法与bytes相同,在 QByteArray 的各个方法中可以用bytes 数据的地方也可以用bytearrayo
  • bytes 数据和QByteArray 数据非常适合在互联网上传输,可以用于网络通信编程bytes 和QByteArray 都可以用来存储图片音视频等二进制格式的文件。

QFile读写数据

QFile 继承自QIODevice,会继承 QIODevice 的方法,

QFile 可以读写文本文件和二进制文件,可以单独使用,也可以与QTextStream 和 QDataStream 一起使用。

用QFile类创建实例对象的方法如下所示,其中 parent 是继承自QObject 的实例,str 是要打开的文件需要注意的是,文件路径中的分隔符可以用///,而不能用\

1
2
3
4
5
6
from PySide6.QtCore import QFile

QFile(self) -> None
QFile(name: Union[str, bytes, os.PathLike]) -> None
QFile(name: Union[str, bytes, os.PathLike], parent: PySide6.QtCore.QObject) -> None
QFile(parent: PySide6.QtCore.QObject) -> None
QFile的常用方法

QFile的常用方法如表所示,主要方法介绍如下

  • QFile打开的文件可以在创建实例时输入
    • 也可以用setFileName(name:Union[str,bytes,os.PathLike])方法来设置
      • 用fileName()方法可以获取文件名。
    • 设置文件名后,用open(QIODeviceBase OpenMode)方法打开文件
      • 或者用open(fh,QIODevice.OpenMode,handleFlags)方法打开文件;
        • 其中fh 是文件句柄号(filehandle),文件句柄号对于打开的文件而言是唯一的识别标识;
        • 参数 handleFlags可以取 QFileDevice.AutoCloseHandle(通过 close()来关闭)或 QFileDevice.DontCloseHandle(如果文件没有用close()关闭,当QFile 构后,文件句柄一直打开,这是默认值)。
  • QFile 的读取和写入需要使用QIODevice 的方法
    • 例如 read(int)、readAlI()readLine()、getChar()、peek(int),write(QByteArray)或 putChar(str)。
    • 用setPermissions(QFileDevice,Permission)方法设置打开的文件的权限,其中参数QFileDevice.Permission 可以取:
      • QFileDevice.ReadOwner(只能由所有者读取)
      • QFileDevice.WriteOwner(只能由所有者写入)
      • QFileDevice.ExeOwner(只能由所有者执行)
      • QFileDevice.ReadUser(只能由使用者读取)
      • QFileDevice.WriteUser(只能由使用者写入)
      • QFileDevice.ExeUser(只能由使用者执行)
      • QFileDevice.ReadGroup(工作组可以读取)
      • QFileDevice.WriteGroup(工作组可以写入)
      • QFileDevice.ExeGroup(工作组可以执行)
      • QFileDevice.ReadOther(任何人都可以读取)
      • QFileDevice.WriteOther(任何人都可以写人)
      • QFileDevice.ExeOther(任何人都可以执行)
  • 用QFile 的静态函数可以对打开的文件或没有打开的文件进行简单的管理
    • 通过exists()方法判断打开的文件是否存在
    • 用exists(fileName)方法判断其他文件是否存在
    • 用copy(newName)方法可以把打开的文件复制到新文件中
    • 用copy(fileName,newName)方法可以把其他文件复制到新文件中
    • 用remove()方法可以移除打开的文件
    • 用remove(fileName)方法可以移除其他文件
    • 用rename(newName)方法可以对打开的文件重命名
    • 用rename(oldName;newName)方法可以对其他文件重命名
QFile的方法及参数类型 说 明
open(flags: QIODeviceBase. OpenMode) 按照模式打开文件,成功则返回True
setFileName(name: Union[str,bytes, os. PathLike]) 设置文件路径和名称
fileName() 获取文件名称
flush() 将缓存中的数据写人到文件中
atEnd() 判断是否到达文件末尾
close() 关闭设备
[static]setPermissions(QFileDevice. Permission) 设置权限,成功则返回True
[static]exists() 获取用fileNane()指定的文件名是否存在
[static]exists(str) · 获取指定的文件是否存在
[static]copy(newName:Union[str,bytes]) 复制打开的文件到新文件中,成功则返回True
[static]copy(fileName: str,newName:str) 将指定的文件复制到新文件中,成功则返回True
[static]remove() 移除打开的文件,移除前先关闭文件,成功则返回True
[static]remove(fileName: str) 移除指定的文件,成功则返回True
[static]rename(newName: str) 重命名,重命名前先关闭文件,成功则返回True
[static]rename(oldName: str,newName: str) 给指定的文件重命名,成功则返回True
QFile的应用实例

下面的程序通过菜单,利用QFile文件可以打开文本文件或十六进制编码文件*hex也可以保存文本文件或十六进制编码文件。

本程序打开的十六进制编码文件是由本程序保存后的十六进制编码文件,不能打开其他程序生成的十六进制编码文件。

程序中可以把打开文本文件和十六进制编码文件的代码放到一个函数中,根据文件扩展名来决定打开哪种格式的文件,保存文件也可以作同样的处理,这里分开到不同动作的槽函数中分别打开文本文件和十六进制文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/10 22:57
# File_name: 01-QFile的应用实例.py


from PySide6.QtWidgets import QApplication, QMainWindow, QPlainTextEdit, QFileDialog
from PySide6.QtCore import QFile, QByteArray
import sys


class MyWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupUI() # 界面

def setupUI(self): # 界面建立
self.plainText = QPlainTextEdit()
self.setCentralWidget(self.plainText)
self.status = self.statusBar()
self.menubar = self.menuBar() # 文件菜单
self.file = self.menubar.addMenu("文件") # 菜单栏

action_textOpen = self.file.addAction("打开文本文件") # 动作
action_textOpen.triggered.connect(self.textOpen_triggered) # 动作与槽的连

action_dataOpen = self.file.addAction("打开十六进制文件")
action_dataOpen.triggered.connect(self.dataOpen_triggered)

self.file.addSeparator()

action_textWrite = self.file.addAction("保存到新文本文件中")
action_textWrite.triggered.connect(self.textWrite_triggered)

action_dataWrite = self.file.addAction("保存到十六进制文件")
action_dataWrite.triggered.connect(self.dataWrite_triggered)

self.file.addSeparator()

action_close = self.file.addAction("关闭")
action_close.triggered.connect(self.close)

def textOpen_triggered(self):
fileName, file = QFileDialog.getOpenFileName(self, caption="打开文本文件", filter="text(*.txt);;python(*.py);;所有文件(*.*)")
file = QFile(fileName)
if file.exists():
file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text) # 打开文件
self.plainText.clear()

try:
while not file.atEnd():
string = file.readLine() # 按行读取
string = str(string, encoding="utf-8") # 转成字符串
self.plainText.appendPlainText(string.rstrip('\n'))
except:
self.status.showMessage("打开文件失败!")
else:
self.status.showMessage("打开文件成功!")

file.close()

def textWrite_triggered(self):
fileName, file = QFileDialog.getSaveFileName(self, caption="另存为", filter="text(*.txt);;python(*.py);;所有文件(*.*)")
string = self.plainText.toPlainText()

if fileName != "" and string != "":
ba = QByteArray(string)
file = QFile(fileName)

try:
file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text) # 打开文件
file.write(ba)
except:
self.status.showMessage("文件保存失败!")
else:
self.status.showMessage("文件保存成功!")

file.close()

def dataOpen_triggered(self):
fileName, file = QFileDialog.getOpenFileName(self, caption="打开Hex文件", filter="Hex文件(*.hex);;所有文件(*.*)")

file = QFile(fileName)
if file.exists():
file.open(QFile.OpenModeFlag.ReadOnly) # 打开文件
self.plainText.clear()

try:
while not file.atEnd():
string = file.readLine() # 按行读取数据
string = QByteArray.fromHex(string) # 从十六进制数据中解码
string = str(string, encoding="utf-8") # 从字节转成字符串
self.plainText.appendPlainText(string)
except:
self.status.showMessage("打开文件失败!")
else:
self.status.showMessage("打开文件成功!")

def dataWrite_triggered(self):
fileName, file = QFileDialog.getSaveFileName(self, caption="另存为Hex文件", filter="Hex文件(*.hex);;所有文件(*.*)")

string = self.plainText.toPlainText()
if fileName != "" and string != "":
ba = QByteArray(string)
hex_ba = ba.toHex()
file = QFile(fileName)

try:
file.open(QFile.OpenModeFlag.WriteOnly) # 打开文件
file.write(hex_ba)
except:
self.status.showMessage("文件保存失败!")
else:
self.status.showMessage("文件保存成功!")

file.close()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

用流方式读写数据

从本机上读写数据更简便的方法是用流(stream)方式,读写文本数据用文本流QTextStream;读写二进制数据用数据流QDataStream。

用数据流可以将文本整数和浮点数以二进制格式保存到文件中,也可以将常用的类的实例保存到文件中,可以从文件中直接读取类的实例。

文本流QTextStream

文本流是指一段文本数据,可以理解成管道中流动的一股水,管道接到什么设备上,水就流人什么设备内。QTextStream 是文本流类,它可以连接到 QIODevice 或 QByteArray上,可以将一段文本数据写人 QIODevice 或 QByteArray 上,或者从QIODevice 或QByteArray 上读取文本数据。

QTextStream 适合写入大量的有一定格式要求的文本,例如试验获取的数值数据,需要将数值数据按照一定的格式写人文本文件中,每个数据需要有固定的长度、精度、对齐方式,数据可以选择是否用科学计数法表示,数据之间要用固定长度的空格隔开等。

用QTextStream 定义文本流的方法如下所示,可以看出其连接的设备可以是QIODevice 或 QByteArray。

1
2
3
4
5
6
from PySide6.QtCore import QTextStream

QTextStream(self) -> None
QTextStream(device: PySide6.QtCore.QIODevice) -> None
QTextStream(array: Union[PySide6.QtCore.QByteArray, bytes],
openMode: PySide6.QtCore.QIODeviceBase.OpenModeFlag = Instance(PySide6.QtCore.QIODeviceBase.OpenModeFlag.ReadWrite)) -> None
文本流QTextStream 的常用方法

QTextStream的常用方法如表 所示,主要方法介绍如下

  • QTextStream 的连接设备可以在创建文本数据流时定义
    • 也可以用setDevice(QIODevice)方法来定义,用device()方法获取连接的设备。
    • QTextStream 与QFile结合可读写文本文件,与QTcpSocketQUdpSocket 结合可读写网络文本数据
  • QTextStream没有专门的写数据的方法
    • 需要用流操作符<<来完成写人数据,
      • <<的左边是QTextStream实例
      • 右边可以是字符串整数或浮点数
      • 如果要同时写人多个数据,可以把多个<<写到一行中,例如out<'Grid'<100<<234<<n
      • 读取数据的方法有read(int)、readAll()和readLine(maxLength=0)
        • maxLength表示读行时一次允许的最大字节数。
      • 用seek(int)方法可以定位到指定的位置,成功则返回True;
      • 用pos()方法获取位置;
      • 用atEnd()方法获取是否还有可读取的数据。
  • 用setEncoding(QStringConverter.Encoding)方法设置文本流读写数据的编码,文本流支持的编码支持以下值,对应值分别是0-8
    • QStringConverter.Utf8
    • QStringConverter.Utf16
    • QStringConverter.Utf16LE
    • QStringConverter.Utf16BE
    • QStringConverter.Ut32
    • QStringConverter.Utf32LE
    • QStringConverter.Utf32BE
    • QStringConverter.Latinl
    • QStringConverterSystem(系统默认的编码)
  • 用setAutoDetectUnicode(bool)方法设置是否自动识别编码,如果能识别出则会替换已经设置的编码。
    • 如果setGenerateByteOrderMark(bool)为 True 且采用UTF编码,会在写人数据前在数据前面添加自动查找编码标识 BOM(byte-order mark)即字节顺序标记
    • 它是插人到以UTF-8UTF-16或UTF-32编码Unicode文件开头的特殊标记,用来识别 Unicode 文件的编码类型。
  • 用setFieldWidth(width:int=0)方法设置写人一段数据流的宽度如果真实数据流的宽度小于设置的宽度
    • 可以用setFieldAlignment(QTextStreamFieldAlignment)方法设置数据在数据流内的对齐方式
    • 其余位置的数据用setPadChar(str)设置的字符来填充。
    • 参数 QTextStream.FieldAlignment 用于指定对齐方式,可以取:
      • QTextStream.AlignLeft(左对齐)
      • QTextStream.AlignRight(右对齐)
      • QTextStream.AlignCenter(居中)
      • QTextStream.AlignAccountingStyle(居中,但数值的符号位靠左)
  • 用setIntegerBase(int)方法设置读取整数或产生整数时的进制,可以取2810或16,用setRealNumberPrecision(int)方法设置浮点数小数位的个数。
  • 用setNumberFlags(QTextStream,NumberFlag)方法设置输出整数和浮点数时数值的表示样式,其中参数QTextStream,NumberFlag 可以取:
    • QTextStream.ShowBase(以进制作为前缀,如 16(“0x”),8(“0”),2(“b”))
    • QTextStream.ForcePoint(强制显示小数点)
    • QTextStream.ForceSign(强制显示正负号)
    • QTextStream.UppercaseBase(进制显示成大写,如”0X””0B”)
    • QTextStream.UppercaseDigits(表示 10~35 的字母用大写)。
  • 用setRealNumberNotation(QTextStream,RealNumberNotation)方法设置浮点数的标记方法,参数QTextStream.RealNumberNotation 可以取:
    • QTextStream.ScientificNotation(科学计数法)
    • QTextStream.FixedNotation(固定小数点)
    • QTextStream.SmartNotation(视情况选择合适的方法)
  • 用setStatus(QTextStream,Status)方法设置数据流的状态,参数QTextStreamStatus可取以下值,对应值分别是0~3,用resetStatus()方法可以重量状态。
    • QTextStream.Ok(文本流正常)
    • QTextStream.ReadPastEnd(读取过末尾)
    • QTextStream.ReadCorruptData(读取了有问题的数据)
    • QTextStream.WriteFailed(不能写人数据)
QTextStream的方法及参数类型 说 明
setDevice(QIODevice) 设置操作的设备
device() 获取设备
setEncoding(QStringConverter.Encoding) 设置文本流的编码
encoding() 获取编码 QStringConverter. Encoding
setAutoDetectUnicode(bool) 设置是否自动识别编码,如果能识别,则替换现有 编码
setGenerateByteOrderMark(bool) 如果设置成True且编码是UTF,则在写人数据前会 先写人 BOM(byte order mark)
setFieldWidth(width;int=0) 设置数据流的宽度,如果为0,则宽度是数据的宽度
fieldWidth() 获取数据流的宽度
setFieldAlignment(QTextStream.FieldAlignment) 设置数据在数据流内的对齐方式
fieldAlignment() 获取对齐方式
setPadChar(str) 设置对齐时域内的填充字符
padChar() 获取填充字符
setIntegerBase(int) 设置读整数的进位制
integerBase() 获取进位制
setNumberFlags(QTextStream.NumberFlag) 设置整数和浮点数的标识
numberFlags() 获取数值数据的标识
setNumberFlags(QTextStream.NumberFlag) 设置整数和浮点数的标识
numberFlags() 获取数值数据的标识
setRealNumberNotation(QTextStream. RealNumberNotation) 设置浮点数的标记方法
realNumberNotation() 获取标记方法
setRealNumberPrecision(int) 设置浮点数的小数位数
rcalNumberPrecision() 获取精度
setStatus(QTextStream.Status) 设置状态
status() 获取状态
resetStatus() 重置状态
read(int) 读取指定长度的数据
readAII() 读取所有数据
readLine(maxLength=0) 按行读取数据,maxLength 是一次允许读的最大 长度
seek(int) 定位到指定位置,成功则返回True
pos() 获取位置
flush() 将缓存中的数据写到设备中
atEnd() 获取是否还有可读取的数据
skipWhiteSpace() 忽略空字符,直到非空字符或达到末尾
reset() 重置除字符串和缓冲以外的其他设置
文本流QTextStream读写文本数据的应用实例

下面的程序通过菜单操作,利用文本流,在d:sin costxt 文件中写入正弦、余弦、正弦+余弦的值也可以打开文本文件。

运行程序后先单击”文件”菜单下的”生成文件”,此时在目录下生成sin_cos.txt 文件;

再单击”文件”菜单下的”打开文件”弹出打开文件对话框,选择 sin_cos.txt 文件后,可以显示文件中的内容。

程序运行界面如图所示

image-20230311145838159

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 14:00
# File_name: 02- 文本流QTextStream读写文本数据的应用实例.py


import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPlainTextEdit, QFileDialog
from PySide6.QtCore import QFile, QTextStream, QStringConverter
from math import sin, cos, pi


class MyWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupUI() # 界面
self.fileName = "./sin_cos.txt" # 写人的文件

def setupUI(self): # 界面建立
self.plainText = QPlainTextEdit()
self.setCentralWidget(self.plainText)
self.status = self.statusBar()
self.menubar = self.menuBar() # 菜单栏
self.file = self.menubar.addMenu("文件") # 文件菜单
action_textCreate = self.file.addAction("生成文件") # 动作
action_textCreate.triggered.connect(self.textCreate_triggered) # 动作与槽的连接

action_textOpen = self.file.addAction("打开文件")
action_textOpen.triggered.connect(self.textOpen_triggered)

self.file.addSeparator()

action_close = self.file.addAction("关闭")
action_close.triggered.connect(self.close)

def textCreate_triggered(self):
file = QFile(self.fileName)

try:
if file.open(QFile.WriteOnly | QFile.Text | QFile.Truncate): # 打开文件
writer = QTextStream(file) # 创建文本流
writer.setEncoding(QStringConverter.Utf8) # 设置编码
writer.setFieldWidth(40) # 设置域宽
writer.setFieldAlignment(QTextStream.FieldAlignment.AlignCenter) # 设置对齐方式
writer.setRealNumberNotation(QTextStream.RealNumberNotation.ScientificNotation)
writer << "x(度)" << "sin(x)" << "cos(x)" << "sin(x)+cos(x)" # 写人数据
writer.setFieldWidth(0) # 设置域宽
writer << "\n" # 写人回车换行
writer.flush()
for i in range(360):
r = i / 180 * pi
writer.setFieldWidth(40)
writer << str(i) << str(sin(r)) << str(cos(r)) << str(sin(r) + cos(r))
writer.setFieldWidth(0)
writer << "\n"

except:
self.status.showMessage("写入文件失败!")

else:
self.status.showMessage("写入文件成功!")

file.close()

def textOpen_triggered(self):
fileName, file = QFileDialog.getOpenFileName(self, caption="打开文本文件", dir=".", filter="text(*.txt);;所有文件(*.*)")

file = QFile(fileName)
try:
if file.open(QFile.ReadOnly | QFile.Text): # 打开文件
self.plainText.clear()
reader = QTextStream(file)
reader.setEncoding(QStringConverter.Utf8)
reader.setAutoDetectUnicode(True)
string = reader.readAll() # 读取所有数据

self.plainText.appendPlainText(string)

except:
self.status.showMessage("打开文件失败!")
else:
self.status.showMessage("打开文件成功!")

file.close()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

数据流 QDataStream

数据流 QDataStream 用于直接读写二进制的数据和网络通信数据,二进制数据具体表的物理意义由读写方法以及后续的解码决定,数据流的读写与具体的操作系统无关,

用DataStream类创建数据流对象的方法如下所示它可以连接到继承自 QIODevice 的设各QByteArray 上。

1
2
3
4
5
6
from PySide6.QtCore import QDataStream

QDataStream(self) -> None
QDataStream(arg__1: PySide6.QtCore.QIODevice) -> None
QDataStream(arg__1: Union[PySide6.QtCore.QByteArray, bytes]) -> None
QDataStream(arg__1: Union[PySide6.QtCore.QByteArray, bytes], flags: PySide6.QtCore.QIODeviceBase.OpenModeFlag) -> None
数据流 QDataStream 的常用方法

数据流的一些常用方法如表所示,主要方法介绍如下

  • 创建数据流对象时,可以设置数据流关联的设备

    • 也可用setDevice(QIODevice)方法重新设置关联的设备
    • 用device()方法获取关联的设备。
  • 用setVersion(int)方法设置版本号。不同版本号的数据的存储格式有所不同,因此建议设暨版本号。到目前为止,版本号可取 :

    • QDataStream.Qt_1_0
    • QDataStream.Qt_2_0
    • QDataStream.Qt_3_0
    • QDataStream.Qt_3_1
    • QDataStream.Qt_3_3
    • QDataStream.Qt_4_0
    • QDataStream.Qt_4_9
    • QDataStream.Qt_5_0 ~ QDataStream.Qt_5_15
    • QDataStream.Qt_6_0 ~ QDataStream.Qt_6_2
  • 用setFloatingPointPrecision(QDataStream,FloatingPointPrecision)方法设置读写0浮点数的精度,其中参数QDataStream.FloatingPointPrecision 可以取:

    • QDataStream,SinglePrecision
    • QDataStream,DoublePrecision。

    对于版本高于Qt_4_6且精度设置为 DoublePrecision 的点数是 64 位精度

    对于版本高于Qt_4_6且,精度设置为 SinglePrecision 的浮点数是 32 位精度。

  • 用setByteOrder(QDataStream,ByteC)rder)方法设置字节序,参数 QDataStream.ByteOrder 可以取 :

    • QDataStream,BigEndian(大端字节序,默认值)
    • QDataStream.IittleEndian(小端字节序),

    大端字节序的高位字节在前,低位字节在后,小端字节序与此相反。对于十进制数 123,如果用”123”顺序存储是大端字节序,而用”321”顺序存储是小端字节序,二进制与此类似。

  • 用setStatus(QDataStream,Status)方法设置状态,状态的取值与 QTextStream的取值相同。

  • 用skipRawData(len:int)方法可以跳过指定长度的原生字节,返回真实跳过的字节数。

    • 原生数据是机器上存储的二进制数据,需要用户自己解码。
  • 用startTransaction()方法可以记录一个读数据的点

    • 对于顺序设备会在内部复制读取的数据,对于随机设备会保存当前数据流的位置
    • 用commitTransaction()方法确认完成记录一个数据块,当数据流的状态是已经超过末尾时,用该方法会回到数据块的记录点,如果状态是数据有误,则会放弃记录的数据块,
    • 用rollbackTransaction()方法在确认完成记录数据块之前返回到记录点;
    • 用abortTransaction()方法放弃对数据块的记录,并不影响当前读数据的位置
QDataStream的方法及参数类型 说己明
setDevice(QIODevice) 设置设备
setByteOrder(QDataStream.ByteOrder) 设置字节序
byteOrder() 获取字节序 QDataStream.ByteOrder
setFloatingPointPrecision(QDataStream. FloatingPointPrecision) 设置读写浮点数的精度
setStatus(QDataStream. Status) 设置状态
resetStatus()、status() 重置状态、获取状态
setVersion(int) 设置版本号
version() 获取版本号
skipRawData(len:int) 跳过原生数据,返回跳过的字节数量
startTransaction() 开启记录一个数据块起始点
commitTransaction() 完成数据块,成功则返回True
rollbackTransaction() 回到数据块的记录点
abortTransaction() 放弃对数据块的记录
atEnd() 获取是否还有数据可读
整数、浮点数和逻辑值的读写方法

计算机中存储的数据用二进制表示,每个位有0和1两种状态通常用8位作为1个字节,如果这8位全部用来记录数据,则这8位数据的最大值是0b11111111=2-1=255

  • 如要记录正负号,可以用第1位记录,这时用7位记录的最大值是 0b1111111-2-1127。

  • 如果要记录更大的值,用1个字节显然是不够的,这时可以用更多个字节来记录

    • 例如用2个字节(16 位)来记录一个数,如果全部用于记录数据,可以记录的最大值为 216 -1;
    • 如果用1位记录正负号,可以记录的最大值为 215 -1。
  • 因此在读写不同大小的数值时,

    • 要根据数值的大小选择合适的字节数来保存数值,可以分别用1个字节、2个字节4 个字节和8个字节来存储数值,
    • 在读取数值时,要根据写入时指定的字节数来读取,
  • 数据流用于读/写整数、浮点数和逻辑值的方法和数值的范围如表所示。需要特别注意的是,在读数值时,必须按照写人数值时所使用的字节数来读,否则读取的数值不是写人时的数值。

    读/写方法(->表示返回值的类型) 读/写方法说明 读/写取值范围
    readInt8()->int writeInt8(int) 在1个字节上读/写带正负号整数 -2^7 ~ 2^7 -1
    readInt16()-> int writeInt16(int) 在2个字节上读/写带正负号整数 -2^15 ~ 2^15-1
    readInt32()-> int writeInt32(int) 在4个字节上读/写带正负号整数 -2^31 ~ 2^31-1
    readInt64()-> int writeInt64(int) 在8个字节上读/写带正负号整数 -2^63 ~ 2^63-1
    readUInt8()->int writeUInt8(int) 在1个字节上读/写不带正负号整数 0 ~ 2^8 -1
    readUInt16()->int writeUInt16(int) 在2个字节上读/写不带正负号整数 0 ~ 2^16 -1
    readUInt32()->int writeUInt32(int) 在4个字节上读/写不带正负号整数 0 ~ 2^32 -1
    readUInt64()->int writeUInt64(int) 在8个字节上读/写不带正负号整数 0 ~ 2^64 -1
    readFloat()-> float writeFloat(float) 在4个字节上读/写带正负号浮点数 ±3.40282E38(精 确到6位小数)
    readDouble()-> float writeDouble(float) 在8个字节上读/写带正负号浮点数 ±1.79769E308(精 确到15位小数)
    readBo01()->bool writeBo01(bool) 在1个字节上读/写逻辑值
对字符串的读/写方法

数据流用于读/写字符串的方法如表所示。读/写字符串时不需要指定字节数量系统会根据字符串的大小来决定所使用的字节数。

读/写方法(>表示返回值的类型) 读/写方法说明
readQString()-> str writeQString(str) 读/写文本
readQStringList()-> List[str] writeQStringList(Sequence[str]) 读/写文本列表
readString()-> str writeString(str) 读/写文
用QDataStream读写字符串和数值的应用实例

下面的程序是将上一个用QTextStream读写文本数据的程序改用QDataStream来完成读写二进制数据,将数据保存到二进制文件中。程序中用到读写字符串、整数和浮点数的方法。

image-20230311152934231

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 15:00
# File_name: 03-用QDataStream读写字符串和数值的应用实例.py


from PySide6.QtWidgets import QApplication, QMainWindow, QPlainTextEdit, QFileDialog
from PySide6.QtCore import QFile, QDataStream
import sys, math


class MyWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUI() # 界面
self.fileName = "./sin_cos.bin" # 写入的文件

def setupUI(self):
self.plainText = QPlainTextEdit()
self.resize(800, 600)
self.setCentralWidget(self.plainText)

self.status = self.statusBar()
self.menubar = self.menuBar() # 菜单栏

self.file = self.menubar.addMenu("文件") # 文件菜单
action_textCreate = self.file.addAction("生成文件") # 动作
action_textCreate.triggered.connect(self.binCreate_triggered) # 动作与槽的连接

action_textOpen = self.file.addAction("打开文件")
action_textOpen.triggered.connect(self.binOpen_triggered)

self.file.addSeparator()

action_close = self.file.addAction("关闭")
action_close.triggered.connect(self.close)

def binCreate_triggered(self):
file = QFile(self.fileName)
try:
if file.open(QFile.WriteOnly | QFile.Truncate): # 打开文件
writer = QDataStream(file)
writer.setVersion(QDataStream.Qt_6_2)
writer.setByteOrder(QDataStream.ByteOrder.BigEndian)
writer.writeQString("version:Qt_6_2")
writer.writeQString("x(度)")
writer.writeQString("sin(x)")
writer.writeQString("cos(x)")
writer.writeQString("sin(x)+cos(x)")
for i in range(360):
r = i / 180 * math.pi
writer.writeInt16(i)
writer.writeDouble(math.sin(r)) # sin
writer.writeDouble(math.cos(r)) # cos
writer.writeDouble(math.sin(r) + math.cos(r)) # sin + cos

except:
self.status.showMessage("写入文件失败!")

else:
self.status.showMessage("写入文件成功!")

file.close()

def binOpen_triggered(self):
fileName, file = QFileDialog.getOpenFileName(self, caption="打开二进制文件", dir=".", filter="bin(*.bin);;所有文件(*.*)")

file = QFile(fileName)
template = "{:^16}{:^16.10}{:^16.10}{:^16.10}"
try:
if file.open(QFile.ReadOnly): # 打开文件
self.plainText.clear()
reader = QDataStream(file)
reader.setVersion(QDataStream.Version.Qt_6_2)
reader.setByteOrder(QDataStream.ByteOrder.BigEndian)
if reader.readQString() == "version:Qt_6_2":
self.plainText.clear()
str1 = reader.readQString()
str2 = reader.readQString()
str3 = reader.readQString()
str4 = reader.readQString()
string = template.format(str1, str2, str3, str4)

self.plainText.appendPlainText(string)
while not reader.atEnd():
deg = reader.readInt16()
sin = reader.readDouble()
cos = reader.readDouble() # 读取浮点数
sin_cos = reader.readDouble() # 读取浮点数
string = template.format(deg, sin, cos, sin_cos)
self.plainText.appendPlainText(string)

except:
self.status.showMessage("打开文件失败!")
else:
self.status.showMessage("打开文件成功!")

file.close()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

类对象的读写方法

用QDataStream可以将一些常用的类实例写人文件中例如字体颜色、调色板列表项、表格项等。

用writeQVariant(Any)方法可以将 QBrush,QColor,QDateTime QFont.QPixmap、QMargin、QPint、QLine QRect、 QSize、 QTime、 QDate、QDateTime、QListWidgetItem、QTableWidgetItem、QTreeWidgetItem 和其他一些实例对象写人文件中,用readQVariant()方法可以读取这些对象

下面的程序是 writeQVariant()和 readQVariant()方法的使用实例。通过”文件”菜单根据文件的扩展名用QDataStream方式打开或保存二进制文件,用QTextStream方式打开或保存文本文件,可以利用”设置”菜单设置颜色和字体。当保存二进制文件时,用writeQVariant()方法写入调色板和字体;当打开二进制文件时用readQVariant()方法读取调色板和字体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 15:30
# File_name: 04-类对象的读写方法实例.py


from PySide6.QtWidgets import QApplication, QMainWindow, QPlainTextEdit, QFileDialog, QMessageBox, QFontDialog, QColorDialog
from PySide6.QtCore import QFile, QTextStream, QDataStream, QStringConverter
from PySide6.QtGui import QPalette
import sys, os


class MyWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupUI() # 界面

def setupUI(self): # 界面建立
self.plainText = QPlainTextEdit()

self.setCentralWidget(self.plainText)
self.status = self.statusBar()
self.menubar = self.menuBar() # 菜单栏
self.file = self.menubar.addMenu('文件') # 文件菜单

action_new = self.file.addAction("新建")
action_new.triggered.connect(self.plainText.clear)

action_open = self.file.addAction("打开文件") # 动作 打开二进制文件或文本文件
action_open.triggered.connect(self.open_triggered) # 动作与槽的连接

self.action_save = self.file.addAction("保存文件") # 动作,保存二进制文件 或文本文件
self.action_save.triggered.connect(self.save_triggered)
self.action_save.setEnabled(False) # 动作与槽的连接

self.file.addSeparator()

action_close = self.file.addAction("关闭")
action_close.triggered.connect(self.close)

self.setting = self.menubar.addMenu("设置")
action_color = self.setting.addAction("设置颜色")
action_color.triggered.connect(self.color_triggered)

action_font = self.setting.addAction("设置字体")
action_font.triggered.connect(self.font_triggered)

self.plainText.textChanged.connect(self.plainText_textChaneged)

def open_triggered(self):
fileName, file = QFileDialog.getOpenFileName(self, caption="打开二进制文件", dir=".", filter="所有文件(*.*);;二进制文件(*.bin);;文本文件(*.txt);;py文件(*.py)")
if not os.path.isfile(fileName):
return

name, extension = os.path.splitext(fileName) # 获取文件名和扩展名
file = QFile(fileName)
try:
if file.open(QFile.ReadOnly): # 打开文件

if extension == ".bin": # 根据扩展名识别二进制文件
reader = QDataStream(file)
reader.setVersion(QDataStream.Version.Qt_6_2) # 设置版本
reader.setByteOrder(QDataStream.BigEndian)

version = reader.readQString() # 读取版本号
if version != "version:Qt_6_2":
QMessageBox.information(self, "错误", "版本不匹配")
return

palette = reader.readQVariant() # 读取调色板信息
font = reader.readQVariant() # 读取字体信息
self.plainText.setPalette(palette) # 设置调色板
self.plainText.setFont(font) # 设置字体
if not file.atEnd():
string = reader.readQString() # 读取文本
self.plainText.clear()
self.plainText.appendPlainText(string)

if extension == ".txt" or extension == ".py": # 根据扩展名识别tt或py文件
file.setTextModeEnabled(True)
reader = QTextStream(file)
reader.setEncoding(QStringConverter.Utf8)
reader.setAutoDetectUnicode(True)
string = reader.readAll()
self.plainText.clear()
self.plainText.appendPlainText(string) # 读取所有数据

except:
self.status.showMessage("打开文件失败!")
else:
self.status.showMessage("打开文件成功!")

file.close()

def save_triggered(self):
fileName, fil = QFileDialog.getSaveFileName(self, caption="保存文件", dir=".", filter="二进制文件(*.bin);;text(*.txt);;python(*.py);;所有文件(*.*)")
if fileName == "":
return

name, extension = os.path.splitext(fileName) # 获取文件名和扩展名
file = QFile(fileName)

try:
if file.open(QFile.WriteOnly | QFile.Truncate): # 打开文件
if extension == ".bin": # 根据扩展名识别二进制文件
writer = QDataStream(file) # 创建数据流
writer.setVersion(QDataStream.Qt_6_2) # 设微版本
writer.setByteOrder(QDataStream.BigEndian)
writer.writeQString("version:Qt_6_2") # 写人版本
palette = self.plainText.palette()
font = self.plainText.font()
string = self.plainText.toPlainText()

writer.writeQVariant(palette) # 写人调色板
writer.writeQVariant(font) # 写人字体
writer.writeQString(string) # 写人内容

if extension == ".txt" or extension == ".py": # 根据扩展名识别txt 或 py文件
reader = QTextStream(file)
reader.setEncoding(QStringConverter.Utf8)
string = self.plainText.toPlainText()
reader << string # 写人内容

except:
self.status.showMessage("文件保存失败!")
else:
self.status.showMessage("文件保存成功!")

file.close()

def font_triggered(self): # 槽函数,设置字体
font = self.plainText.font()
ok, font = QFontDialog.getFont(font, parent=self, title="选择字体")
if ok:
self.plainText.setFont(font)

def color_triggered(self): # 槽函数, 设置颜色
color = self.plainText.palette().color(QPalette.Text)
colorDialog = QColorDialog(color, parent=self)
if colorDialog.exec():
color = colorDialog.selectedColor()
palette = self.plainText.palette()
palette.setColor(QPalette.Text, color)
self.plainText.setPalette(palette)

def plainText_textChaneged(self): # 槽函数,判断保存动作是否需要激活或失效
if self.plainText.toPlainText() == "":
self.action_save.setEnabled(False)
else:
self.action_save.setEnabled(True)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

临时数据的保存

文件可以用QFile打开并可以读写数据,另外在进行科学计算时,计算过程中产生的中间临时数据可以写到临时文件或缓存中,程序退出时自动删除临时文件和缓存中的数据

临时文件QTemporaryFile

在进行大型科学运算时,通常会产生大量的中间结果数据

  • 例如进行有限元计算时,一个规模巨大的刚度矩阵、质量矩阵和迭代过程中的中间结果会达到几十 GB 或上百 GB甚至更多,如果把这些数据放到内存中通常是放不下的。
    • 需要把这些数据放到临时文件中,并保证临时文件不会覆盖现有的文件,计算过程中读取临时文件中的数据进行运算,计算结束后则自动删除临时文件。

QTemporaryFile类用于创建临时文件它继承自QFile,当用Open()方法打开设备时创建临时文件,并保证临时文件名是唯一的,不会和本机上的文件同名。

用QTemporaryFile创建临时文件对象的方法如下其中templateName是文件名称模板或者不用模板而用指定文件名,parent 是继承自QObject类的实例对象。

模板的文件名中包含6个或6个以上的大写”X”扩展名可以自已指定,例如QTemporaryFile”XXXXXXXXsdb”)QTemporaryFile(“abXXXXXXXXcdsdb”)。

  • 如果没有使用模板而使用具体文件名,则临时文件名是在文件名基础上添加新的扩展名,
  • 如果指定了父对象则用应用程序的名称(用app.setApplicationName(str)设置)再加上新的扩展名作为临时文件名。
  • 如果没有使用模板或指定文件名,则存放临时文件的路径是系统临时路径,可以通过QDir.tempPath()方法获取系统临时路径;
  • 如果使用模板或指定文件名,则存放到当前路径下,当前路径可以用QDir.currentPath()方法查询。
1
2
3
4
5
6
from PySide6.QtCore import QTemporaryFile

QTemporaryFile(self) -> None
QTemporaryFile(parent: PySide6.QtCore.QObject) -> None
QTemporaryFile(templateName: str) -> None
QTemporaryFile(templateName: str, parent: PySide6.QtCore.QObject) -> None

QTemporaryFile 的常用方法如表所示。

  • 创建临时文件对象后,用open()方法打开文件,这时生成临时文件,
  • 临时文件名可以用fileName()方法获取,
  • 临时文件的打开方式是读写模式(QIODeviceBase,ReadWrite)。
  • 打开临时文件后,可以按照前面介绍的写人和读取方法来读写数据。
  • 用setAutoRemove(bool)方法设置临时文件对象销毁后临时文件是否自动删除,默认为 True。
QTemporaryFile的方法及参数类型 返回值的类型 说甲 明
open() bool 创建并打开临时文件
fileName() str 获取临时文件名和路径
setAutoRemove(bool) None 设置是否自动删除临时文件
autoRemove() bool 获取是否自动删除临时文件
setFileTemplate(name:str) None 设置临时文件的模板
file Template() str 获取临时文件的模板

临时路径QTemporaryDir

与创建临时文件类似,也可以创建临时路径,应保证所创建的临时路径不会覆盖本机上的路径,程序退出时自动除临时路径。

创建临时路径的方法如下所示。

  • 其中第一种方法QTemporaryDir()不含模板,这时用应用程序的名称(用app.setApplicationName(str)方法设置)和随机名称作为路径名称,随机路径保存到系统默认的路径(可用DirtempPath()方法查询)下;
  • 第二种方法QTemporaryDir(templateName:str)用模板创建临时路径如果模板中有路径,则是指相对于当前的工作路径,如果模板中含有”XXXXXX”则必须放到路径名称的尾部,”XXXXXX”是临时路径的动态部分。
1
2
3
4
from PySide6.QtCore import QTemporaryDir

QTemporaryDir(self) -> None
QTemporaryDir(templateName: str) -> None

临时文件 QTemporaryDir 的常用方法如表0所示。

  • 用isValid()方法查询临时路径是否创建成功;
  • 如果没有成功,可以用errorString()方法获取出错信息;
  • 用path()方法获取创建的临时路径。
QTemporaryDir的方法及参数类型 返回值的类型 说明
path() Str 获取创建的临时路径
isValid() bool 获取临时路径是否创建成功
errorString() str 如果临时路径创建不成功、获取出错信息
filePath(fileName: str) str 获取临时路径中的文件的路径
setAutoRemove(bool) None 设置是否自动移除临时路径
autoRemove() bool 获取是否自动移除路径
remove() bool 移除临时路径

存盘 QSaveFile

QSaveFile用来保存文本文件和二进制文件,在写入操作失败时不会导致已经存在的数据丢失。

QSaveFile 执行写操作时,会先将内容写人到一个临时文件中,如果没有错误发生,则调用commit()方法来将临时文件中的内容移到目标文件中。

这样能确保目标文件中的数据在写操作发生错误时不会丢失,也不会出现部分写人的情况,一般使用QSaveFile在磁盘上保存整份文档。

QSaveFile 会自动检测写人过程中所出现的错误,并记住所有发生的错误,在调用commit)方法时放弃临时文件。

用QSaveFile创建保存文件的方法如下所示其中name是文件名,parent 是继承自QObiect 的对象

1
2
3
4
5
from PySide6.QtCore import QSaveFile

QSaveFile(name: str) -> None
QSaveFile(name: str, parent: PySide6.QtCore.QObject) -> None
QSaveFile(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

QSaveFile的常用方法如表所示,主要方法介绍如下

  • 用open(flags:QIODeviceBase.OpenMode)方法打开文件,并创建临时文件,如果创建临时文件出错则返回 False。
  • 可以使用QDataStream或QTextStream 进行读写
    • 也可以使用从 QIODevice 继承的read()readLine()write()等方法进行读写
  • QSaveFile不能调用close()函数而是通过调用commit()函数完成数据的保存
    • 如果没有调用commit()函数则QSaveFile对象销时会丢弃临时文件。
  • 当应用程序出错时用cancelWriting()方法可以放弃写入的数据即使又调用了commit(),也不会发生真正保存文件操作。
  • QSaveFile会在目标文件的同一目录下创建一个临时文件,并自动进行重命名。
    • 但如果由于该目录的权限限制不允许创建文件,则调用open()会失败。
    • 为了解决这个问题,即能让用户编辑一个现存的文件,而不创建新文件,可使用setDirectWriteFallback(True)方法,这样在调用open()时就会直接打开目标文件并向其写人数据而不使用临时文件。但是在写人出错时不能使用cancelWriting()方法取消写入。
QSaveFile 的方法 返回值的类型 说明
setFileName(name: str) None 设置保存数据的目标文件
filename() Str 获取目标文件
open(flags: QIODeviceBase. OpenMode) bool 打开文件,成功则返回True
commit() bo0l 从临时文件中将数据写人到目标文件中, 成功则返回True
cancelWriting() None 取消将数据写入到目标文件
selDirectWriteFallback(enabled: bool) None 设置是否直接向目标文件中写数据
directWriteFallback() bool 获取是否直接向目标文件中写数据
writeData(data: bytes,len:int) int 重写该函数,写人字节串,并返回实际写人 的字节串的数量

缓存QBuffer

对于程序中反复使用的一些临时数据,如果将其保存到文件中,则反复读取这些数据要比从缓存读取数据慢得多。

缓存是内存中一段连续的存储空间,QBuffer 提供了可以从缓存读取数据的功能,在多线程之间进行数据传递时选择缓存比较方便。缓存属于共享资源所有线程都能进行访问。

QBuffer和 QFile一样也是一种读写设备它继自QIODevice可以用QIODevice的读写方法从缓存中读写数据也可以与QTextStream和QDataStream结合读写文本数据和二进制数据。

用QBuffer 创建缓存设备的方法如下,其中 parent 是继承自QObject 的实例对象。定义QBuffer需要一个QByterArray对象也可不指定QByteArray;系统会给QBuffer创建一个默认的 QByteArray 对象。

1
2
3
4
from PySide6.QtCore import QBuffer

QBuffer(buf: Union[PySide6.QtCore.QByteArray, bytes], parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QBuffer(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
缓存QBuffer 的常用方法

QBuffer的常用方法如表所示。

  • 默认情况下系统会自动给QBuffer 的实例创建默认的QByteArray对象
  • 可以用buffer()方法或data()方法获取 QByteArray 对象,也可用setBuffer(QByteArray)方法设置缓存。
  • QBuffer 需要用open(QIODeviceBaseOpenMode)方法打开缓存,成功则返回 True,打开后可以读写数据;
  • 用close)方法关闭缓存。
QBufler的方法及参数类型 返回值的类型 说明
setBuffer(Union[QByteArray,bytes]) None 设置缓存
buffer() QByteArray 获取缓存中的QByteArray对象
data() QByteArray 获取 QByteArray,与buffer()功能相同
open(QIODeviceBase.OpenMode) bool 打开缓存,成功则返回True
close() None 关闭缓存
canReadLine() bool 获取是否可以按行读取
setData(data: Union[QByteArray, bytes]) None 给缓存设置 QByteArray 对象
pos() int 获取指向缓存内部指针的位置
seek(off:int) bool 定位到指定的位置,成功则返回True
readData(data: bytes,maxlen:int) object 重写该函数,读取指定的最大数量的字节 数据
writeData(data: bytes,len:int) int 重写该函数,写人数据
atEnd() bool 获取是否到达尾部
size() int 获取缓存中字节的总数
缓存QBuffer的应用实例

下面的程序是将前面往文件中写正弦、余弦数据的程序稍作修改,通过”文件”菜单的牛成数据,将数据写入到缓存中,再通过”文件”菜单的读取数据,将数据从缓存中读取并显示出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 17:09
# File_name: 05-缓存QBuffer的应用实例.py


from PySide6.QtWidgets import QApplication, QMainWindow, QPlainTextEdit
from PySide6.QtCore import QDataStream, QBuffer
import sys, math, struct


class MyWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupuI() # 界面
self.buffer = QBuffer() # 创建缓存

def setupuI(self): # 界面建立
self.plainText = QPlainTextEdit()
self.setCentralWidget(self.plainText)
self.status = self.statusBar()
self.menubar = self.menuBar() # 菜单栏

self.file = self.menubar.addMenu('文件!') # 文件菜单
action_dataCreate = self.file.addAction('生成数据') # 动作
action_dataCreate.triggered.connect(self.dataCreate_triggered) # 动作与槽的连接

action_dataRead = self.file.addAction("读取数据") # 动作
action_dataRead.triggered.connect(self.dataRead_triggered) # 动作与槽的连接

self.file.addSeparator()
action_close = self.file.addAction('关闭')
action_close.triggered.connect(self.close)

def dataCreate_triggered(self):
try:
if self.buffer.open(QBuffer.OpenModeFlag.WriteOnly.WriteOnly | QBuffer.OpenModeFlag.Truncate): # 打开缓存
writer = QDataStream(self.buffer) # 创建数据流
writer.setVersion(QDataStream.Version.Qt_6_2)
writer.setByteOrder(QDataStream.ByteOrder.BigEndian)

writer.writeString("x(度)")
writer.writeString("sin(x)")
writer.writeString("cos(y)")
writer.writeString("sin(x) + cos(x)")

for i in range(360):
r = i / 180 * math.pi
writer.writeInt16(i)
writer.writeDouble(math.sin(r)) # sin
writer.writeDouble(math.cos(r)) # cos
writer.writeDouble(math.sin(r) + math.cos(r)) # sin + cos

except:
self.status.showMessage("写数据失败!")

else:
self.status.showMessage("写数据成功!")

self.buffer.close()

def dataRead_triggered(self):
template = "{:^10}{:^20.13}{:^20.13}{:^20.13}"
try:
if self.buffer.open(QBuffer.OpenModeFlag.ReadOnly): # 打开缓存

reader = QDataStream(self.buffer)
reader.setVersion(QDataStream.Version.Qt_6_2)
reader.setByteOrder(QDataStream.ByteOrder.BigEndian)
self.plainText.clear()
str1 = reader.readQString() # 读取字符串
str2 = reader.readQString() # 读取字符串
str3 = reader.readQString() # 读取字符串
str4 = reader.readQString() # 读取字符串
string = template.format(str1, str2, str3, str4)

self.plainText.appendPlainText(string)
while not reader.atEnd():
deg = reader.readInt16()
sin = reader.readDouble()
cos = reader.readDouble() # 读取浮点数
sin_cos = reader.readDouble() # 读取浮点数
string = template.format(deg, sin, cos, sin_cos)
self.plainText.appendPlainText(string)

except:
self.status.showMessage("读数据失败!")
else:
self.status.showMessage("读数据件成功!")

self.buffer.close()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

文件管理

程序中除了对数据进行读写外,还需要对文件进行管理。进行文件管理可以用Python自带的os模块,也可以用PySide6 提供的文件管理的类

文件信息 QFilelnfo

文件信息 QFileInfo 用于查询文件的信息,如文件的相对路径绝对路径文件大小文件权限文件的创建及修改时间等。

用QFileInfo类创建文件信息对象的方法如下所示,其中str 是需要获取文件信息的文件,QFileInfo(QDir,str)表示用QDir 路下的 str 文件创建文件信息对象

1
2
3
4
5
6
7
from PySide6.QtCore import QFileInfo

QFileInfo(self) -> None
QFileInfo(dir: Union[PySide6.QtCore.QDir, str], file: Union[str, bytes, os.PathLike]) -> None
QFileInfo(file: Union[str, bytes, os.PathLike]) -> None
QFileInfo(file: PySide6.QtCore.QFileDevice) -> None
QFileInfo(fileinfo: PySide6.QtCore.QFileInfo) -> None

QFileInfo的常用方法如表,所示主要方法介绍如下方法重新设置要获取文件信息的文件。

  • 可以在创建QFileInfo 对象时设置要获取文件信息的文件,也可以用
    • setFile(dir:Union[QDir, str], file: str)
    • setFile(file: Union[str, bytes])
    • setFile(file:QFileDevice)
  • QFileInfo 提供了一个 refresh()函数用于重新读取文件信息。
    • 如果想关闭该缓存功能,以确保每次访问文件时都能获取当前最新的信息,可以通过 setCaching(False)方法来完成设置。
  • 用absoluteFilePath()方法获取绝对路径和文件名;
    • 用absolutePath()方法获取绝对路径,不含文件名;
    • 用fileName()方法获取文件名,包括扩展名,不包含路径。
    • 当文件名中有多个.时用suffix()方法取扩展名,不包括.
    • 用completeSuffx()方法获取第 1个.后的文件名,包括扩展名。
  • 用exists()方法获取文件是否存在用exists(str)方法获取指定的文件是否存在
  • 用birthTime()方法获取创建时间QDateTime,如果是快捷文件则返回目标文件的创建时间;
  • 用lastModified()方法获取最后修改时间 QDateTime;
    • 用lastRead()方法获取最后读取时间 QDateTime。
  • 可以用相对于当前的路径来指向一个文件,也可以用绝对路径指向文件。
    • 用isRelative()方法获取是否是相对路径;
    • 用makeAbsolute()方法转换成绝对路径返回值若是 False 则表示已经是绝对路径。
  • 用isFile()方法获取是否是文件,
    • 用isDir()方法获取是否是路径
    • 用isShortcut()方法获取是否是快捷方式(链接),
    • 用isReadable()方法获取文件是否可读,
    • 用isWritable()方法获取文件是否可写。
QFileln[o的方法及参数类型 返回值的类型 说 明
getFile(dir: Union[QDir,sur]lile:str) None 设置需要获取文件信息的文件
setFile(file: Union[str.bytes]) None 设置需要获取文件信息的文件
setFile(file: QFileDevice) None 设置需要获取文件信息的文件
setCaching(bool) None 设置是否需要进行缓存
refresh() None 重新获取文件信息
absoluteDir() QDir 获取绝对路径
absoluteFilePath() Str 获取绝对路径和文件名
absolutePath() Str 获取绝对路径
baseName() Str 获取第1个.之前的文件名
completeBaseName() Str 获取最后1个.前的文件名
suffix() Str 获取扩展名,不包活”.”
completeSufix() Str 获取第1个.后的文件名,含扩展名
fileName() Str 获取文件名,包括扩展名,不含路径
path() Str 获取路径,不含文件名
filePath() Str 获取路径和文件名
canonicalFilePath() Str 获取绝对路径和文件名,路径中不含链接 符号和多余的...
acanonicalPath() Str 获取绝对路径,路径中不含链接符号和多 余的...
birthTime() QDateTime 获取创建时间,如果是快捷文件,则返回目 标文件的创建时间
lastModified() QDaLeTime 获取最后修改日期和时间
lastRead() QDateTime 获取最后读取日期和时间
adir() QDir 获取父类的路径
group() Str 获取文件所在的组
groupId() int 获取文件所在组的ID
isAbsolute() bool 获取是否是绝对路径
isDir() bool 获取是否是路径
isExecutable() bool 获取是否是可执行文件
isFile() bool 获取是否是文件
isHidden() bool 获取是否是隐藏文件
isReadable() bool 获取文件是否可读
isRelative() bool 获取使用的路径是否是相对路径
isRoot() bool 获取是否是根路径
isShorteut() bool 获取是否是快捷方式(链接)
isSymLink() bool 获取是否是连接符号或快捷方式
isSymbolicLink() bool 获取是否是链接符号
isWritable() bool 获取文件是否可写
makeAbsolute() bool 转换成绝对路径、返回False时表示已经是 绝对路径
owner() Str 获取文件的所有者
ownerld() int 获取文件的所有者的ID
size() int 返回按字节计算的文件大小
symLinkTarget() Str 返回被链接文件的绝对路径
[static]exists(file: str) bool 获取指定的文件是否存在
[static]exists() bool 获取文件是否存在

路径管理QDir

路径管理QDir 用于管理路径和文件它的一些功能与QFilenfo的功能相同。

用QDir创建路径管理对象的方法如下,其中:path 是路径;nameFilter 是名称过滤器;sort 是枚举类型QDirSortFlag,指定排序规则;filters 是枚举类型QDirFilter,是属性过滤器

1
2
3
4
5
from PySide6.QtCore import QDir

QDir(arg__1: Union[PySide6.QtCore.QDir, str]) -> None
QDir(path: Union[str, bytes, os.PathLike, NoneType]) -> None
QDir(path: Union[str, bytes, os.PathLike], nameFilter: str, sort: PySide6.QtCore.QDir.SortFlag = Instance(QDir.SortFlags(QDir.SortFlag.Name | QDir.SortFlag.IgnoreCase)), filter: PySide6.QtCore.QDir.Filter = Instance(QDir.Filter.AllEntries)) -> None
路径管理QDir的常用方法

QDir的常用方法如表所示,主要方法介绍如下

  • 可以在创建路径对象时指定路径,也可以用setPath(str)方法指定路径用path()方法获取路径。
  • 在创建路径对象时,指定的过滤器、排序规则用于获取路径下的文件和子路径。
    • 获取路径下的文件和子路径的方法有:
      • entryInfoList(filters,sort)
      • entryInfoList(Sequence[nameFilters], filters, sort)
      • entryList(filters, sort)
      • entryList[str]和entryList(Sequence[nameFilters],filters,sort)
      • 其中属性过滤器 filters 可以取:
        • QDir.Dirs(列出满足条件的路径)
        • QDir,AllDirs(所有路径)QDirFiles(文件)
        • QDir,Drives(驱动器)
        • QDir,NoSymLinks(没有链接文件)
        • QDir.NoDot(没有.)
        • QDir.NoDotDot(没有..)
        • QDir.NoDotAndDotDot
        • QDir.AllEntries(所有路径、文件和驱动器)
        • QDir.Readable
        • QDir.Writable
        • QDir.Executable
        • QDir.Modified
        • QDir.Hidden
        • QDir.System
        • QDir.CaseSensitive(区分大小写),
      • 排序规则 sort 可以取:
        • QDir.Name
        • QDir.Time
        • QDir.Size
        • QDir.Type、
        • QDir.Unsorted
        • QDir.NoSort
        • QDir.DirsFirst
        • QDir.DirsLast
        • QDir.Reversed
        • QDir.IgnoreCase
        • QDir.LocaleAware。
      • 名称过滤器、属性过滤器和排序规则也可以分别用setNameFilters(Sequence[str])、setFilter(QDir, Filter)和 setSorting(QDir.SortFlag)方法设置
  • 用setCurrent(str)方法设置应用程序当前的工作路径
    • 用currentPath()方法获取应用程序的当前绝对工作路径。
  • 用mkdir(str)方法创建子路径;
    • 用mkpath(str)方法创建多级路径;
    • 用rmdir(str)方法移除子路径,
    • 在路径为空的情况下,用rmpath(str)方法移除多级路径
QDir的方法及参数类型 返回值的类型 说 明
setPath(path: Union[str, bytes]) None 设置路径
path() Str 获取路径
absoluteFilePath(fileName:str) StI 获取文件的绝对路径
absolutePath() str 获取绝对路径
canonicalPath() Str 获取不含...的路径
cd(dirName: str) bool 更改路径,如果路径存在则返回True
cdUp() bool 从当前工作路径上移一级路径,如果新路 径存在则返回 True
[static]cleanPath(path) Str 返回移除多余符号后的路径
count() int 获取文件和路径的数量
dirName() Str 获取最后一级的目录或文件名
[static]drives() List[QFileInfo] 获取根文件信息列表
setNameFilters(Sequence[str]) None 设置 entryList()、entryInfoList()使用的名 称过滤器,可用”*”和”?”通配符
setFilter(QDir.Filter) None 设置属性过滤器
setSorting(QDir.SortFlag) None 设置排序规则
[static]setSearchPaths(prefix: str, searchPaths:Sequence[str]) None 设置搜索路径
entryInfoList(filters: QDir.Filters = QDir.NoFilter, sort:QDir.SortFlags= QDir.NoSort) List[QFileInfo] 根据过滤器和排序规则,获取路径下的所有文件信息和子路径信息
entryInfoList(Sequence[nameFilters], filters,sort) List[QFileInfo] 根据过滤器和排序规则,获取路径下的所有文件信息和子路径信息
entryList(filters,sort) List[str] 根据过滤器和排序规则,获取路径下的所有文件信息和子路径信息
entryList(Sequence[nameFilters],filters,sort) List[str] 根据过滤器和排序规则,获取路径下的所有文件信息和子路径信息
exists() bool 判断路径或文件是否存在
exists(name:str) bool 判断路径或文件是否存在
[static]home() QDir 获取系统的用户路径
[static]homePath() str 获取系统的用户路径
[static]isAbsolute() bo0l 获取是否是绝对路径
[static]isAbsolutePath(path: str) bool 获取指定的路径是否是绝对路径
isRelative() bool 获取是否是相对路径
[static]isRelativePath(path:str) bool 获取指定的路径是否是相对路径
isRoot() bool 获取是否是根路径
isEmpty(filters= QDir.NoDotAndDotDot) bool 获取路径是否为空
isReadable() bool 获取文件是否可读
[static]listSeparator() str 获取多个路径之间的分隔符,Windows 系统是”;”,UNIX系统是”:”
makeAbsolute() bool 转换到绝对路径
mkdir(str) bool 创建子路径,路径如已存在,则返回 False
mkpath(str) bool 创建多级路径,成功则返回True
refresh() None 重新获取路径信息
relativeFilePath(fileName;str) Str 获取相对路径
remove(fileName:str) bool 移除文件,成功则返回True
removeRecursively() bool 移除路径和路径下的文件、子路径
rename(oldName: str,newName: str) bool 重命名文件或路径,成功则返回True
rmdir(dirName;str) bool 移除路径,成功则返回True
rmpath(dirPath:str) bool 移除路径和空的父路径,成功则返回True
[static]root() QDir 获取根路径
[static]rootPath() str 获取根路径
[static]separator() str 获取路径分隔符
[static]setCurrent(str) bool 设置程序当前工作路径
[static]current() QDir 获取程序工作路径
[static]currentPath() str 获取程序当前绝对工作路径
[static]temp() QDir 获取系统临时路径
[static]tempPath() str 获取系统临时路径
[static]fromNativeSeparators(pathName str) str 获取用”/“分割的路径
[static]toNativeSeparators(pathName: str) str 转换成用本机系统使用的分隔符分割的 路径
路径管理Dir的应用实例

下面的程序,单击”文件”菜单下的选择路径,从路径选择对话框中选择一个路径后,将列出该路径下所有文件的文件名、文件大小创建日期和修改日期信息。

image-20230311175325911

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 17:39
# File_name: 06-路径管理Dir的应用实例.py


from PySide6.QtWidgets import QApplication, QMainWindow, QPlainTextEdit, QFileDialog
from PySide6.QtCore import QDir
import sys


class MyWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
self.setupUI() # 界面

def setupUI(self): # 界面建立
self.plainText = QPlainTextEdit()
self.setCentralWidget(self.plainText)
self.status = self.statusBar()
self.menubar = self.menuBar() # 菜单栏

self.file = self.menubar.addMenu('文件') # 文件菜单
action_dir = self.file.addAction('选择路径') # 动作
action_dir.triggered.connect(self.action_dir_triggered)

self.file.addSeparator()

action_close = self.file.addAction('关闭')
action_close.triggered.connect(self.close)

def action_dir_triggered(self):
path = QFileDialog.getExistingDirectory(self, caption="选择路径")
dir = QDir(path)
dir.setFilter(QDir.Files) # 只显示文件
if dir.exists(path):
template = "文件名:{} 文件大小:{}字节 创建日:{} 修改日期:{}"
fileInfo_list = dir.entryInfoList() # 获取文件信息列表
n = len(fileInfo_list) # 文件数量
if n: # 如果路径下有文件
self.status.showMessage("选择的路径是:" + dir.toNativeSeparators(path) + "该路径下有" + str(n) + "个文件")
self.plainText.clear()
self.plainText.appendPlainText(dir.toNativeSeparators(path) + "下的文件如下:")
for info in fileInfo_list:
string = template.format(info.fileName(), info.size(), info.birthTime().toString(), info.lastModified().toString())
self.plainText.appendPlainText(string)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

文件和路径监视器QFileSystemWatcher

QFileSystemWatcher 是文件和路径监视器当被监视的文件或路径发生修改、添加和删除等变化时会发送相应的信号,被监视的文件和路径一般不超过 256 个。

用QFileSystemWatcher定义文件监视器对象的方法如下所示,其中 parent是继承自QObject类的实例对象;Sequence[str]是字符串列表,是被监视的文件或路径

1
2
3
4
from PySide6.QtCore import QFileSystemWatcher

QFileSystemWatcher(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QFileSystemWatcher(paths: Sequence[str], parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

QFileSystemWatcher 的方法如表 所示。

  • 用addPath(file:str)方法或 addPaths(files:Seguence[str])方法添加被监视的路径或文件;
  • 用removePath(file:str)方法或removePaths(files:Sequence[str])方法移除被监视的文件或路径;
  • 用directories()方法获取被监视的路径列表;
  • 用files()方法获取被监视的文件列表。当被监视的路径发生改变(增加和删除文件及路径)或文件发生改变(修改、重命名、删除)时,会分别发送directoryChanged(path)信号和 fileChanged(fileName)信号。
QFileSystemWatcher的方法 返回值的类型 说明
addPath(file:str) bool 添加被监视的路径或文件,成功则返回True
addPaths(files: Sequence[str]) ListEstr] 添加被监视的路径或文件列表,返回没有添加 成功的路径和文件列表
directories() List[str] 获取被监视的路径列表
files() List[str] 获取被监视的文件列表
removePath(file:str) bool 将被监视的路径或文件从监视中移除,成功则 返回 True
removePaths(files:Sequence[str]) List[str] 移除被监视的路径或文件列表,返回没有移除 成功的路径和文件列表

绘制二维图表

如果文件中存在大量的数据,若直接观察,很难发现数据的规律,而且也不方便,可以将数据绘制成图表的形式以方便分析。

PySide6 可以绘制二维图表和三维图表PySide6的PyCharts模块提供绘制二维图表的控件和数据序列,可以绘制折线图样条曲线图散点图、面积图饼图条形图蜡烛图、箱线图和极坐标图。

图表视图控件和图表

图表由数据序列、坐标轴和图例构成,数据序列提供图表曲线上的数据。

要正确绘制出图表,首先需要创建出能容纳和管理图表的控件,图表可以放到 QGraphicsView 上也可以放到专门的图表视图控件 QChartView 上。

图表视图控件QChartView

QChartView控件是图表QChart 的容器控件,需要将图表对象放到QChartView 控件中以显示图表。

图表视图控件 QChartView 继承自视图控件 QGraphicsView。

用QChartView类创建图表视图控件的方法如下所示其中parent 是继承自QWidget的对象,chart 是继承自QChart 的实例对象。

1
2
3
4
from PySide6.QtCharts import QChartView

QChartView(chart: PySide6.QtCharts.QChart.parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None
QChartView(parent: Union[PySide6.QtWidgets.QWidget, NoneType]= None) -> None

图表视图控件的方法比较少,

  • 用setChart(QChart)方法设置图表;
  • 用chart()方法获取图表QChart;
  • 用setRubberBand(rubberBands:QChartView.RubberBands)方法设置光标
  • 在图表视图控件上拖动时选择框的类型,参数 rubberBands 是 QChartView.RubberBands枚举类型,可取:
    • QChartView.NoRubberBand(无选择)
    • QChartView.VerticalRubberBand(竖向选择框)
    • QChartView.HorizontalRubberBand(水平选择框)
    • QChartView.RectangleRubberBand(矩形选择框);
  • 用setRubberBandSelectionMode(Qt.ItemSelectionMode)方法设置选择模式,参数Q.ItemSelectionMode 可以取:
    • Qt.ContainsItemShape(完全包含形状时被选中)
    • Qt.IntersectsItemShape(与形状交叉时被选中)
    • Qt.ContainsItemBoundingRect(完全包含边界形时被选中)
    • Qt.IntersectsltemBoundingRect(与边界矩形交叉时被选中)

图表QChart

QChart 是图表类,它继承自 QGraphicsWidget。

一个图表一般包含数据序列、坐标轴图表标题和图例。

用QChart 类创建图表的方法如下所示,其中

  • parent 是继承自QGraphicsItem 的实例,
  • type 是 QChart;
  • ChartType 的举类型可以取
    • QChart.ChartTypeUndefined(类型未定义)
    • QChart.ChartTypeCartesian(直角坐标)
    • QChart.ChartTypePolar(极坐标)
1
2
3
4
from PySide6.QtCharts import QChart

QChart(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None, wFlags: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None
QChart(type: PySide6.QtCharts.QChart.ChartType, parent: PySide6.QtWidgets.QGraphicsItem, wFlags: PySide6.QtCore.Qt.WindowType) -> None
图表QChart的常用方法

图表的常用方法如表所示,主要是如何设置数据序列和坐标轴,主要方法介绍如下

  • 用addSeries(series;QAbstractSeries)方法添加数据序列,

    • 用removeAl1Series()方法移除所有数据序列,
    • 用removeSeries(series;QAbstractSeries)方法移除指定的数据序列。
  • 分别用以下方法设置数据序列的X轴和Y轴,同时也起到坐标轴与数据序列关联的作用;也可用createDefaultAxes()方法创建默认的坐标轴。

    • setAxisX(axis:QAbstractAxis,series: QAbstractSeries= None)
    • setAxisY(axis:QAbstractAxis,series: QAbstractSeries=None)
    • 用removeAxis(axis:QAbstractAxis)方法移除指定的坐标轴。
  • 用setTheme(theme:QChart.ChartTheme)方法设置主题,主题是图表字体颜色画刷钢笔和坐标轴等的组合方案,参数可取以下值,值分别对应0~7。

    • QChart.ChartThemeLight 浅色主题,这是默认主题。
    • QChart.ChartThemeBlueCerulean 蔚蓝主题。
    • QChart.ChartThemeDark 黑暗主题。
    • QChart.ThemeBrownSand 沙褐色主题。
    • QChart.ChartThemeBlueNcs 自然色系统(NCS) 蓝色主题。
    • QChart.ChartThemeHighContrast 高对比度主题。
    • QChart.ChartThemeBluelcy 冰蓝色主题。
    • QChart.ChartThemeQt Qt主题。
  • 用setAnimationOptions(QChart.AnimationOptions)方法可以设置坐标轴和数据序列的动画效果,参数可取:

    • QChart.NoAnimation(没有动画效果)
    • QChart.GridAxisAnimations(坐标轴有动画效果)
    • QChart.SeriesAnimations(数据序列有动画效果)
    • QChart.AllAnimations(全部有动画效果);
    • 用setAnimationDuration(msecs:int)方法设置动画的持续时间,单位是毫秒。
  • 用setTitle(title:str)方法设置图表的标题;

    • 用setTitleFont(font:Union[QFont,str,Sequence[str])方法设置标题的字体
    • 用setTitleBrush(QBrush)方法设置标题的画刷。
QChart 的方法及参数类型 说明
addSeries(series: QAbstractSeries) 添加数据序列
removeAllSeries() 移除所有的数据序列
removeSeries(series:QAbstractSeries) 移除指定的数据序列
setAxisX(axis:QAbstractAxis, series:QAbstractSeries = None) 设置X轴
axisX(series:QAbstractSeries=None) 获取X轴 QAbstractAxis
setAxisY(axis:QAbstractAxis,series:QAbstractSeries= None) 设置Y轴
axisY(series:QAbstractSeries=None) 获取Y轴QAbstractAxis
addAxis(axis: QAbstractAxis,alignment:Qt.Alignment) 添加坐标轴
createDefaultAxes() 创建默认的坐标轴
axes(orientation = Qt.Horizontal | Qt.Vertical, series = None) 获取坐标轴列表List[QAbstractAxis]
removeAxis(axis:QAbstractAxis) 移除指定的坐标轴
scroll(dx:float,dy: float) 沿着X和Y方向移动指定距离
setAnimationOptions(QChart.AnimationOptions) 设置动画选项
setAnimationDuration(msecs:int) 设置动画显示持续时间(毫秒)
setBackgroundBrush(brush:Union[QBrush,Qt.BrushStyle, Qt.GlobalColor,QColor,QGradient,QImage.QPixmap]) 设置背景画刷
setBackgroundPen(pen:Union[QPen,Qt.PenStyle.QColor]) 设置背景钢笔
setBackgroundRoundness(diameter: float) 设置背景4个角处的圆的直径
setBackgroundVisible(visible:bool=True) 设置背景是否可见
isBackgroundVisible() 获取背景是否可见
setDropShadowEnabled(enabled: bool=True) 设置背景阴影效果
isDropShadowEnabled() 获取是否有阴影效果
setMargins(margins:QMargins) 设置页边距
setPlotArea(rect:Union[QRectF:QRect]) 设置绘图区域
setPlotAreaBackgroundBrush(QBrush) 设置绘图区域的背景画刷
setPlotAreaBackgroundPen(pen:Union[QPen,QColor]) 设置绘图区域的背景钢笔
setPlotAreaBackgroundVisible(visible:bool=True) 设置绘图区域背景是否可见
isPlotAreaBackgroundVisible() 获取绘图区域背景是否可见
setTheme(theme: QChart. ChartTheme) 设置主题
theme() 获取主题
setTitle(title: str) 设置标题
title() 获取标题
setTitleBrush(QBrush) 设置标题的画刷
setTitleFont(font: Union[QFont, str.Sequence[str]]) 设置标题的字体
legend() 获取图例QLegend
plotArea() 获取绘图区域QRectF
zoom(factor:float) 按照指定的缩放值进行缩放
zoomIn() 按照缩放值2进行缩小
zoomIn(rect: Union[QRectF,QRect]) 缩放图表使指定区域可见
zoomOut() 按照缩放值2进行放大
isZoomed() 获取是否进行过缩放
zoomReset() 重置缩放
QChart 信号

QChart 只有一个信号 plotAreaChanged(plotArea: QRectF),当绘图范围发生改变时发送信号。

数据序列

图表QChart中显示的数据曲线的值和数据曲线的类型由数据序列来定义

QtCharts模块中的数据序列都继承自QAbstractSeries。QAbstractSeries 及其子类之间的继承关系如图所示。

image-20230311203725514

数据序列抽象类QAbstractSeries

QAbstractSeries类是所有数据序列的基类它的方法和信号也会被其子类所继承

QAbstractSeries 的常用方法
  • 要正确显示数据序列曲线,需要将数据序列与坐标轴关联。将数据序列和坐标轴加入到图表中后,有两种方法可以实现数据序列与坐标轴的关联:
    • ==此方法新版已废弃==一种方法是用QChart 的setAxisX(axis:QAbstractAxis,seriesQAbstractSeries = None)方法和 setAxisY(axis: QAbstractAxis, series:QAbstractSeries =None)方法;
    • 另一种方法是用数据序列的 addAxis(axis: PySide6.QtCharts.QAbstractAxis, alignment: PySide6.QtCore.Qt.AlignmentFlag)方法将数据序列与坐标轴关联
      • 用detachAxis(axis:QAbstractAxis)方法断开与坐标轴的关联。
  • 另外用数据序列的 setName(str)方法设置数据序列在图例中的名称;
  • 如果使用将把数据序列显示在透明的QOpenGLWidget 控件上用setUseOpenGL(enable=True)方法设置是否用OpenGL 加速显示。
QAbstractSeries的方法及参数类型 返回值的类型 说明
attachAxis(axis:QAbstractAxis) bool 关联坐标轴,成功则返回True
attachedAxes() List[QAbstractAxis] 获取关联的坐标轴列表
detachAxis(axis; QAbstractAxis) bool 断开与坐标轴的关联
setName(name:str) None 设置数据序列在图列中的名称
name() Str 获取数据序列在图列中的名称
setUseOpenGL(enable:bool=True) None 设置是否使用OpenGL加速显示
useOpenGL() bool 获取是否使用OpenGL加速显示
setOpacity(opacity:float) None 设置不透明度;范围是0.0~1.0
opacity() float 获取不透明度
setVisible(visible:bool=True) None 设置是否可见
isVisible() bool 获取数据序列是否可见
hide() None 隐藏数据序列
show() None 显示数据序列
chart() QChart 获取数据序列所在的图表
QAbstractSeries 的信号

QAbstractSeries 的信号有

  • nameChanged()(当在图例中的名称改变时发送该信号)
  • opacityChanged()(当不透明度发生改变时发送该信号)
  • useOpenGLChanged()和visibleChanged()。

XY图

XY 图由横坐标X 数据和纵坐标 Y 数据构成,包括折线图样条曲线图和散点图。XY所需的数据序列都继承自QXYSeries。

QXYSeries是QAbstractSeries 的派生类之一,主要实现以二维数据点作为数据源,坐标类型为二维坐标系的图表,包括折线图(QLineSeries)、样条曲线图(QSplineSeries)和散点图(QScatterSeries)。

QXYSeries 提供对数据源进行增替换操作的方法和信号,同时内部实现了控制数据点在坐标系上的显示形态(数据点标签的格式、颜色、是否显示等)的功能。

用QLineSeries、QSplineSeries 和 QScatterSeries 类创建数据序列的方法如下所示

1
2
3
4
5
from PySide6.QtCharts import QLineSeries, QSplineSeries, QScatterSeries

QLineSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QSplineSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QScatterSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QXYSeries 数据序列
QXYSeries 数据序列的方法

QXYSeries 数据序列需要由其继承者来实现绘图。

QXYSeries 为 QLineSeries、QSplineSeries和 QScatterSeries 提供了一些的共同方法和信号,常用方法如表所示,主要方法介绍如下。

  • 用append(point: Union[QPointF,QPoint]),append(points: Sequence[QPointF])和append(x:float,y:float)方法可以添加数据点;

    • 用insert(index:int,point:Union[QPointF,QPoint])方法可以根据索引插人数据点;
  • 用remove(index:int)方法根据索引移除数据点;

    • 用remove(point:Union[QPointF,QPoint])或 remove(x:float;y: float)方法根据数据点的坐标移除数据点;
    • 用removePoints(index:int,count:int)方法根据索引和数量移除多个数据点;用clear()方法可以清除所有数据点。
  • 用at(index:int)方法根据索引获取数据点 QPointF,用points()方法获取所有数据点构成的列表 List[QPointF]。

  • 用setPointLabelsVisible(visible: bool=Tue)方法设置数据点的标签是否可见这里的标签是指数据点的X和Y的值;

    • 用setPointLabelsFormat(format:str)方法设置数据点标签的格式,
      • 格式中用@xPoint@yPoint 表示X和Y值的占位符,
        • 例如setPointLabelsFormat(‘(值: @xPoint, Y值: @yPoint)’)
    • 用setPointLabelsClipping(enabled;bool-True)方法设置数据点的标签超过绘图区域时被裁剪。
  • 根据数据序列上的数据点,可以用最小二乘法计算出一个逼近直线,该直线称为“best fit line”

    • 可以分别用以下方法设置该逼近直线是否可见直线的颜色和绘图钢笔
    • setBestFitLineVisible(visible: bool= True)
    • setBestFitLineColor(color: Union[QColor,str])
    • setBestFitLinePen(pen:Union[QPen,QColor])
QXYSeries的方法及参数类型 说 明
append(point:Union[QPointF,QPoint]) 添加数据点
append(points:Sequence[QPointF]) 添加数据点
append(x: float,y: float) 添加数据点
insert(index: int, point: Union[QPointF, QPoint]) 根据索引插入数据点
at(index:int) 根据索引获取数据点QPointF
points() 获取数据点列表ListLQPointF]
remove(index: int) 根据索引移除数据点
remove(point: Union[QPointF,QPoint]) 移除数据点
remove(x:float,y:float) 移除数据点
removePoints(index: int,count:int) 根据索引移除指定数量的数据点
clear() 清空所有数据点
replace(index: int,newPoint:Union[QPointF, .QPoint]) 很据索引替换数据点
replace(index: int,newX:float,newY:float) 根据索引替换数据点
replace(oldPoint: Union[QPointF,QPoint], newPoint:Union[QPointF,QPoint]) 用新数据点替换旧数据点 .
replace(oldX: float,oldY: float, newX: float, newY:float) 用新坐标点替换旧坐标点
replace(points: Sequence[QPointFJ) 用多个数据点替换当前点 .
count() 获取数据点的数量
setBrush(QBrush) 设置画刷
setColor(QColor) 设置颜色
setPen(QPen) 设置钢笔
setPointsVisible(visible:bool=True) 设置数据点是否可见
setPointLabelsVisible(visible; bool=True) 设置数据点标签是否可见
setPointLabelsFormat(format: str) 设置数据点标签的格式
setPointLabelsClipping(enabled: bool=True) 设置数据点标签超过绘图区域时被裁剪
setPointLabelsColor(QColor) 设置数据点标签的颜色
setPointLabelsFont(QFont) 设置数据点标签的字体
setPointSelected(index:int,selected:bool) 根据索引设置某个点是否被选中
setMarkerSize(size:float) 设置标志的尺寸,默认值是15.0
setLightMarker(lightMarker: Union[QImage, str]) 设置灯光标志 动西己
selectAllPoints() 选择所有点
selectPoint(index:int) 根据索引选择一点
selectPoints(indexes: Sequence[int]) 根据索引选择多个点
selectedPoints() 获取选中的点的索引列表 List[int]
setSelectedColor(Union[QColor,Qt.GlobalColor, str]) 设置选中的点的颜色
toggleSelection(indexes:Sequence[int]) 将索引列表中的点切换选中状态
sizeBy(sourceData: Sequence[float], minSize: float,maxSize:float) 根据sourceData值,设置点的尺寸,尺寸在最小值和 最大值之间映射
setBestFitLineVisible(visible: bool=True) 设置通近直线是否可见
setBestFitLineColor(color;Union[QColor,str]) 设置通近直线的颜色
setBestFitLinePen(pen:Union[QPen,QColor]) 设置逼近直线的绘图钢笔
QXYSeries 数据序列的信号

QXYSeries 数据序列的信号如表所示:

QXYSeries的信号及参数类型 说 明
clicked(QPointF) 单击时发送信号
pressed(QPointF) 按下鼠标按时发送信号
released(QPointF) 释放鼠标按键时发送信号
doubleClicked(QPointF) 双击时发送信号
colorChanged(QColor) 颜色改变时发送信号
hovered(point: QPointF,state: bool) 光标悬停或移开时发送信号,悬停时 state是True,移开时 state 是 False
penChanged(QPen) 钢笔改变时发送信号
pointAdded(index:int) 添加点时发送信号
pointLabelsClippingChanged(bool) 数据点标签裁剪状态改变时发送信号
pointLabelsColorChanged(QColor) 数据点标签颜色改变时发送信号
pointLabelsFontChanged(QFontF) 数据点标签字体改变时发送信号
pointLabelsFormatChanged(QFormatF) 数据点标签格式改变时发送信号
pointLabelsVisibilityChanged(bool) 数据点标签可见性改变时发送信号
pointRemoved(index:int) 移除数据点时发送信号
pointReplaced(index:int) 替换数据点时发送信号
pointsRemoved(index:int,count:int) 移除指定数量的数据点时发送信号
pointsReplaced() 替换多个数据点时发送信号
lightMarkerChanged(QImage) 灯光标志发生改变时发送信号
markerSizeChanged(size:float) 标志的尺寸发生改变时发送信号
selectedColorChanged(QColor) 选中的点的颜色发生改变时发送信号
bestFitLineVisibilityChanged(bool) 逼近线的可见性发生改变时发送信号
bestFitLineColorChanged(QColor) 逼近线的颜色发生改变时发送信号
散点图QScatterSeries 数据序列
散点图QScatterSeries 数据序列的方法

QLineSeries和 QSplineSeries 并没有自已特有的方法和信号,只有从QXYSeries 继承的方法和信号。

下面对QScatterSeries 的方法和信号进行介绍。

QScatterSeries 的常用方法中,

  • 用setMarkerShape(QScatterSeries.MarkerShape)方法设置散点标志的形状,其参数可取以下值,对应值分别是0~5:
    • QScatterSeries.MarkerShapeCircle(默认值)
    • QScatterSeries.MarkerShapeRectangle
    • QScatterSeries.MarkerShapeRotatedRectangle
    • QScatterSeries.MarkerShapeTriangle
    • QScatterSeries.MarkerShapeStar
    • QScatterSeries.MarkerShapePentagon
  • 用setMarkerSize(float)方法设置散点标志的尺寸;
  • 用setBorderColor(QColor)方法设置边界颜色。
散点图QScatterSeries 数据序列的信号

QLineSeries和 QSplineSeries 并没有自已特有的方法和信号,只有从QXYSeries 继承的方法和信号。

QScatterSeries 的信号有

  • borderColorChanged(QColor)
  • colorChanged(QColor)
  • markerSizeChanged(float)
  • markerShapeChanged(QScatterSeries.MarkerShape shape)
QLineSeries、QSplineSeries 和 QScatterSeries 的应用实例

下面的程序用“文件”菜单打开 test_data,txt 文件,显示读入的数据,并用折线图样条曲线图和散点图绘制数据曲线,其中折线图和样条曲线图使用相同的数据。程序运行结果如图8-2所示。

image-20230311213805909

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 21:02
# File_name: 01-QLineSeries、QSplineSeries 和 QScatterSeries 的应用实例.py


from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QMenuBar, QFileDialog, QPlainTextEdit
import sys
from PySide6.QtCore import QFile
from PySide6.QtCharts import QChartView, QChart, QLineSeries, QSplineSeries, QScatterSeries


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUi()

def setupUi(self):
menuBar = QMenuBar()
fileMenu = menuBar.addMenu("文件(E)")
fileMenu.addAction("打开(&0)").triggered.connect(self.action_open_triggered)
fileMenu.addSeparator()
fileMenu.addAction("退出(E)").triggered.connect(self.close)
self.plainText = QPlainTextEdit()
chartView = QChartView()

v = QVBoxLayout(self)
v.addWidget(menuBar)
v.addWidget(chartView)
v.addWidget(self.plainText)
self.chart = QChart()
chartView.setChart(self.chart)

def action_open_triggered(self):
fileName, fil = QFileDialog.getOpenFileName(self, "打开测试文件", ".", "文本文件(*.txt)")
file = QFile(fileName)
data = list()
if file.exists():
file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text)

self.plainText.clear()
try:
while not file.atEnd():
string = file.readLine() # 按行读取
string = str(string, encoding="utf-8").strip() # 转成字符中
self.plainText.appendPlainText(string)
temp = list()
for i in string.split():
temp.append(float(i))
data.append(temp) # 转成浮点数, 并添加数据
self.chart.removeAllSeries() # 移除现有曲线
self.plot(data) # 调用函数,绘制曲线

except:
self.plainText.appendPlainText("打开文件出错")

finally:
file.close()

def plot(self, data): # 绘制图表的函数
lineSeries = QLineSeries() # 创建折线数据序列
splineSeries = QSplineSeries() # 创建样条数据序列
scatterSeries = QScatterSeries() # 创建散点数据序列
lineSeries.setName("折线图")
splineSeries.setName("样条曲线图")
scatterSeries.setName("散点图")

scatterSeries.setMarkerShape(QScatterSeries.MarkerShape.MarkerShapeStar)
scatterSeries.setBestFitLineVisible(True) # 逼近线
for i in data:
lineSeries.append(i[0], i[0]) # 添加数据
splineSeries.append(i[0], i[1]) # 添加数据
scatterSeries.append(i[0], i[2]) # 添加数据

self.chart.addSeries(lineSeries) # 图表中添加数据序列
self.chart.addSeries(splineSeries) # 图表中添加数据序列
self.chart.addSeries(scatterSeries) # 图表中添加数据序列
self.chart.createDefaultAxes() # 创建坐标轴


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

面积图

面积图QAreaSeries 一般由上下两个折线数据序列 QLineSeries 构成在上下两个折线之间填充颜色;

也可以只有上折线数据序列,把轴当成下折线数据序列。

面积图的数据序列是QAreaSeries,用QAreaSeries 类创建面积数据序列的方法如下所示,其中 parent是继承自 QObject 的实例对象,upperSeries 和 lowerSeries 分别是上下两个折线序列。

1
2
3
4
from PySide6.QtCharts import QAreaSeries

QAreaSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QAreaSeries(upperSeries: PySide6.QtCharts.QLineSeries, lowerSeries: Union[PySide6.QtCharts.QLineSeries, NoneType]= None) -> None
面积图QAreaSeries 的方法

面积图 QAreaSeries 的常用方法如表所示

主要方法是用setUpperSeriesQLineSeries)方法和 setLowerSeries(QLineSeries)方法分别设置面积数据序列的上下两个数据序列

QAreaSeries的方法及参数类型 说 明
setUpperSeries(QLineSeries) 设置上数据序列
upperSeries() 获取上数据序列
setLowerSeries(QLineSeries) 设置下数据序列
lowerSeries() 获取下数据序列
setBorderColor(QColor) 设置边框颜色
setBrush(QBrush) 设查画刷
setColor(QColor) 设置填充颜色
setPen(QPen) 设置钢笔
setPointLabelsClipping(enabled=True) 设置数据点的标签超过绘图区域时被裁剪
setPointLabelsColor(QColor) 设置标签颜色
setPointLLabelsFont(QFont) 设置标签字体
setPointLabelsFormat(str) 设置标签格式
setPointLabelsVisible(visible=True) 设置标签是否可见
pointLabelsVisible() 获取标签是否可见
setPointsVisible(visible=True) 设置数据点是否可见
面积图QAreaSeries 的信号

面积图QAreaSeries 的信号如表所示

QAreaSeries的信号及参数类型 说 明
clicked(QPointF) 单击时发送信号
pressed(QPointF) 按下鼠标按键时发送信号
released(QPointF) 释放鼠标按键时发送信号
doubleClickecl(QPointF) 双击时发送信号
hovered(point:QPointF,state:bool) 光标悬停或移开时发送信号,悬停时 state 是True,移开时 state 是False
colorChanged(QColor) 颜色发生改变时发送信号
borderColorChanged(QColor) 当边框颜色发生变化时发送信号
pointLabelsClippingChanged(bool) 数据点标签裁剪状态发生改变时发送信号
pointLLabelsColorChanged(QColor) 微据点标签颜色发生改变时发送信号
pointL.abelsFontChanged(QFont) 数据点标签字体发生改变时发送信号
pointLabelsFormatChanged(str) 数据点标签格式发生改变时发送信号
pointLabelsVisibilityChanged(bool) 数据点标签可见性发生改变时发送信号

饼图

饼图是把一个圆分成多个扇形,每个扇形是一个切片,每个切片赋予一个值,每个切片的大小与其值在所有切片总值中的百分比成正比;如果在圆中心添加圆孔,将会成为圆环图。

饼图的数据序列是QPieSeries,每个切片需要用QPieSlice 来定义。

用QPieSeries 和QPieSlice分别定义饼图数据序列和饼图切片的方法如下所示,其中 label是切片的标签文字,value 是切片的值,切片的大小由切片值之间的相对值决定。

1
2
3
4
5
from PySide6.QtCharts import QPieSeries, QPieSlice

QPieSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QPieSlice(label: str, value: float, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QPieSlice(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
饼图数据序列 QPieSeries 的方法

QPieSeries 的常用方法如表所示,主要方法介绍如下

  • 用append(QPieSlice)方法添加切片;

    • 用append(Sequence[QPieSlice])添加多个切片;
    • 用append(label:str,value: float)方法添加一个全新的切片,并返回该切片
  • 用insert(index:int,slice:QPieSlice)方法根据索引插入切片;

  • 用count()方法获取切片的数量;

    • 用slices()方法获取切片列表;
  • 用remove(QPieSlice)方法移除并删除切片;

    • 用clear()方法删除所有切片。
  • 用setHoleSize(holeSize:float)方法设置饼图中心的圆,参数的取值范围是0~1,是相对于饼图所在的矩形尺寸,默认为0。

    • 参数如果不是0,则饼图成为圆环图
  • 用setPieSize(relativeSize: float)方法设置饼图相对于容纳饼图矩形的尺寸,参数取值为0~1;

    • 用setHorizontalPosition(relativePosition: float)方法设置饼图在矩形内的水平相对位置,参数取值为0~1,默认值是0.5,表示在水平中间位置,0表示左侧,1表示右侧;
    • 同理用setVerticalPosition(relativePosition:float)方法设置饼图在矩形内的坚直相对位置,0 表示顶部,1表示底部
  • 用setLabelsVisible(visible: bool= True)方法设置切片标签是否可见;

  • 用setLabelsPosition(QPieSlice,LabelPosition)方法设置切片标签的位置,枚举参数QPieSlice. LabelPosition 可取:

    • QPieSlice.LabelOutside
    • QPieSlice.LabelInsideHorizontal
    • QPieSlice.LabelInsideTangential
    • QPieSlice.LabelInsideNormal。
  • 默认情况下,饼图是0°一360°全部填充,0在竖直方向,顺时针旋转为正,可以设置饼图只在指定角度范围内绘制。

    • 用setPieStartAngle(startAngle:float)方法设置饼图的起始角,
    • 用setPieEndAngle(endAngle:float)方法设置终止角
QPieSeries的方法及参数类型 说明
append(QPieSlice) 添加切片,成功则返回True
append(Sequence[QPieSlice]) 添加多个切片,成功则返回True
append(label: str,value:float) 添加切片,并返回切片 QPieSlice
insert(index: int.slice: QPieSlice) 插人切片,成功则返回True
slices() 获取切片列表List[QPieSlice]
remove(QPieSlice) 移除并删除切片
take(QPieSlice) 移除但不删除切片
clear() 删除所有切片
count() 获取切片的数量
sum() 计算所有切片值的和
isEmpty() 获取是否含有切片
setPieSize(relativeSize: float) 设置饼图的相对尺寸,参数取值为0~1
setHoleSize(holeSize:float) 设置饼图内孔的相对尺寸,参数值为0~1
setHorizontalPosition(relativePosition:float) 设置饼图的水平相对位置,参数值为0~1
setVerticalPosition(relativePosition: float) 设置饼图的竖直相对位置,参数值为0~1
setLabelsVisible(visible:bool=True) 设置切片的标签是否可见
setLabelsPosition(QPieSlice. LabelPosition) 设置切片标签的位置
setPieStartAngle(startAngle:float) 设置饼图的起始角
setPieEndAngle(endAngle: float) 设置饼图的终止角
饼图数据序列QPieSeries 的信号

饼图数据序列QPieSeries 的信号如表所示

QPieSeries的信号及参数类型 说明
added(slices: List[QPieSlice]) 添加切片时发送信号,参数是添加的切片
clicked(slice: QPieSlice) 单击切片时发送信号
countChanged() 切片数量发生改变时发送信号
doubleClicked(slice:QPieSlice) 双击切片时发送信号
hovered(slice:QPieSlice,state:bool) 光标在切片上悬停时发送信号,光标在切片上移动时 state值 是True,光标离开切片时 state 值是False
pressed(slice:QPieSlice) 在切片上按下鼠标按键时发送信号
released(slice; QPieSlice) 在切片上释放鼠标按键时发送信号
removed(slices: List[QPieSlice]) 移除切片时发送信号,参数是移除的切片列表
sumChanged() 所有切片的值的和发生改变时发送信号
饼图切片 QPicSlice的方法

饼图由切片 QPieSlice构成,通常需要为切片设标签和值。

切片 QPieSlice 的常用方法如表所示

  • 主要方法是用setLabel(label:str)方法设置标签文宇;
  • 用setValue(value; float)方法设置切片的值;
  • 用setExploded(exploded;bool=True)方法设置切片是否是爆炸切片;
  • 用setExplodeDistanceFactor(factor: float)方法设置爆炸距离;
  • 用setLabelPosition(position: QPieSlice.LabelPosition)方法设置标的位置,参数可取以下值,对应值分别是0~3。
    • QPieSlice.LabelOutside
    • QPieSlice.LabelInsideHorizontal
    • QPieSlice.LabelIngideTangential
    • QPieSlice.LabelInsideNormal
QPieSlice的方法及参数类型 悦明
setLabel(lnbel; str) 设置切片的标签文字
label() 获取切片的标签文字
serValue(value:float) 设置切片的值
value() 获取切片的值
percentage() 获取切片的百分比值
setPen(pen:Union[QPen,Qt.PenStyle,QColor]) 设置钢笔
setBorderColor(color:Union[QColor,Qt.GlobulColor,str]) 设置边框的颜色
setBorderWidth(width:int) 设置边框的宽度
setBrush(brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor,QGradient,QImage,QPixmap]) 设置画刷
setColor(color:Union[QColor,Qt.GlobalColor,str]) 设填充颜色
setExploded(exploded:bool=True) 设置切片是否处于爆炸状态
isExploded() 获取切片是否处于爆炸状态
setExplodeDistanceFactor(factor:float) 设置爆炸距离
explodeDistanceFactor() 获取爆炸距离
setLabelVisible(visible:bool=True) 设置切片标签是否可见
isLabelVisible() 获取切片标签是否可见
setLabelArmLengthFactor(factor: float) 设置切片标签的长度
setLabelBrush(brush: Union[QBrush, Qt.BrushStyle, Qt.GlobalColor,QColor,QGradient,QImage,QPixmap]) 设置切片标签画刷
setLabelColor(color:Union[QColor,Qt.GlobalColor,str]) 设置切片标签的颜色
setLabelFont(font: Union[QFont,str,Sequence[str]]) 设置切片标签的字体
setLabelPosition(position: QPieSlice. LabelPosition) 设置切片标签的位置
labelPosition() 获取切片标签的位置
series() 获取切片所在的数据序列
startAngle() 获取切片的起始角
angleSpan() 获取切片的跨度角
饼图切片 QPieSlice 的信号

饼图切片 QPieSlice 的信号如表所示可以通过信号的名称获取其发送的时机

QPieSlice的信号 QPieSlice的信号 QPieSlice的信号 QPieSlice的信号
angleSpanChanged() colorChanged() labelColorChanged() pressed()
borderColorChanged() doubleClicked() labelFontChanged() released()
borderWidthChanged() hovered(state:bool) labelVisibleChanged() penChanged()
brushChanged() labelBrushChanged() startAngleChangedl() clicked()
valueChanged() labelChanged() percentageChanged()
饼图的应用实例

下面的程序根据季度销售额绘制圆环图,程序运行结果如图所示

image-20230311233852518

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 23:31
# File_name: 02- 饼图的应用实例.py


import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PySide6.QtCharts import QChartView, QChart, QPieSeries, QPieSlice


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

chartView = QChartView()
V = QVBoxLayout(self)
V.addWidget(chartView)

self.chart = QChart()
chartView.setChart(self.chart)
pieSeries = QPieSeries()
pieSeries.setLabelsPosition(QPieSlice.LabelPosition.LabelOutside)
pieSeries.setPieStartAngle(90)
pieSeries.setPieEndAngle(- 270)

first = QPieSlice("第1季度销售额", 32.3) # 创建切片

second = QPieSlice("第2季度销售额", 22.5) # 创建切片
second.setExploded(exploded=True) # 爆炸切片

pieSeries.append(first) # 添加切片

pieSeries.append("第3季度销售额", 46.3) # 添加切片
pieSeries.append("第4季度销售额", 52.7) # 添加切片

pieSeries.setLabelsVisible(visible=True) # 标签可见

pieSeries.setHoleSize(0.3) # 孔的尺寸

self.chart.addSeries(pieSeries) # 图表中添加数据序列

pieSeries.append(second)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

条形图

条形图以竖直条或水平条显示数据,它由数据项 QBarSet 构成,每个数据项包含多个数据

条形图的数据序列有多种类型,竖直数据序列有 QBarSeries、QStackedBarSeries、QPercentBarSeries

水平数据序列有 QHorizontalBarSeries、QHorizontalStackedBarSeries和QHorizontalPercentBarSeries

它们并没有特有的方法和信号它们的方法和信号继承自抽象类 QAbstractBarSeries。

用QBarSeries、QStackedBarSeries、 QPercentBarSeries、 QHorizontalBarSeries、QHorizontalStackedBarSeries、QHorizontalPercentBarSeries 、QBarSet 创建实例对象的方法如下所示,其中 label 是数据项在图例中的名称。

1
2
3
4
5
6
7
8
9
10
from PySide6.QtCharts import QBarSeries, QStackedBarSeries, QPercentBarSeries
from PySide6.QtCharts import QHorizontalBarSeries, QHorizontalStackedBarSeries, QHorizontalPercentBarSeries, QBarSet

QBarSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QStackedBarSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QPercentBarSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QHorizontalBarSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QHorizontalStackedBarSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QHorizontalPercentBarSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QBarSet(label: str, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
抽象类QAbstractBarSeries
抽象类QAbstractBarSeries 的方法

QAbstractBarSeries 的常用方法如表所示,主要方法介绍如下

  • 用append(set:QBarSet)方法添加数据项;
    • 用append(sets: Sequence[QBarSet])方法添加多个数据项;
    • 用insert(index;int,set;QBarSet)方法根据索引插入数据项;
  • 用barSets()方法获取数据项列表;
    • 用count()方法获取数据项的个数;QChartView
  • 用remove(QBarSet)方法州除指定的数据项;
    • 用clear()方法删除所有的数据项。
  • 用setLabelsVisible(visible; bool= True)方法设置条形的标签是否可见;
  • 用setLabelsFormat(format:str)方法设置标签的个数格式符中用”@value”表示条形的值;
  • 用setLabelsPosition(QAbstractBarSeries。LabelsPosition)方法设置标签的位置,参数可以取以下值,值分别对应0~3。
    • QAbstractBarSeries.LabelsCenter
    • QAbstractBarSeries.LabelsInsideEnd
    • QAbstractBarSeries.LabelsInsideBase
    • QAbstractBarSeries.LabelsOutsideEnd
QAbstractBarSeries的方法及参数类型 说明
append(set: QBarSet) 添加数据项,成功则返回True
append(sets:Sequence[QBarSet]) 添加多个数据项,成功则返回True
insert(index: int,set: QBarSet) 根据索引插入数据项,成功则返回True
barSets() 获取数据项列表List[QBarSet]
remove(set: QBarSet) 删除数据项,成功则返回 True
take(set: QBarSet) 移除数据项,成功则返回True
clear() 除所有数据项
count() 获取数据项的个数
setBarWidtb(width;flont) 设置条形的宽度
barWidth() 获取条形的宽度
setLabelsAngle(angle; flont) 设置标签的旋转角度
setLabelsVisible(visible;bool=True) 设置标签是否可见
isLabelsVisible() 获取标签是否可见
setLabelsPosition(QAbstractBarSeries. LabelsPosition) 设置标签的位置
setLabclsFormat(format;str) 设置标签的格式
setLabelsPrecision(precision:int) 设置标签的最大小数位数
抽象类QAbstractBarSeries 的信号

抽象类QAbstractBarSeries 的信号如表所示

QAbstractBarSeries的信号 说明
barsetsAdded(barsets: List[QBarSet]) 添加数据项时发送信号
barsetsRemoved(barsets: List[QBarSet]) 移除数据项时发送信号
clicked(index:int,barset:QBarSet) 单击数据项时发送信号
doubleClicked(index:int,barset:QBarSet) 双击数据项时发送信号
pressed(index:int,barset:QBarSet) 在标签上按下鼠标按键时发送信号
released(index:int,barset:QBarSet) 在标签上释放鼠标按键时发送信号
hovered(status: bool,index: index,barset:QBarSet) 光标在数据项上移动时发送信号
labelsAngleChanged(angle: float) 标签角度发生改变时发送信号
labelsFormatChanged(fromat: str) 标签格式发生改变时发送信号
labelsPositionChanged(QAbstractBarSeries. LabelsPosition) 标签位置发生改变时发送信号
labelsPrecisionChanged(precision:int) 标签精度发生改变时发送信号
labelsVisibleChanged() 标签的可见性发生改变时发送信号
countChanged() 数据项的个数发生改变时发送信号
数据项QBarSet
数据项QBarSet的方法

数据项QBarSet 中定义不同条目的值。

数据项的常用方法如表所示主要方法是:

  • 用append(value:float)方法或 append(values:Sequence[float])方法添加条目的值;
  • 用insert(index:int,value:float)方法插入值;
  • 用at(index:int)方法根据索引获取值
QBarSet的方法及参数类型 说 明
append(value: float) 添加条目的值
append(values: Sequence[float]) 添加多个条目的值
insert(index:int,value:float) 根据索引插人条目的值
at(index: int) 根据索引获取条目的值
count() 获取条目值的个数
sum() 获取所有条目的值的和
remove(index: int,count:int=1) 根据索引,移除指定数量的值
replace(index:int,value: float) 根据索引替换值
setBorderColor(color: Union[QColor,Qt.GlobalColor,str]) 设置边框颜色
setPen(pen: Union[QPen,Qt.PenStyle,QColor]) 设置钢笔
setBrush(brush:Union[QBrush,Qt.BrushStyle,QColor,Qt.GlobalColor,QGradient,QImage,QPixmap]) 设置画刷
setColor(color;Union[QColor,Qt.GlobalColor,str]) 设置颜色
setLabel(label: str) 设置数据项在图例中的名称
label() 获取数据项在图例中的名称
setLabelBrush(brush:Union[QBrush, Qt.BrushStyle,Qt.GlobalColor,QColor,QGradient,QImage,QPixmap]) 设置标签画刷
setLabelColor(color:Union[QColor,Qt.GlobalColor.str]) 设置标签颜色
setLabelFont(font: Union[QFont,str,Sequence[str]]) 设置标签字体
setBarSelected(index: int,selected: bool) 根据索引选中数据项
setSelectedColor(color:Union[QColor.Qt.GlobalColor,str]) 设置选中的数据项的颜色
selectedColor() 获取选中的数据项的颜色
selectAllBars() 选中所有的数据项
selectBar(index:int) 根据索引选中指定的数据项
selectBars(indexes: Sequence[int]) 根据索引选中多个数据项
selectedBars() 获取选中的数据项的索引列表
deselectBars(indexes:Sequence[int]) 根据索引取消选择
isBarSelected(index:int) 根据索引获取指定的数据项是否被选中
toggleSelection(indexes: Sequence[int]) 根据索引切换选中状态
deselectBar(index:int) 根据索引取消选中状态
deselectAIlBars() 取消所有的选中状态
数据项QBarSet的信号

数据项QBarSet 的信号如表所示

QBarSet 的信号 说 明
valuesAdded(index:int,count:int) 添加值发送信号
valuesRemoved(index: int,count:int) 移除值时发送信号
valueChanged(index:int) 值发生改变时发送信号
borderColorChanged(color:QColor) 边框颜色发生改变时发送信号
brushChanged() 画刷发生改变时发送信号
clicked(index:int) 单击鼠标时发送信号
colorChanged(color:QColor) 颜色发生改变时发送信号
doubleClicked(index:int) 双击鼠标时发送信号
hovered(status: bool,index: int) 光标在数据项上移动或移出时发送信号
labelBrushChanged() 标签画刷发生改变时发送信号
labelChanged() 标签发生改变时发送信号
labelColorChanged(color: QColor) 标签颜色发生改变时发送信号
labelFontChanged() 标签字体发生改变时发送信号
penChanged() 钢笔发生改变时发送信号
pressed(index: int) 按下鼠标按键时发送信号
released(index:int) 释放鼠标按键时发送信号
条形图的应用实例

下面的程序用条形图显示某公司 3 个团队的季度销售额,程序运行结果如图所示

image-20230312021158180

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/11 23:56
# File_name: 03-条形图的应用实例.py
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QGraphicsLinearLayout
from PySide6 import QtCharts
import sys


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(1500, 600)
V = QVBoxLayout(self)

chartView = QtCharts.QChartView(self) # 创建图表视图控件
V.addWidget(chartView)
chart = QtCharts.QChart()
chartView.setChart(chart)
linearGraphicsLayout = QGraphicsLinearLayout(chart) # 创建显示图表的空间

# 创建图表并添加到组件显示
linearGraphicsLayout.addItem(chart1 := QtCharts.QChart())
linearGraphicsLayout.addItem(chart2 := QtCharts.QChart())
linearGraphicsLayout.addItem(chart3 := QtCharts.QChart())

# 设置图表标题
chart1.setTitle("公司2020年季度销售业绩")
chart2.setTitle("公司2021年季度销售业绩")
chart3.setTitle("公司2022年季度销售业绩")

# 创建数据项
set1 = QtCharts.QBarSet("1组")
set2 = QtCharts.QBarSet("2组")
set3 = QtCharts.QBarSet("3组")
# 添加数据
set1.append([12, 34, 23, 45])
set2.append([24, 33, 42, 41])
set3.append([21, 41, 23, 40])

# 创建数据序列
self.barSeries = QtCharts.QBarSeries() #(并排)
self.stackedBarSeries = QtCharts.QStackedBarSeries() # 堆叠)
self.percentBarSeries = QtCharts.QPercentBarSeries() #(堆叠百分比)
# 数据序列添加数据项
self.barSeries.append([set1, set2, set3])
self.stackedBarSeries.append([set1, set2, set3])
self.percentBarSeries.append([set1, set2, set3])

# 图表中添加数据序列
chart1.addSeries(self.barSeries)
chart2.addSeries(self.stackedBarSeries)
chart3.addSeries(self.percentBarSeries)

# 创建X坐标轴,并
self.barCategoryAxis1 = QtCharts.QBarCategoryAxis()
self.barCategoryAxis2 = QtCharts.QBarCategoryAxis()
self.barCategoryAxis3 = QtCharts.QBarCategoryAxis()
self.barCategoryAxis1.append(["并排"])
self.barCategoryAxis2.append(["堆叠"])
self.barCategoryAxis3.append(["堆叠占满"])

# 图表设置Y轴
# chart1.setAxisX(self.barCategoryAxis1, self.barSeries) # 图表设置X轴
# chart2.setAxisX(self.barCategoryAxis1, self.stackedBarSeries) # 图表设置X轴
# chart3.setAxisX(self.barCategoryAxis2, self.percentBarSeries) # 图表设置X轴
chart1.addAxis(self.barCategoryAxis1, Qt.AlignmentFlag.AlignBottom)
chart2.addAxis(self.barCategoryAxis2, Qt.AlignmentFlag.AlignBottom)
chart3.addAxis(self.barCategoryAxis3, Qt.AlignmentFlag.AlignBottom)
self.barSeries.attachAxis(self.barCategoryAxis1)
self.stackedBarSeries.attachAxis(self.barCategoryAxis2)
self.percentBarSeries.attachAxis(self.barCategoryAxis3)

self.barSeries.attachAxis(self.barCategoryAxis1)
self.stackedBarSeries.attachAxis(self.barCategoryAxis2)
self.percentBarSeries.attachAxis(self.barCategoryAxis3)

self.valueAxis1 = QtCharts.QValueAxis() # 创建坐标轴
self.valueAxis1.setRange(0, 50) # 设置坐标轴的数值范围
self.valueAxis2 = QtCharts.QValueAxis() # 创建坐标轴
self.valueAxis2.setRange(0, 150) # 设置坐标轴的数值范围
self.valueAxis3 = QtCharts.QValueAxis() # 创建坐标轴
self.valueAxis3.setRange(0, 100) # 设置坐标轴的数值范围

# 图表设置Y轴
# chart1.setAxisY(self.valueAxis1, self.barSeries) # 图表设置Y轴
# chart2.setAxisY(self.valueAxis2, self.stackedBarSeries) # 图表设置Y轴
# chart3.setAxisY(self.valueAxis3, self.percentBarSeries) # 图表设置Y轴
chart1.addAxis(self.valueAxis1, Qt.AlignmentFlag.AlignLeft)
chart2.addAxis(self.valueAxis2, Qt.AlignmentFlag.AlignLeft)
chart3.addAxis(self.valueAxis3, Qt.AlignmentFlag.AlignLeft)

# 设置数据标签可见
self.barSeries.setLabelsVisible(True)
# 设置标签格式
self.barSeries.setLabelsFormat("@value万")
# 设置标签位置
self.barSeries.setLabelsPosition(self.barSeries.LabelsPosition.LabelsInsideEnd)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

蜡烛图

蜡烛图类似于股票k线图,能反映一段时间内的初始值、期末值和这段时间内的最大值和最小值。

蜡烛图的数据序列是 QCandlestickSeries,蜡烛序列中的数据项用QCandlestickSet定义。

用QCandlestickSeries 和 QCandlestickSet 创建实例对象的方法如下所示,其中:

  • open和close分别是初始值和期末值,
  • high 和low 是这段时间内的最大值和最小值
  • timestamp 是时间戳
1
2
3
4
5
from PySide6.QtCharts import QCandlestickSeries, QCandlestickSet

QCandlestickSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QCandlestickSet(open: float, high: float, low: float, close: float, timestamp: float = 0.0, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QCandlestickSet(timestamp: float = 0.0, parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
蜡烛图数据序列QCandlestickSeries 的方法

蜡烛图数据序列QCandlestickSeries 的方法如表所示,主要方法介绍如下

  • 用append(set;QCandlestickSet)和 append(sets; Sequence[QCandlestickSet])方法可以添加蜡烛数据;

  • 用insert(index:int,set:QCandlestickSet)方法根据索引插人蜡烛数据;

  • 用remove(set; QCandlestickSet)方法和 remove(sets; Sequence[QCandlestickSet])方法可以删除蜡烛数据;

  • 用clear()方法除所有蜡烛数据:用count()方法获取蜡烛数据的个数;

  • 用set()方法获取蜡烛数据列表

  • 用setIncreasingColor(increasingColor: QColor)方法和 setDecreasingColor(decreasingColor:QColor)方法分别设置上涨和下跌时的颜色。

  • 用setCapsVisible(capsVisible:bool=False)方法设置最大值和最小值的帽线是否可见;

  • 用setCapsWidth(capsWidth:float)方法设置帽线相对于蜡烛的宽度,参数取值范围是 0~1。

QCandlestickSeries的方法及参数类型 返回值的类型 说明
append(set:QCandlestickSet) bool 添加蜡烛数据
append(sets: Sequence[QCandlestickSet]) b001 添加多个蜡烛数据
insert(index:int,set: QCandlestickSet) bo01 根据索引插人蜡烛数据项
sets() List[QCandlestickSetJ 获取蜡烛数据项列表
clear() None 删除所有蜡烛数据项
count() int 获取蜡烛数据的数量
remove(set:QCandlestickSet) bool 删除蜡烛数据
remove(sets:Sequence[QCandlestickSet]) bool 删除多个蜡烛数据
take(set:QCandlestickSet) b.01 移除蜡烛数据
setBodyOutlineVisible(bodyOutlineVisible:bool) None 设置蜡烛轮廓线是否可见
setBodyWidth(bodyWidth: float) None 设置蜡烛相对宽度,取值范围是0~1
bodyWidth() float 获取蜡烛宽度
setBrush(brush: Union[QBrush, QColor, Qt.GlobalColor, QGradient, QImage, QPixmap]) None 设置画刷
brush() QBrush 获取画刷
setCapsVisible(capsVisible: bool = False) None 设置最大值和最小值的帽线是否可见
capsVisible() bool 获取帽线是否可见
setCapsWidth(capsWidth:float) None 设置帽线相对于蜡烛的宽度,取值范 围是0~1
capsWidth() float 获取帽线的相对宽度
setDecreasingColor(decreasingColor: QColor) None 设置下跌时的颜色
decreasingColor() QColor 获取下跌时的颜色
setIncreasingColor(increasingColor: QColor) None 设置上涨时的颜色
increasingColor() QColor 获取上涨时的颜色
setMaximumColumnWidth(float) None 设置最大列宽(像素),设置负值没有 最大列宽限制
maximumColumnWidth() float 获取最大宽度
setMinimumColumnWidth(float) None 设置最小列宽(像素),设置负值没有 最小列宽限制
minimumColumnWidth() float 获取最小宽度
setPen(pen: Union[QPen, Qt.PenStyle,QColor]) None 设置钢笔
pen() QPen 欢取钢笔
蜡烛图数据序列QCandlestickSeries 的信号

蜡烛图数据序列QCandlestickSeries 的信号如表所示

QCandlestickSeries的信号及参数类型 说 明
bodyOutlineVisibilityChanged() 轮廓发生改变时发送信号
bodyWidthChanged() 宽度发生改变时发送信号
brushChanged() 画刷发生改变时发送信号
candlestickSetsAdded(sets: List[QCandlestickSet]) 添加蜡烛数据时发送信号
candlestickSetsRemoved(sets: List[QCandlestickSet]) 删除蜡烛数据时发送信号
capsVisibilityChanged() 最大值和最小值可见性发生改变时发送信号
capsWidtbChanged() 最大值和最小值的宽度发生改变时发送信号
clicked(set: QCandlestickSet) 单击时发送信号
countChanged() 蜡烛数据发生改变时发送信号
decreasingColorChanged() 下跌时的颜色发生改变时发送信号
doubIeClicked(set: QCandlestickSet) 双击鼠标时发送信号
hovered(status; bool,set: QCandlestickSet) 光标在蜡烛数据上移动或移开蜡烛数据时发送 信号
increasingColorChanged() 上涨时的颜色发生改变时发送信号
maximumColumnWidthChanged() 列的最大宽度发生改变时发送信号
minimumColumnWidthChanged() 列的最小宽度发生改变时发送信号
penChanged() 钢笔发生改变时发送信号
pressed(set:QCandlestickSet) 在蜻烛数据上按下鼠标按键时发送信号
released(set: QCandlestickSet) 在蜡烛数据上释放鼠标按键时发送信号
蜡烛数据项 QCandlestickSet 的方法

蜡烛数据项 QCandlestickSet 的常用方法如表所示

  • 用setOpen(open:float)和 setClose(close:float)方法分别设置初始值和期末值;
  • 用setHigh(high: float)和setLow(low;float)方法设置最高值和最低值;
  • 用setTimestamp(timestamp: float)方法设置时间戳
QCandlestickSet的方法及参数类型 返回值的类型 说 明
setOpen(open:float) None 设置初始值
open() float 获取初始值
setClose(close:float) None 设置期末值
close() float 获取期末值
setHigh(high: float) None 设置最高值
high() float 获取最高值
setLow(low:float) None 设置最低值
low() float 获取最低值
setTimestamp(timestamp:float) None 设置时间戳
timestamp() float 获取时间截
setPen(pen:Union[QPen,Qt.PenStyle,QColor]) None 设置钢笔
pen() QPen 获取钢笔
setBrush(brush:Union[QBrush,Qt.GlobalColor,Qt.BrushStyle,QColor,QGradient,QImage,QPixmap]) None 设置画刷
brush() QBrush 获取画刷
蜡烛数据项QCandlestickSet 的信号

蜡烛数据项QCandlestickSet 的信号如表所示

QCandlestickSet 的信号 说明
brushChanged() 画刷发生改变时发送信号
clicked() 在蜡烛数据上单击鼠标时发送信号
closeChanged() 期末值发生改变时发送信号
doubleClicked() 在蜡烛数据上双击鼠标时发送信号
highChanged() 最高值发生改变时发送信号
hovered(status: bool) 光标在蜡烛数据上移动或移开蜡烛数据时发送信号
lowChanged() 最低值发生改变时发送信号
openChanged() 初始值发生改变时发送信号
penChanged() 钢笔发生改变时发送信号
pressed() 在蜡烛数据上按下鼠标按键时发送信号
released() 在蜡烛数据上释放鼠标按键时发送信号
timestampChanged() 时间戳发生改变时发送信号

箱线图

箱线图是一种用来显示一组数据分散情况的统计图,因形状如箱子而得名。箱线图的示意图如图 所示。

箱线图的计算方法是,找出一组数据的 5 个特征值,特征值(从下到上)分别是

  • 最小值
  • Q1(下四分位数)
  • 中位数
  • Q3(上四分位数)
  • 最大值。

将这5 个特征值描绘在一条竖直线上,将最小值和 Q1 连接起来,利用Q1中位数Q3 分别作平行等长的线段,然后连接两个四分位数构成箱子,再连接两个极值点与箱子,形成箱线图。

中位数、Q1 和 Q3 以及最大值、最小值的概念如下:

  • 中位数:将所有数值从小到大排列,如果数据的个数是奇数,则取中间一个值作为中位数,之后中间的值在计算 Q1 和 Q3时不再使用,如果数据的个数是偶数则取中间两个数的平均数作为中位数,这两个数在计算 Q1和 Q3 时继续使用
  • Q1:中位数将所有数据分成两部分,最小值到中位数的部分按取中位数的方法再取中位数作为 Q1。
  • Q3:同Q1 的取法取中位数到最大值的中位数
  • 最大值和最小值:取四分位数间距 IQR=Q3-Q1,所有不在(Q1-whisker * IQR, Q3+whisker *IQR)区间内的数为异常值,其中whisker 值一般取15,剩下的值中最大的为最大值,最小的为最小值。

箱线图的数据序列是QBoxPlotSeries,箱线图的数据项是QBoxSet。

用QBoxPlotSeries和QBoxSet创建实例对象的方法如下所示,其中

  • label是数据项的标签,le(lowerextreme)是最小值
  • lq(lower quartile)是下四分位数
  • m(median)是中位数
  • uq(upper quartile)是上四分位数
  • ue(upper extreme)是最大值。
1
2
3
4
5
from PySide6.QtCharts import QBoxPlotSeries, QBoxSet

QBoxPlotSeries(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QBoxSet(label: str = '', parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QBoxSet(le: float, lq: float, m: float, uq: float, ue: float, label: str = '', parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
箱线图数据序列 OBoxPlotSeries 的方法

箱线图数据序列QBoxPlotSeries 的常用方法如表所示,主要方法:

  • 用append(box:QBoxSet)或append(boxes: Sequence[QBoxSet])方法添加数据项;
  • 用insert(index:int,box:QBoxSet)方法根据索引插人数据项。
QBoxPlotSeries的方法及参数类型 返回值的类型 说明
append(box:QBoxSet) bool 添加箱线图数据项
append(boxes:Sequence[QBoxSet]) bo01 添加多个箱线图数据项
insert(index; int,box:QBoxSet) bool 根据索引插入数据项
boxSets() List[QBoxSet] 获取箱线图数据项列表
clear() None 清除所有箱线图数据项
count() int 获取箱线图数据项的个数
setBoxOutlineVisible(visible:bool) None 设置轮廓是否可见
boxOutlineVisible() b001 获取轮廓是否可见
setBoxWidth(width:float) None 设置箱形宽度
boxWidth() float 获取箱形宽度
setBrush(brush:Union[QBrush,Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap]) None 设置画刷
brush() QBrush 获取画刷
setPen(pen: Union[QPen,Qt.PenStyle,QColor]) None 设置钢笔
pen() QPen 获取钢笔
remove(box:QBoxSet) bo01 删除箱线图数据项
take(box: QBoxSet) bo0l 移除箱线图数据项
箱线图数据序列QBoxPlotSeries的信号

箱线图数据序列 QBoxPlotSeries 的信号如表所示,发送时机可参考前面的内容。

QBoxPlotSeries的信号 说明
countChanged() 当系列中的盒须物品数量发生变化时,会发出此信号。
boxWidthChanged() 当盒须物品的宽度发生变化时,会发出此信号。
brushChanged() 当用于填充长方体和胡须项的长方体的笔刷发生变化时,会发出此信号。
clicked(QBoxSet) 当用户单击图表中框集指定的框和胡须项时,会发出此信号。
penChanged() 当用于绘制长方体线条和胡须项目的笔发生变化时,会发出此信号。
doubleClicked(QBoxSet) 当用户双击图表中框集指定的框和胡须项时,会发出此信号。
boxsetsAdded(sets: List[QBoxSet]) 当将集合指定的长方体和胡须项列表添加到系列中时,会发出此信号。
boxsetsRemoved(List[QBoxSet]) 当将集合指定的长方体和胡须项列表添加到系列中时,会发出此信号。
hovered(status:bool,QBoxSet) 当鼠标悬停在图表中框集指定的框和胡须项目上时,会发出此信号。当鼠标移动到项目上时,状态变为真,而当鼠标再次移开时,状态则变为假。
pressed(boxset:QBoxSet) 当用户单击图表中框集指定的框和胡须项目并按住鼠标按钮时,会发出此信号。
released(boxset:QBoxSet) 当用户在图表中的框集指定的框和胡须项目上释放鼠标时,会发出此信号。
boxOutlineVisibilityChanged() 当框轮廓可见性更改时,会发出此信号。
箱线图数据项QBoxSet的方法

箱线图数据项QBoxSet 的常用方法如表所示,主要方法:

  • 用append(value:float)方法或 append(values: Sequence[float])方法添加数据;
  • 用setValue(index; int,value:float)方法根据索引设置数据
QBoxSet的方法及参数类型 返回值的类型 说:明
append(value:float) None 添加数据
append(values:Sequence[float]) None 添加多个数据
setValue(index: int,value:float) None 根据索引设置数据的值
at(index:int) float 根据索引获取数据的值
clear() None 清除所有数据
count() int 获取数据的个数
setLabel(label: str) None 设置标签
label() Str 获取标签
setBrush(brush: Union[QBrush, Qt.GlobalColor, Qt.BrushStyle,QColor,QGradient,QImage,QPixmap]) None 设置画刷
brush() QBrush 获取画刷
setPen(pen: Union[QPen,Qt.PenStyle,QColor]) None 设置钢笔
pen() QPen 获取钢笔
箱线图数据项QBoxSet 的信号

和箱线图数据项 QBoxSet 的信号如表所示,发送时机可参考前面的内容。

QBoxSet的信号 说明
brushChanged() 当长方体和胡须项的笔刷更改时,会发出此信号。
doubleClicked() 当用户双击框和胡须项目时,会发出此信号。
hovered(status:bool) 当鼠标悬停在图表中的框和胡须项目上时,会发出此信号。当鼠标移动到项目上时,状态变为真,而当鼠标再次移开时,状态则变为假。
penChanged() 当方框和胡须项目的笔发生变化时,会发出此信号。
valueChanged(index) 当修改索引指定的框和胡须项的值时,会发出此信号。
valuesChanged() 当长方体和胡须项的多个值发生变化时,会发出此信号。
pressed() 当用户单击图表中的框和胡须项目并按住鼠标按钮时,会发出此信号。
released() 当用户释放对框和胡须项目的鼠标按压时,会发出此信号。
cleared() 当长方体和胡须项的所有值都设置为0时,将发出此信号。
clicked() 当用户单击图表中的框和胡须项时,会发出此信号。

极坐标图

绘制极坐标图需要用QPolarChart;它是从QChart 继承而来的。

用QPolarChart 创建极坐标图实例的方法如下,其中parent 是继承自QGraphicsItem 的实例对象。

1
2
3
from PySide6.QtCharts import QPolarChart

QPolarChart(parent: Union[PySide6.QtWidgets.QGraphicsItem, NoneType]= None, wFlags: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None
  • 在QPloarChart中可以添加QLineSeries、QSplineSeries、QScatterSeries和QAreaSeries 数据序列,不过添加坐标轴的方法有所不同
    • 用addAxis(axisQAbstractAxis,polarOrientation: PolarOrientation)方法添加标轴,其中参数polarOrientation 确定坐标轴的方法可以取:
      • QPolarChart.PolarOrientationRadial(半径方向)
      • QPolarChart.PolarOrientationAngular(角度方向);
  • 用静态方法axisPolarOrientation(axis:QAbstractAxis)可以获取指定的坐标轴的方向。极坐标的0方法是在图表的正上面,顺时针方向为正。

下面的程序用极坐标绘制一个渐开线图表,分别用折线图和散点图添加两条渐开线,渐开线的方程是r=(r0** 2+(pi* rO*angle/180)** 2)**05其中r是基圆半径。

image-20230312172958181

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 17:18
# File_name: 05-极坐标图与实例.py


from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PySide6.QtCharts import QChartView, QPolarChart, QLineSeries, QScatterSeries, QValueAxis
from PySide6.QtCore import Qt
import sys, math


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(1000, 600)
V = QVBoxLayout(self)
chartView = QChartView(self)
V.addWidget(chartView) # 创建图表视图控件

chart = QPolarChart() # 创建极坐标图表
chartView.setChart(chart) # 图表控件中设置图表
chart.setTitle("极坐标图表") # 设置图表的标题
lineSeries = QLineSeries() # 创建折线数据序列
lineSeries.setName("折线") # 设置数据序列的名称
scatterSeries = QScatterSeries() # 创建散点数据序列
scatterSeries.setName("散点")

r0 = 10
for angle in range(0, 360, 2):
r =(r0 ** 2 +(math.pi * r0 * angle / 180) ** 2) ** 0.5
lineSeries.append(angle, r) # 数据序列中添加数据

r0 = 12
for angle in range(0, 360, 5):
r =(r0 ** 2 +(math.pi * r0 * angle / 180) ** 2) ** 0.5
lineSeries.append(angle, r) # 数据序列中添加数据

chart.addSeries(lineSeries) # 图表中添加数据序列
chart.addSeries(scatterSeries) # 图表中添加数据序列

axis_angle = QValueAxis() # 创建数值坐标轴
axis_angle.setTitleText("Angle") # 设置坐标轴的标题
axis_angle.setRange(0, 360)
axis_angle.setLinePenColor(Qt.black)
axis_radius = QValueAxis() # 创建数值坐标轴
axis_radius.setTitleText("Distance")
axis_radius.setRange(0, 80)
axis_radius.setGridLineColor(Qt.gray)

chart.addAxis(axis_angle, QPolarChart.PolarOrientation.PolarOrientationAngular) # 添加坐标轴
chart.addAxis(axis_radius, QPolarChart.PolarOrientation.PolarOrientationRadial) # 添加坐标轴

lineSeries.attachAxis(axis_angle)
lineSeries.attachAxis(axis_radius)
scatterSeries.attachAxis(axis_angle)
scatterSeries.attachAxis(axis_radius)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

图表的坐标轴

要正确显示数据序列所表示的图表,需要给数据序列关联坐标轴,根据数据序列的类型关联对应类型的坐标轴。

图表的坐标轴类型和继承关系如图 所示,坐标轴的类型有:

  • QValueAxis
  • QLogValueAxis
  • QBarCategoryAxis
  • QCategoryAxis
  • QDataTimeAxis

它们都是从QAbstractAxis 继承而来的.

image-20230312173321607

QAbstractAxis

QAbstractAxis是抽象类,不能直接使用,需要用其子类定义坐标轴。

QAbstractAxis方法

QAbstractAxis定义子类的公共属性和信号,其常用方法如表所示。

QAbstractAxis的方法及参数类型 说 明
show()、hide() 显示坐标轴、隐藏坐标轴
setVisible(visible: bool=True) 设置坐标轴是否可见
isVisible() 获取坐标轴是否可见
setMin(Any)、setMax(Any)、setRange(Any.Any) 设置坐标轴的最小和最大值
setReverse(reverse:bool=True) 设置坐标轴的方向颠倒
isReverse() 获取是否颠倒
setTitleText(str) 设置坐标轴标题的名称
setTitleVisible(visible=True) 设置坐标轴标题的可见性
isTitleVisible() 获取标题是否可见
setTitleBrush(brush: Union[QBrush, Qt.BrushStyle,Qt.GlobalColor,QColor,QGradient,QImage,QPixmap]) .. 设置标题的画刷
setTitleFont(font:Union[QFont,str,Sequence[str]]) 设置标题的字体
setGridLineColor(color:Union[QColor,QL.GlobalColor.str]) 设置主网格线的颜色
setGridLinePen(pen: Union[QPen,Qt.PenStyle.QColor]) 设置主网格线的钢笔
setGridLineVisible(visible:bool=True) 设置主网格线是否可见
isGridLineVisible() 获取主网格线是否可见
setMinorGridlLineColor(color:Union[QColor,Qt.GlobalColor, str]) 设置次网格线的颜色
setMinorGridLinePen(QPen) 设置次网格线的颜色
setMinorGridLineVisible(visible:bool=True) 设置次网格线是否可见
isMinorGridLineVisible() 获取次网格线是否可见
setLabelsAngle(int) 设置刻度标签的旋转角度
setLabelsBrush(Union[QBrush,QColor,Qt.GlobalColor, QGradient]) 设置刻度标签的画刷
setLabelsColor(color:Union[QColor,Qt.GlobalColor,strJ) 设置刻度标签的颜色
setLabelsEditable(editable;bool=True) 设置标签是否可编辑
setLabelsFont(font;Union[QFont,str,Sequence[str]]) 设置标签的字体
setLabelsVisible(visible;bool=True) 设置标签是否可见
setTruncateLabels(truncateLabels:bool=True) 当无法全部显示标签时,设置是否可 截断显示
setLinePen(pen:Union[QPen,Qt.PenStyle,QColor]) 设置坐标轴的线条的钢笔
setLinePenColor(color:Union[QColor,Qt.GlobalColor,str]) 设置坐标轴的线条的钢笔颜色
setLineVisible(visible:bool=True) 设置坐标轴的线条是否可见
isLineVisible() 获取坐标轴的线条是否可见
setShadesBorderColor(color: Union[QColor, Qt.GlobalColor, str]) 设置阴影边框的颜色
setShadesBrush(Union[QBrush, QColor, Qt.GlobalColor, QGradient]) 设置阴影的画刷
setShadesColor(color:Union[QColor,Qt.GlobalColor,str]) 设置阴影的颜色
setShadesPen(pen:Union[QPen,Qt.PenStyle,QColor]) 设置阴影的钢笔
setShadesVisible(visible:bool=True) 设置阴影是否可见
alignment() 获取对齐方式 Qt.Alignment
QAbstractAxis 的信号

QAbstractAxis 的信号如表所示通过名称可知其表达的含义和信号发送的时机。

QAbstractAxis的信号 参数 说明
colorChanged(color) color – PySide6.QtGui.QColor 当轴的颜色变为颜色时,会发出此信号。
gridLineColorChanged(color) color – PySide6.QtGui.QColor 当用于绘制网格线的笔的颜色变为颜色时,会发出此信号。
gridLinePenChanged(pen) pen – PySide6.QtGui.QPen 当用于绘制网格线的笔变为笔时,会发出此信号。
gridVisibleChanged(visible) visible – bool 当轴的网格线的可见性更改为可见时,会发出此信号。
labelsAngleChanged(angle) angle – int 当轴标签的角度更改为角度时,会发出此信号。
labelsBrushChanged(brush) brush – PySide6.QtGui.QBrush 当用于绘制轴标签的画笔更改为画笔时,会发出此信号。
labelsColorChanged(color) color – PySide6.QtGui.QColor 当轴标签的颜色更改为颜色时,会发出此信号。
labelsEditableChanged(editable) editable – bool 当标签的可编辑状态发生变化时,会发出此信号。
labelsFontChanged(pen) pen – PySide6.QtGui.QFont 当轴标签的字体更改为字体时,会发出此信号。
labelsTruncatedChanged(labelsTruncated) labelsTruncated – bool 该信号在两种情况下发出;
当轴从具有一个或多个截断标签改变为没有截断标签时
以及当轴从没有截断标签改变成具有一个或者多个截断的标签时。当前状态由标签Truncated标识。
labelsVisibleChanged(visible) visible – bool 当轴标签的可见性更改为可见时,会发出此信号。
linePenChanged(pen) pen – PySide6.QtGui.QPen 当用于绘制轴线的笔变为笔时,会发出此信号。
lineVisibleChanged(visible) visible – bool 当轴线的可见性更改为可见时,会发出此信号。
minorGridLineColorChanged(color) color – PySide6.QtGui.QColor 当用于绘制次要网格线的笔的颜色变为颜色时,会发出此信号。
minorGridLinePenChanged(pen) pen – PySide6.QtGui.QPen 当用于绘制次要网格线的笔变为笔时,会发出此信号。
minorGridVisibleChanged(visible) visible – bool 当轴的次网格线的可见性更改为可见时,会发出此信号。
reverseChanged(reverse) reverse – bool 当颠倒轴改变状态是发送此信号
shadesBorderColorChanged(color) color – PySide6.QtGui.QColor 当轴的边框颜色变为颜色时,会发出此信号。
shadesBrushChanged(brush) brush – PySide6.QtGui.QBrush 当用于绘制轴阴影的笔刷更改为笔刷时,会发出此信号。
shadesColorChanged(color) color – PySide6.QtGui.QColor 当轴的颜色变为颜色时,会发出此信号。
shadesPenChanged(pen) pen – PySide6.QtGui.QPen 当用于绘制轴阴影的笔更改为笔时,会发出此信号。
shadesVisibleChanged(visible) visible – bool 当轴阴影的可见性更改为可见时,会发出此信号。
titleBrushChanged(brush) brush – PySide6.QtGui.QBrush 当用于绘制轴标题的画笔更改为画笔时,会发出此信号。
titleFontChanged(font) font – PySide6.QtGui.QFont 当轴标题的字体更改为字体时,会发出此信号。
titleTextChanged(title) title – str 当轴标题的文本更改为文本时,会发出此信号。
titleVisibleChanged(visible) visible – bool 当轴的标题文本的可见性更改为可见时,会发出此信号。
truncateLabelsChanged(truncateLabels) truncateLabels – bool 当标签的截断变为truncateLabels时,会发出此信号。
visibleChanged(visible) visible – bool 当轴的可见性更改为可见时,会发出此信号。

QValueAxis

数值轴QValueAxis 适用于具有连续数据坐标的图表,它在继承 QAbstractAxis 的属性、方法和信号的同时,根据数值轴的特点又增添了一些设置坐标轴刻度的方法。

用QValueAxis 创建实例对象的方法是

1
2
3
from PySide6.QtCharts import QValueAxis

QValueAxis(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
数值轴的常用方法

数值轴QValueAxis的常用方法如表所示主要方法介绍如下。

  • 用setTickAnchor(float)方法设置刻度错点(参考点);
  • 用setTickInterval(float)方法设置刻度之间的间隔值;
  • 用setTickCount(int)方法设置刻度数量,刻度线平均分布在最小值和最大值之间;
  • 用setTickType(type:QValueAxis.TickType)方法设置刻度类型,参数可取:
    • QValueAxis.TicksDynamic
    • QValueAxis.TicksFixed.
  • 用setLabelFormat(str)方法设置刻度标签的格式符可以使用字符串的“%”格式符,例如“%3d”表示输出3 位整数,“%7.2”表示输出宽度为7位的浮点数,其中小数位为2,整数位为 4,小数点占1位,
    • 用applyNiceNumbers()智能方法设置刻度的标签。
QValueAxis的方法及参数类型 说 明
setTickCount(int) 设置刻度线的数量
setTickAnchor(float) 设置刻度锚点
setTickInterval(float) 设置刻度线的间隔值
setMinorTickCount(int) 设置次刻度的数量
setTickType(type: QValueAxis.TickType) 设置刻度类型
setMax(float) 设置最大值
setMin(float) 设置最小值
setRange(float,float) 设置坐标轴的最小值和最大值
setLabelFormat(str) 设置标签的格式
[slot]applyNiceNumbers() 使用智能方法设置刻度的标签
数值轴QValueAxis的信号
信号 参数 说明
labelFormatChanged(format) format – str 当轴标签的格式更改时,会发出此信号。
maxChanged(max) max – float 当轴的最大值(由max指定)发生变化时,会发出此信号。
minChanged(min) min – float 当轴的最小值(由min指定)发生变化时,会发出此信号。
minorTickCountChanged(tickCount) tickCount – int 当minorTickCount指定的轴上的次要刻度线数量发生变化时,会发出此信号。
rangeChanged(min, max) min – float
max – float
当轴的最小值或最大值(由最小值和最大值指定)发生变化时,会发出此信号。
tickAnchorChanged(anchor) anchor – float 刻度线布局发生变化时,会发出此信号。
tickCountChanged(tickCount) tickCount – int 当tickCount指定的轴上的刻度线数量发生变化时,会发出此信号。
tickIntervalChanged(interval) interval – float 刻度线数发生变化时,会发出此信号。
tickTypeChanged(type) type – TickType 刻度发生变化时,会发出此信号。

QLogValueAxis

对数轴 QLogValueAxis 是一个非线性值变化坐标轴它是基于数量级的非线性标尺轴上的每一个刻度线都是由前一个刻度线的值乘以一个固定的值而得到的。

1
2
3
from PySide6.QtCharts import QLogValueAxis

QLogValueAxis(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

如果QLogValueAxis 连接的数据序列中含有 0或负数,则该数据序列不会被绘制。
QLogValueAxis 的方法不多,主要是:

  • 用setBase(float)方法设置对数的基;
  • 用setLabelFormat(str)方法设置标签格式;
  • 用setMin(float)方法、setMax(float)方法或setRange(float,float)方法设置幅度范围,
  • 用setMinorTickCount(int)方法设置次网格的数量;
  • 用tickCount()方法和 minorTickCount()方法分别获取网格和次网格的数量。

QLogValueAxis 的信号有

信号 参数 说明
baseChanged(base) base – float 当轴的对数基数改变时,发出该信号。
labelFormatChanged(format) format – str 当轴标签的格式更改时,会发出此信号。
maxChanged(max) max – float 当轴的最大值(由max指定)发生变化时,会发出此信号。
minChanged(min) min – float 当轴的最小值(由min指定)发生变化时,会发出此信号。
minorTickCountChanged(minorTickCount) minorTickCount – int 当minorTickCount指定的轴上的次要刻度线数量发生变化时,会发出此信号。
rangeChanged(min, max) min – float
max – float
当轴的最小值或最大值(由最小值和最大值指定)发生变化时,会发出此信号。
tickCountChanged(tickCount) tickCount – int 当tickCount指定的轴上的刻度线数量发生变化时,会发出此信号。

下面的程序,横坐标用数值坐标、纵坐标用对数坐标绘制图表,并对横坐标和纵坐标的显示进行设置,程序运行结果如图所示

image-20230312182102327

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 18:07
# File_name: 06-对数轴 QLogValueAxis.py


import sys, random
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PySide6 import QtCharts
from PySide6.QtCore import Qt


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(1000, 600)
v = QVBoxLayout(self)
chartView = QtCharts.QChartView(self)
v.addWidget(chartView) # 创建图表视图控件
chart = QtCharts.QChart() # 创建图表
chartView.setChart(chart) # 图表控件中设置图表
chart.setTitle("随机数据") # 设置图表的标题
lineSeries = QtCharts.QLineSeries() # 创建折线数据序列
lineSeries.setName("随机序列") # 设置数据序列的名称
random.seed(10000)
for i in range(101):
lineSeries.append(i, 100000 * random.random()) # 数据序列中添加数据

chart.addSeries(lineSeries) # 图表中添加数据序列
axis_x = QtCharts.QValueAxis() # 创建数值坐标轴
axis_x.setTitleText("Numbers") # 设置坐标轴的标题
axis_x.setTitleBrush(Qt.black)
axis_x.setLabelsColor(Qt.black)
axis_x.setRange(0, 100) # 设置坐标轴的范围
axis_x.setTickCount(10) # 设置刻度的数量
axis_x.applyNiceNumbers() # 应用智能刻度标签
axis_x.setLinePenColor(Qt.black) # 设置坐标轴的颜色

pen = axis_x.linePen() # 获取坐标轴的钢笔
pen.setWidth(2) # 设置钢笔的宽度
axis_x.setLinePen(pen) # 设置坐标轴的钢笔
axis_x.setGridLineColor(Qt.gray) # 设置网格线的颜色
pen = axis_x.gridLinePen() # 获取网格线的钢笔
pen.setWidth(2) # 设置钢笔的宽度
axis_x.setGridLinePen(pen) # 设置网格线的宽度
axis_x.setMinorTickCount(3) # 设置次刻度的数量
axis_x.setLabelFormat("% 5,1f") # 设置标签的格式

axis_y = QtCharts.QLogValueAxis() # 建立对数坐标轴
axis_y.setBase(10.0) # 定义对数基
axis_y.setMax(100000.0) # 设置最大值
axis_y.setMin(100.0) # 设置最小值
axis_y.setTitleText("随机数据") # 设置标题
axis_y.setMinorTickCount(9) # 设置次网格线的数量
axis_y.setLabelFormat("%6d") # 设置格式

chart.setAxisX(axis_x, lineSeries) # 设置坐标轴的数据
chart.setAxisY(axis_y, lineSeries) # 设置坐标轴的数据


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWidget()

win.show()
sys.exit(app.exec())

QBarCategoryAxis

QBarCategoryAxis 主要用于定义条形图的坐标轴,添加条目也可用于定义折线图的坐标轴。

QBarCategoryAxis 的常用方法如表所示。

1
2
3
from PySide6.QtCharts import QBarCategoryAxis

QBarCategoryAxis(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None

QBarCategoryAxis 的信号有

信号 参数 说明
categoriesChanged() 当轴的类别发生变化时,会发出此信号。
countChanged() 当轴的类别数发生变化时,会发出此信号。
maxChanged(max) max – str 当轴的最大值发生变化时,会发出此信号。
minChanged(min) min – str 当轴的最小值发生变化时,会发出该信号。
rangeChanged(min, max) min – str
max – str
当轴的最小值或最大值发生变化时,会发出该信号。

下面的程序,在一个图表中添加条形图和折线图,条形图和折线图使用相同的坐标轴程序运行结果如图所示。

image-20230312184409176

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 18:32
# File_name: 07-条形图的坐标轴QBarCategoryAxis.py


from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
import sys
from PySide6.QtCore import Qt
from PySide6 import QtCharts


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(1200, 600)
v = QVBoxLayout(self)
self.chartView = QtCharts.QChartView(self) # 创建图表视图控件
v.addWidget(self.chartView)
self.chart = QtCharts.QChart() # 创建图表
self.chartView.setChart(self.chart) # 将图表加人到图表视图控件中

set1 = QtCharts.QBarSet("一组销售额") # 创建数据项
set1.append([12, 34, 23, 45]) # 添加数据
set2 = QtCharts.QBarSet("二组销售额") # 创建数据项
set2.append([24, 33, 42, 41]) # 添加数据
set3 = QtCharts.QBarSet("三组销售额") # 创建数据项
set3.append([21, 44, 23, 40]) # 添加数据

self.barSeries = QtCharts.QBarSeries() # 创建数据序列
self.barSeries.append([set1, set2, set3]) # 添加数据项
self.lineSeries = QtCharts.QLineSeries() # 创建数据序列
self.lineSeries.setName("去年季度总额")
self.lineSeries.append(0, 32) # 添加数据
self.lineSeries.append(1, 46)
self.lineSeries.append(2, 43)
self.lineSeries.append(3, 48)
self.chart.addSeries(self.barSeries) # 图表中添加数据序列
self.chart.addSeries(self.lineSeries) # 图表中添加数据序列

# 创建坐标轴
self.barCategoryAxis = QtCharts.QBarCategoryAxis()
self.chart.addAxis(self.barCategoryAxis, Qt.AlignmentFlag.AlignBottom) # 图表中添加坐标轴
self.barCategoryAxis.append(["第一季度", "第二季度", "第三季度", "第四季度"])

self.valueAxis = QtCharts.QValueAxis() # 创建数值坐标轴
self.chart.addAxis(self.valueAxis, Qt.AlignmentFlag.AlignRight) # 图表中添加坐标轴
self.valueAxis.setRange(0, 50) # 设置坐标轴的数值范围

self.barSeries.attachAxis(self.valueAxis) # 数据项与坐标轴关联
self.barSeries.attachAxis(self.barCategoryAxis) # 数据项与坐标轴关联
self.lineSeries.attachAxis(self.valueAxis) # 数据项与坐标轴关联
self.lineSeries.attachAxis(self.barCategoryAxis) # 数据项与坐标轴关联


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWidget()

win.show()
sys.exit(app.exec())

QCategoryAxis

与QBarCategoryAxis 不同的是,QCategoryAxis 坐标轴可以定义每个条目的宽度,常用来放在竖直轴上,实现坐标轴不等分。

1
2
3
from PySide6.QtCharts import QCategoryAxis

QCategoryAxis(parent: Union[PySide6.QtCore.QObject, NoneType]= None) -> None
QCategoryAxis 的常用方法
  • 用append(label:str,categoryEndValue:float)方法添加条目,其中 label是条目名称,categoryEndValue 是条目的终止值,一个条目的宽度是两个相邻条目的终止值的差,因此后加人的条目的终止值一定要大于先加入的条目的终止值;
  • 用setStartValue(min: loat)方法设置坐标轴的起始值;
  • 用startValue(categoryLabel=)方法获取条目的起始值;
  • 用endValue(str)方法获取条目的终止值,
  • 用setLabelsPosition(QCategoryAxis.AxisLabelsPosition)方法设置条目标签的位置,参数可取:
    • QCategoryAxis.AxisLabelsPositionCenter(标签在条目中间位置)
    • QCategoryAxis.AxisLabelsPositionOnValue(标签在条目的最大值处)
QCategoryAxis的方法与参数类型 返回值的类型 说明
append(label: str,categoryEndValue: float) None 添加条目
categoriesLabels() ListCstr] 获取条目列表
count() int 获取条目的数量
endValue(categoryLabel:str) float 获取指定条目的终止值
remove(label:str) None 移除指定的条目
replaceLabel(oldLabel: str,newLabel: str) None 用新条目替换旧条目
setLabelsPosition(QCategoryAxis. AxisLabelsPosition) None 设置标签的位置
setStartValue(min:float) None 设置条目的最小值
stariValue(categoryLabel:str=’) float 获取指定条目的起始值
QCategoryAxis的信号
信号 参数 说明
categoriesChanged() 当轴的类别发生变化时,会发出此信号。
labelsPositionChanged(position) position – AxisLabelsPosition 标签位置更改,会发出此信号。
QCategoryAxis例子

下面的程序是将 QCategoryAxis 轴放在左侧,QCategoryAxis 轴的条目是销售等级分为“不及格”“及格”“良好”“优秀”和“超出预期”每个等级的宽度并不相等。程序运行结果如图所示。

image-20230312192018568

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 18:51
# File_name: 08-QCategoryAxis例子.py


from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
import sys
from PySide6 import QtCharts
from PySide6.QtCore import Qt


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
v = QVBoxLayout(self)
self.chartView = QtCharts.QChartView(self) # 创建图表视图控件
v.addWidget(self.chartView)
self.chart = QtCharts.QChart() # 创建图表
self.chartView.setChart(self.chart) # 将图表加入到图表视图控件中

set1 = QtCharts.QBarSet("一组销售额") # 创建数据项
set1.append([12, 34, 23, 45]) # 添加数据
set2 = QtCharts.QBarSet("二组销售额") # 创建数据项
set2.append([24, 33, 42, 41]) # 添加数据
set3 = QtCharts.QBarSet("三组销售额") # 创建数据项
set3.append([21, 44, 23, 40]) # 添加数据

self.barSeries = QtCharts.QBarSeries() # 创建数据序列
self.barSeries.append([set1, set2, set3]) # 添加数据项
self.chart.addSeries(self.barSeries) # 图表中添加数据序列

self.barCategoryAxis = QtCharts.QBarCategoryAxis() # 创建坐标轴
self.chart.addAxis(self.barCategoryAxis, Qt.AlignBottom) # 图表中添加坐标轴
self.barCategoryAxis.append(["第一季度""第二季度", "第三季度", "第四季度"])
self.categoryAxis = QtCharts.QCategoryAxis() # 创建数值坐标轴
self.categorvAxis = self.chart.addAxis(self.categoryAxis, Qt.AlignmentFlag.AlignLeft) # 图表中添加坐标轴

self.categoryAxis.setRange(0, 60) # 设置坐标轴的数值范围
self.categoryAxis.append("不及格", 10) # 添加条目
self.categoryAxis.append("及格", 20) # 添加条目
self.categoryAxis.append("良好", 25) # 添加条目
self.categoryAxis.append("优秀", 42) # 添加条目
self.categoryAxis.append("超出预期", 60) # 添加条目
self.categoryAxis.setStartValue(5) # 指定起始值

self.barSeries.attachAxis(self.categoryAxis) # 数据项与坐标轴关联
self.barSeries.attachAxis(self.barCategoryAxis) # 数据项与坐标轴关联


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWidget()

win.show()
sys.exit(app.exec())

QDateTimeAxis

QDateTimeAxis 轴用于设置时间坐标轴可用于XY图。

QDateTimeAxis 的常用方法

QDateTimeAxis 的常用方法如表所示,主要方法:

  • 用setFormat(format:str)方法设置显示格式,显示格式可参考QDateTime 的格式;
  • 用setMin(min:QDateTime)和 setMax(max:QDateTime)方法设置坐标轴显示的最小时间和最大时间;
  • 用setTickCount(count;int)方法设置坐标轴的刻度数量。

在定义数据序列的值时,例如 QLineSeries 数据序列需要把X值转换成毫秒可以用QDateTime的 toMSecsSinceEpoch()方法转换否则数据序列与时间坐标轴的关联会出问题,时间坐标轴显示的时间不准确,可参考下面的实例

QDateTimeAxis的方法及参数类型 返回值的类型 说明
setFormat(format:str) None 设置显示时间的格式
format() Str 获取格式
setMax(max: QDateTime) None 设置坐标轴的最大时间
max() QDateTime 获取最大时间
setMin(min:QDateTime) None 设置坐标轴的最小时间
min() QDateTime 获取最小时间
setRange(min: QDateTime,max: QDateTime) None 设置范围
setTickCount(count:int) None 设置刻度数量
tickCount() int 获取刻度数量
QDateTimeAxis的信号
信号 参数 说明
formatChanged(format) format – str 当轴的格式改变时,会发出此信号。
maxChanged(max) max – PySide6.QtCore.QDateTime 当轴的最大值(由max指定)发生变化时,会发出此信号。
minChanged(min) min – PySide6.QtCore.QDateTime 当轴的最小值(由min指定)发生变化时,会发出此信号。
rangeChanged(min, max) min – PySide6.QtCore.QDateTime
max – PySide6.QtCore.QDateTime
当轴的最小值或最大值(由最小值和最大值指定)发生变化时,会发出此信号。
tickCountChanged(tick) tick – int 当tickCount指定的轴上的刻度线数量发生变化时,会发出此信号。
QDateTimeAxis的实例

下面的程序用菜单打开 Excel 文件 price.xlsx,读取数据并绘制价格走势图,pricexlsx文件中第1列是时间,第2列和第 3列是价格。程序运行结果如图8-12所示。

image-20230312195258054

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 19:26
# File_name: 09-QDateTimeAxis的实例.py


import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QMenuBar, QFileDialog
from PySide6.QtCharts import QChartView, QChart, QLineSeries, QValueAxis, QDateTimeAxis
from PySide6.QtCore import QDateTime
from openpyxl import load_workbook


class MyWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(1200, 800)
self.setupUi()

def setupUi(self):
menuBar = QMenuBar()
fileMenu = menuBar.addMenu("文件(&E)")
fileMenu.addAction("打开(&O)").triggered.connect(self.action_open_triggered)
fileMenu.addSeparator()
fileMenu.addAction("退出(&Q)").triggered.connect(self.close)
chartView = QChartView()
v = QVBoxLayout(self)
v.addWidget(menuBar)
v.addWidget(chartView)
self.chart = QChart()
chartView.setChart(self.chart)

def action_open_triggered(self): # 打开 Excel文档,读取数据
fileName, fil = QFileDialog.getOpenFileName(self, "打开测试文件", ".", "Excel(*.xlsx)")
if fileName and fil == "Excel(*.xlsx)":
print("进来了")
dateTimeList = list() # 时间列表
valueList_1 = list() # 数值列表
valueList_2 = list() # 数值列表

wb = load_workbook(fileName)
ws = wb.active
for row in ws.rows:
valueList_1.append(row[1].value) # 添加数值数据
valueList_2.append(row[2].value) # 添加数值数据
dateTimeList.append(QDateTime(row[0].value)) # 添加时间数据

self.plot(dateTimeList, valueList_1, valueList_2) # 调用绘制图表函数

def plot(self, dateTimeList, valueList_1, valueList_2): # 绘制图表的函数
lineSeries_1 = QLineSeries(self) # 第1个数据序列
lineSeries_1.setName("价格1")
lineSeries_2 = QLineSeries(self) # 第2个数据序列
lineSeries_2.setName("价格2")

for i in range(len(dateTimeList)):
msec = float(dateTimeList[i].toMSecsSinceEpoch()) # 换算成毫秒
lineSeries_1.append(msec, valueList_1[i]) # 第1个数据序列添加数据
lineSeries_2.append(msec, valueList_2[i]) # 第2个数据序列添加数据

dateTimeAxis = QDateTimeAxis(self) # 创建时间坐标轴
dateTimeAxis.setRange(dateTimeList[0], dateTimeList[len(dateTimeList) - 1])
dateTimeAxis.setFormat('yyyy - MM -.dd HH:mm')
dateTimeAxis.setTickCount(8)
valueAxis = QValueAxis(self) # 创建数值坐标轴

self.chart.removeAllSeries()
self.chart.removeAxis(self.chart.axisX())
self.chart.removeAxis(self.chart.axisY())
self.chart.addSeries(lineSeries_1)
self.chart.addSeries(lineSeries_2)

self.chart.setAxisX(dateTimeAxis, lineSeries_1) # 图表设置 X轴
self.chart.setAxisY(valueAxis, lineSeries_1) # 图表设置Y轴
self.chart.setAxisX(dateTimeAxis, lineSeries_2) # 图表设置 X轴
self.chart.setAxisY(valueAxis, lineSeries_2) # 图表设置Y轴


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()

win.show()
sys.exit(app.exec())

图例与图例上的标志

图例QLegend

examples_percentbarchart_legend.png

如图图例 QLegend用于定义图表中图例的位置颜色可见性和序列的标志形状等。

图例QLegend继承自 QGraphicsWidget,用图表 QChart 的 legend()方法获取图表上的图例对象;然后用图例 QLegend 提供的方法对图例进行设置。不能单独创建图例对象

图例QLegend的方法

图例QLegend 的常用方法如表所示,主要方法介绍如下

  • 用setAlignment(alignment;Qt.Alignment)方法可以设置图例在图表的位置,如参数取:

    • Qt.AlignTop 把图例放在图表的上位置。
    • Qt.AlignBottom 把图例放在图表的下位置。
    • Qt.AlignLeft 把图例放在图表的左位置。
    • Qt.AlignRight 把图例放在图表的右位置。
  • 用setMarkerShape(shape: QLegend.MarkerShape)方法设置数据序列标志的形状,参数可取:

    • QLegend.MarkerShapeDefault(使用默认形状) 由 QLegend 确定的默认形状用于标记。此值仅支持单个 QLegendMarker 项。
    • QLegend.MarkerShapeRectangle 使用矩形标记。标记大小由字体大小决定。
    • QLegend.MarkerShapeCircle 使用圆形标记。标记大小由字体大小决定。
    • QLegend.MarkerShapeFromSeries(根据数据序列的类型确定形状)标记形状由序列确定。对于散点序列,图例标记看起来像散点,并且与点的大小相同。对于直线或样条线系列,图例标记看起来像直线的一小部分。对于其他系列类型,将显示矩形标记。如果为序列指定了 a,则将显示 ,其大小将由系列标记大小确定。lightMarkerlightMarker
    • QLegend.MarkerShapeRotatedRectangle 使用旋转的矩形标记。标记大小由字体大小决定。
    • QLegend.MarkerShapeTriangle 使用三角形标记。标记大小由字体大小决定。
    • QLegend.MarkerShapeStar 使用星形标记。标记大小由字体大小决定。
    • QLegend.MarkerShapePentagon 使用五边形标记。标记大小由字体大小决定。
    • 对应值分别是0~7当使用矩形或圆形时,矩形或圆形的尺寸由字体的尺寸决定;当选择数据序列的类型时,如果数据序列是折线或样条曲线,则形状是线段,如果是散列图,则形状是散列图上的点的形状,其他情况时形状是矩形。
  • 用setInteractive(interactive:bool)方法可以将图例设置成交互模式

    • 用detachFromChart()方法使图例与图表失去关联,则可以用鼠标移动图例和调整图例的尺寸。
  • 用markers(series;QAbstractSeries=None)方法可以获取图例上数据序列的标志对象列表,可以对每个标志对象进行更详细的设置

QLegend 的方法及参数类型 说 明
setAlignment(alignment: Qt.Alignment) 设置图例在QChart中的位置
setBackgroundVisible(visible:bool=True) 设置图例的背景是否可见
setBorderColor(color:Union[QColor,Qt.GlobalColor, str]) 在背景可见时,设置边框的颜色
setBrush(brush: Union[QBrush, Qt.BrushStyle, Qt.GlobalColor,QColor,QGradient,QImage,QPixmap]) 设置画刷
setColor(color:Union[QColor,Qt.GlobalColor,str]) 设置填充色
setFont(font:Union[QFont,str,Sequence[str]]) 设置字体
setLabelBrush(brush: Union[QBrush, QColor, QGradient]) 设置标签画刷
setLabelColor(color: Union[QColor, Qt.GlobalColor, str]) 设置标签颜色
setMarkerShape(shape:QLegend. MarkerShape) 设置数据序列标志的形状
markerShape() 获取标志的形状 QLegend. MarkerShape
setPen(pen:Union[QPen,Qt.PenStyle,QColor]) 设置边框的钢笔
setReverseMarkers(reverseMarkers:bool=True) 设置数据序列的标志是否反向
setToolTip(str) 设置提示信息
setShowToolTips(show:bool) 设置是否显示提示信息
detachFromChart() 使图例与图表失去关联
attachToChart() 使图例与图表建立关联
isAttachedToChart() 获取图例
setInteractive(interactive: bool) 设置图例是否是交互模式
markers(series:QAbstractSeries=None) 获取图例中标志列表 list[QLegendMarker]
图例QLegend 的信号

图例QLegend的信号如表所示

QLegend的信号及参数类型 说 .明
attachedToChartChanged(attached:bool) 图例与图表的关联状态发生改变时发送信号
backgroundVisibleChanged(visible:bool) 背景可见性发生改变时发送信号
borderColorChanged(color:QColor) 背景颜色发生改变时发送信号
colorChanged(color:QColor) 颜色发生改变时发送信号
fontChanged(font:QFont) 字体发生改变时发送信号
labelColorChanged(color:QColor) 标签颜色发生改变时发送信号
markerShapeChanged(QLegend.MarkerShape) 标志形状发生改变时发送信号
reverseMarkersChanged(reverseMarkers:bool) 标志反转状态发生改变时发送信号
showToolTipsChanged(showToolTips:bool) 提示信息显示状态发生改变时发送信号

图例的标志QLegendMarker

用图例的 markers(series:QAbstractSeries=None)方法可以获取图例上的数据序列标志对象列表 list[QLegendMarker]可以对每个标志对象进行详细的设置。

QLegendMarker 继承自QObject,继承自 QLegendMarker 的类有

  • QXYLegendMarker
  • QAreaLegendMarker
  • QBarLegendMarker
  • QBoxPlotLegendMarker
  • QCandlestickLegendMarker
  • QPieLegendMarker

除 QBarLegendMarker和QPieLegendMarker 外,这些派生类没有自己特有的方法和信号,都是继承QLegendMarker 的方法和信号

图例标志 QLegendMarker 的方法

图例标志 QLegendMarker 的常用方法如所示,主要方法是

  • 用setShape(shape:QLegend.MarkerShape)方法设置形状;

  • 用type()方法获取标志类型返回值是QLegendMarker.LegendMarkerType 的枚举值,可取以下值,分别对应值0~5,根据类型可以给标志设置不同的形状

    标记 说明
    QLegendMarker.LegendMarkerTypeArea 区域系列的图例标记。
    QLegendMarker.LegendMarkerTypeBar 条形图集的图例标记。
    QLegendMarker.LegendMarkerTypePie 饼图扇区的图例标记。
    QLegendMarker.LegendMarkerTypeXY 直线、样条或散点序列的图例标记。
    QLegendMarker.LegendMarkerTypeBoxPlot 箱形图系列的图例标记。
    QLegendMarker.LegendMarkerTypeCandlestick 烛台系列的图例标记。
QLegendMarker的方法及参数类型 返回值的类型 说明
brush() QBrush 获取画刷
font() QFont 获取字体
isVisible() bool 获取是否可见
label() str 获取标签
labelBrush() QBrush 获取标签画刷
pen() QPen 获取钢笔
series() QAbstractSeries 获取关联的数据序列
setBrush(brush: Union[QBrush, QColor,QGradient,QPixmap]) None 设置画刷
setFont(font:Union[QFont,str]) None 设置字体
setLabel(label: str) None 设置标签
setLabelBrush(brush:Union[QBrush, QColor,QGradient,QPixmap]) None 设置标签的画刷
setPen(pen: Union[QPen,QColor]) None 设置钢笔
setShape(shape: QLegend. MarkerShape) None 设置形状
setVisible(visible:bool) None 设置可见性
shape() QLegend. MarkerShape 获取形状
type() QLegendMarker. LegendMarker1ype 获取类型·
图例标志 QLegendMarker 的信号
信号 说明
brushChanged() 当图例标记的画笔发生变化时,会发出此信号。
clicked() 单击图例标记时会发出此信号。
fontChanged() 当图例标记的(标签)字体更改时,会发出此信号。
hovered(status) status – bool
当鼠标悬停在图例标记上时,会发出此信号。当鼠标在标记上移动时,状态变为真,当鼠标再次移开时,状态将变为假。
labelBrushChanged() 当图例标记的标签画笔发生变化时,会发出此信号。
labelChanged() 当图例标记的标签发生更改时,会发出此信号。
penChanged() 当图例标记的笔发生变化时,会发出此信号。
shapeChanged() 当图例标记的形状发生变化时,会发出此信号。
visibleChanged() 当图例标记的可见性发生变化时,会发出此信号。

图例QLegend 和图例标志OLegendMarker的应用实例

下面的代码生成折线图和条形图,对图表中的图例进行设置。程序运行结果如图所示。

image-20230312203821921

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 20:21
# File_name: 10-图例QLegend 和图例标志OLegendMarker的应用实例.py


import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PySide6.QtCore import Qt.QPointF
from PySide6 import QtCharts


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.resize(800, 600)
v = QVBoxLayout(self)
self.chartView = QtCharts.QChartView(self) # 创建图表视图控件
v.addWidget(self.chartView)
self.chart = QtCharts.QChart() # 创建图表
self.chartView.setChart(self.chart) # 将图表加入到图表视图控件中

set1 = QtCharts.QBarSet("一组销售额") # 创建数据项
set1.append([12, 34, 23, 45]) # 添加数据
set2 = QtCharts.QBarSet("二组销售额") # 创建数据项
set2.append([24, 33, 42, 41]) # 添加数据

self.barSeries = QtCharts.QBarSeries() # 创建数据序列
self.barSeries.append([set1, set2]) # 添加数据项
self.lineSeries = QtCharts.QLineSeries() # 创建数据序列
self.lineSeries.setName("去年季度总额")

self.lineSeries.append([QPointF(0, 32), QPointF(1, 46), QPointF(2, 43), QPointF(3, 48)])

self.chart.addSeries(self.barSeries) # 图表中添加数据序列
self.chart.addSeries(self.lineSeries) # 图表中添加数据序列

self.barCategoryAxis = QtCharts.QBarCategoryAxis() # 创建坐标轴
self.chart.addAxis(self.barCategoryAxis, Qt.AlignmentFlag.AlignBottom) # 图表中添加坐标轴
self.barCategoryAxis.append(["第一乘度""第二季度", "第三季度", "第四季度"]) # 添加条目

self.valueAxis = QtCharts.QValueAxis()
self.valueAxis.setRange(0, 50)
self.chart.addAxis(self.valueAxis, Qt.AlignmentFlag.AlignLeft)

self.barSeries.attachAxis(self.valueAxis) # 数据项与坐标轴关联
self.barSeries.attachAxis(self.barCategoryAxis) # 数据项与坐标轴关联
self.lineSeries.attachAxis(self.valueAxis) # 数据项与坐标轴关联
self.lineSeries.attachAxis(self.barCategoryAxis) # 数据项与坐标轴关联

# 以下是对图例的设置
legend = self.chart.legend()
legend.setAlignment(Qt.AlignBottom)
legend.setBackgroundVisible(True)
legend.setBorderColor(Qt.red)
legend.setColor(Qt.yellow)
pen = legend.pen()
pen.setWidth(4)
legend.setPen(pen)
legend.setToolTip("销售团队的销售额对比")
legend.setShowToolTips(True)
legend.setMarkerShape(legend.MarkerShape.MarkerShapeFromSeries)
for i in legend.markers():
font = i.font()
font.setPointSize(12)
i.setFont(font)

if i.type() == QtCharts.QLegendMarker.LegendMarkerType.LegendMarkerTypeBar:
i.setShape(QtCharts.QLegend.MarkerShape.MarkerShapeRotatedRectangle)
else:
i.setShape(QtCharts.QLegend.MarkerShape.MarkerShapeFromSeries)


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWidget()

win.show()
sys.exit(app.exec())

数据库操作

数据库(database)是统一管理的、有组织的可共享的大量数据的集合。

数据有多种形式,如文字、数值、符号、图形、图像及声音等,可以按照第 7章介绍的方法以文件形式存储数据,但这种文件管理方法有很大的不足,例如它使得数据通用性差,不便于移植,在不同文件中存储大量重复信息,从而浪费存储空间,查询数据和更新数据不便等。

数据库不是针对具体的应用程序,而是立足于数据本身的管理,它将所有数据保存在数据库中,进行科学的组织,并借助于数据库管理系统,通过 SQL 与各种应用程序或应用系统连接,使之能方便地使用数据库中的数据。

PySide 提供了对常用数据库的驱动,可以从数据库中进行查询、读取写人、修改、删除数据等操作,同时提供了可视化的控件和数据库数据模型,可以将数据从数据库读取到数据模型中,然后用Model/View 结构在图形界面中对数据进行操作。

SQL与数据库连接

数据库将数据存储在一个或多个表格中,管理这个数据库的软件称为数据库管理系统(database management system,DBMS)。主流的数据库管理系统有 OracleInformix、Sybase,SQL Server,PostgreSQL、MySQL、Access、FoxPro 和 SQLite 等。关系型数据库管理系统一般都支持结构化查询语言(structured query language,SQL),SQL 是数据库的基础,通过它可以实现对关系型数据库进行查询、新增、更新、删除、求和和排序等操作。

SQL

关系型数据库由数据表(table)构成,数据表的一行数据称为字段,可以在数据库中添加和删除数据表,在数据表中可以查询、添加和删除字段。要对数据库进行操作,首先需要掌握 SQL的格式。SQL可以分为以下几类

  • 数据定义语言(data definition language,DDL)。DDL是SQL中定义数据结构和数据库对象的语言,主要关键字有 CREATE、ALTER和DROP。
  • 数据操纵语言(data manipulation language,DML)。DML是SQL中操纵数据库中数据的语言,可对数据库中的数据进行插入、删除、更新和选择,主要关键字有INSERTUPDATE DELETE 和 SELECT。
  • 事务控制语言(transaction control language,TCL)。TCL 用于管理 DML对数据所作的修改,主要关键字有提交 COMMIT 和撤销 ROLLBACK。对数据库的操作需要用COMMIT进行确认,事务一经提交就不能撤销如果要在提交前撤销对数据库的操作,可以用ROLLBACK 来“回滚”到相应事务开始时的状态
  • 数据控制语言(data control language,DCL)。DCL是对数据访问权限进行控制定义安全级别及创建用户的语言,主要关键字有 GRANT 和 REVOKESQL由关键字构成,常用的关键字如表 10-1 所示,更高级的 SOL 请参考相关书籍SQL的关键字不区分大小写,例如 CREATE与 Create 或 create 相同,SQL的每个指令以分号“;”结束。
关键字 用法 说 明
CREATE CREATE DATABASE database_name 新建数据库
CREATE TABLE table_name(column_ namel data_type, column_name2 data_ type,…) 新建数据表格,同时指定列(字段)名和数据 类型
ALTER ALTER TABLE table _ name ADD column_name datatype 在已经存在的表中增加列(字段)
ALTER TABLE table_name DROP COLUMN column_name 在已经存在的表中移除列(字段)
DROP DROP DATABASE database_name 移除数据库
DROP TABLE table_name 在数据库中移除数据表
SELECT . SELECT column_name(s)FROM table_ name 从指定表中获取指定的列的数据 SELECT语句返回 WHERE 子句中条件为
WHERE SELECT column FROM table WHERE column condition true 的数据,可使用=、<>、>、<、>=、<=、 LIKE,可用AND、OR或NOT连接逻辑表达式,也可用Between…And..来设置范围,还可以用LIKE与通配符搭配,其中%代表零个或多个字符,仅代表一个字符,[charlist]代表字符列中的任何单一字符,[^charlist][! charlist]表示不在字符列中的任何单一字符
DISTINCT SELECT DISTINCT column-name(s) FROM table-name 当column-name(s)中存在重复值时,返回结 果仅留下一个
ORDER BY SELECT column-name(s) FROM table- name ORDER BY ASC | DESC 设置返回值是升序还是降序,默认是升序。 ASC是升序,DESC是降序
GROUP BY SELECT column,SUM(column)FROM table GROUP BY column 对结果进行分组,常与汇总函数一起使用
HAVING SELECT column,SUM(column)FROM table GROUP BY column HAVING SUM(column) condition value 指定群组或汇总的搜寻条件,通常与 GROUPBY子句同时使用。不使用GROUP BY时,HAVING 则与 WHERE 子句功能 相似
INSERT INTO INSERT INTO table _name VALUES(valuel,value2,…) 在表中插入一行 >
INSERT INTO INSERT INTO table_name(columnl, column2,…) VALUES(valuel,value2,…) 在表中插入一行 >
UPDATE UPDATE table_name SET column_name = new_value WHERE column_name = value 更新表中的数据
DELETE DELETE FROM table_name WHERE column_name = value 删除表中的数据·
COUNT SELECT COUNT(column _ name) FROM table_name 返回结果集中行的数量
SUM SELECT SUM(column_ name)FROM table_name 返回指定列中数值的总和,或仅DISTINCT 值,SUM仅可用于数值列
AVG SELECT AVG(column_ name)FROM table_name 返回指定列中数据的平均值,忽略空行
MAX SELECT MAX(column_name) FROM table_name 返回指定列中数据的最大值
MIN SELECT MIN(column_name)FROM table_name 返回指定列中数据的最小值 c

除关键字外,SQL 中也可以用到一些函数,常用的函数如表所示

SQL函数格式 说明 SQL函数格式 说明
CEIL(value) 大于或等于给定数值的 最小整数 FLOOR(value) 小于或等于给定数值的最 大整数
ABS(value) 绝对值 NOW() 当前日期
PI() 圆周率 REVERSE(sUr) 颠倒字符串
COS(value) 余弦函数 LOWER(str) 字符串转成小写
COSH(value) 反余弦函数 UPPER(str) 字符串转成大写
SIN(value) 正弦函数 LTRIM(str) 去除左边空格
SINH(value) 反正弦函数 RTRIM(str) 去除右边空格
TAN(value) 正切函数 LENGTH(str) 字符串的长度
TANH(value) 反正切函数 LEFT(str,n) 字符串左侧n个字符
EXP(value) 以e为底的指数函数 RIGHT(str,n) 字符串右侧n个字符
LOG(value) 自然对数函数 STR(value,n) . 将数值转换成字符串,n是 字符串的长度
POWER(valuel, value2) 指数函数 ASCII(str) 字符串中第1个字符的 ASCII值
SIGN(value) 符号函数 REPLICATE(str,n) 复制字符串n次
SQRT(value) 开方 SPACE(n) n个空格构成的字符串
MOD(valuel,value2) 求余数 SUBSTRING(str, start,end) 从字符串中获取子字符串
ROUND(value,n) 按照n指定的小数位进 行四舍五人 REPLACE(str, strl, str2) 用字符串 str2替换字符串 str中的子字符串 str1
RAND([n]) 生成随机数 CONCAT(str1,str2,…) 连接字符串

SQLite数据库连接

SQLite数据库是一个常用的开源、跨平台轻量化本机版数据库,可以作为嵌人式数据库使用。

Python 自带的 sqlite3 可以实现对 SQLite 数据库的查询使用前需要用import sqlite3 语句导人 sglite3。下面介绍 sqlite3 的使用方法。

sqlite3提供了两个基本的类:数据库连接 Connection 和游标Cursor。

用sqlite3的connect(database:str)方法打开一个已经存在的SQLite 数据库或新建一个数据库并返回Connection对象

  • 其中databaseName是本机上已经存储的数据库文件或者新建立的数据库文件名称,
  • 还可取”;memory:”表示在内存中创建临时数据库。

用Connection 对象的cursor()方法获取 Cursor 对象,用Cursor 对象提供的方法可以执行 SQL 指令。

数据库连接Connection 的常用方法

数据库连接Connection的常用方法如表所示主要方法是

  • 用cursor()创建并返回Cursor对象;用commit()方法提交对数据库的操作;
  • 用rollback()方法放弃自上次调用commit()方法后对数据库的操作。
Connection的方法及参数类型 说明
cursor() 创建并返回 Cursor 对象
commit() 提交当前的事务
interrupt() 停止还未执行的操作
rollback() 放弃对数据库的操作,返回到调用commit()时的状态
close() 关闭数据库
backup(target: Connection) 将数据备份到另外一个数据库中
execute(sql: str[,parameters]) 调用cursor()方法获取Cursor对象,并调用Cursor的execute()方法 执行一条SQL命令。parameters是SQL中的占位符的值
executemany(sql: str, sequence of parameters) 调用cursor()方法获取Cursor对象,并调用Cursor的 executemany()方 法执行多条 SQL命令
executescript(sql_script: str) 调用cursor()方法获取Cursor对象,并调用Cursor的 executeseript()方 法执行多条 SQL命令
create_function(name: str,num_ params:int,func:Function) 将func 函数定义成 SQL指令中可以使用的函数,其中 name 是SQL 中使用的函数名,num_params是函数参数的个数
1otal_changes 操作数据后,返回受影响的行的数量
游标Cursor 的常用方法

游标Cursor 用于执行 SQL 命令。Cursor 的常用方法如表所示,主要方法介绍如下

  • 执行一条SQL命令

    • 可以用execute(sql:str[;parameters])方法

      • parameters是可选的,用于SQL命令中有占位符的情况,占位符可取“?”。

      • parameters 的取值是序列(如元组、列表)

        1
        execute("insert into tableName values(?,?)",("ABC",2015));
      • 也可以在SQL命令中用名称做占位符,这时 parameters 是字典且字典的键是占位符的名称,例如

        1
        execute("select * from tableName where birthday= :year",("year"2015));
    • 用executemany(sql:str,sequence of parameters)方法可以重复执行一条 SQL命令,重复执行的次数是参数序列的长度 len(sequence of parameters),例如

      1
      2
      executemany("insert into tableName values(?,?)",(("A"2015),("B"2016)("C",2017))
      # 执行3次,占位符(?,?)依次取("A",2015),("B",2016)("C",2017)
  • 要执行多条 SQL 命令,需要用executescript(sql_script:str)方法,例如

    1
    executescript("insert into tableName values("A",2015); insert into tableNamevalues("B",2016);insert into tableName values("C",2017);")
  • 要获取数据表中的数据,可以用execute()方法执行SQL的SELECT命令

    • 也可用etchone()方法获取当前行的下一行对象,如果当前行是最后一行,则返回值是None;
    • 用fetchmany(size=cursor.arraysize)方法可以获取当前行后的多行记录
      • 如果没有给出行的数量,则用cursor.arraysize 属性值确定行数
      • 用fetchall()方法获取所有剩余的行。
Cursor的方法及参数类型 说 明
execute(sql: str[,parameters]) 执行一条 SQL命令,parameters 是SQL中的占位符的值
executemany(sql: str, sequence of parameters) 重复执行SQL命令,parameters是SQL中的占位符的值
executescrip1(sql_script: str) 执行多条SQL.命令
fetchone() 获取数据表中的下一行,返回由行数据构成的元组或 None
fetchmany(size=cursor. arraysize) 获取多行数据,参数size是要获取的行数,并返回多行数据构成的 列表
arraysize 设置或获取Letchmany()方法每次默认读取的行数
fetchall() 获取所有剩余的行,并返回多行数据构成的列表
connection 获取 Connection对象
lastrowid 获取用execute()方法执行sql指令INSERT或 REPLACE后,最后 插人的行的ID号,用executemany方法或 executescript()方法插人 行不改变 lastrowid 的值
close() 关闭游标,游标不可再使用
Python 的数据类型与SQLite 的数据类型的相互转换

SQLite 支持的数据类型较少,它的数据类型有NULL、INTEGER、REAL、TEXT和BLOB,在往SQLite 数据库中写入数据和从SQLite数据中读取数据时需要注意 Python和SQLite数据类型之间的转换。

Python 的数据类型与 SQLite 的数据类型的相互转换如表所示。

SQLite的TEXT数据类型转换成 Python 数据类型时,与数据库连接对象Connection的 text_factory 属性有关默认将TEXT数据类型转换成Python的 str 数据型

  • 如果设置context_factory=bytes,则TEXT类型将转换成 bytes 类型
Python数据类型 SQLite 数据类型 SQLite 数据类型 Python数据类型
None NULL NULL None
int INTEGER INTEGER int
float REAL REAL float
str TEXT TEXT 与Connection对象的属性text factory 有关,默认是str
bytes BLOB BLOB bytes
对SOLite数据库查询的应用实例

下面的程序建立一个数据库 student _score.db,建立一个表格 score,并输人4个学生的考试成绩,然后重新打开数据库,并输出结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 22:03
# File_name: 01- 对SOLite数据库查询的应用实例.py


import sqlite3

dbName = "d:/student score.db" # 数据库保存位置和数据库名称
con = sqlite3.connect(dbName) # 新建数据库链接
cur = con.cursor() # 创建游标

cur.execute("CREATE TABLE score(ID INTEGER,name TEXT,语文 REAL,数学 REAL))") # 执行一条 SQL 命令,创建表格
information =((2001, "张", 78, 89),(2002, "刘", 88, 82.5),(2003, "王", 78.5, 83),(2004, "张", 72, 5, 86)) # 学生考试信息
cur.executemany("INSERT INTO score VALUES((?,?,?,?) ,information)") # 执行多条 SQL命令
con.commit() # 提交事务
con.close() # 关闭数据库

sqlite3.connect(dbName) # 打开数据库
concur = con.cursor() # 创建游标
for row in cur.execute("SELECT * From score"): # 查询数据表中的内容
print(row)

cur.execute("SELECT * From score Where name ='张'") # 重新查询数据表中的内容
rows = cur.fetchall() # 获取数据表中的所有内容

for row in rows:
print(row)
con.close() # 关闭数据库

Pyside对数据库的操作

PySide可以驱动常用的关系型数据库;在对数据库进行操作之前需要用QSqlDatabase类建立对数据库的连接,然后再用QSlQuery 类执行SQL命令,实现对数据库的操作。

数据库连接QSglDatabase

在对数据库进行操作之前,需要先建立对数据库的连接。

数据库连接用QSqIDatabase类,用QSqlDatabase 创建实例的方法如下所示其中:

  • type 是数据库的驱动类型,可取的值如表所示。

    数据库驱动类型 说明
    QDB2 IBM DB2数据库,需要最低是7.1版本
    QIBASE Borland InterBase 数据库
    QMYSQL MySQL数据库
    QODBC 支持ODBC接口的数据库,包括 Microsoft SQL Server,例如 Access
    QPSQL PostgreSQL数据库,需要最低是7.3版本
    QSQLITE SQLite3 数据库
    QOCI Oracle 数据库(oracle call interface,OCI)
1
2
3
4
5
6
from PySide6.QtSql import QSqlDatabase

QSqlDatabase(self) -> None
QSqlDatabase(driver: PySide6.QtSql.QSqlDriver) -> None
QSqlDatabase(other: PySide6.QtSql.QSqlDatabase) -> None
QSqlDatabase(type: str) -> None

数据库连接 QSqlDatabase 的常用方法如表所示,主要方法介绍如下。

  • 不同的系统支持的数据库驱动类型也不同
    • 用静态方法 drivers()获取系统支持的驱动类型列表;
    • 用isDriverAvailable(name;str)方法获取某种驱动类型是否可用。
  • 用静态方法addDatabase(type: str,connectionName:str = gt_sql_ defaultconnection’)添加某种驱动类型的连接,其中参数 type 是驱动类型。
  • 对同一个数据库可以添加多个连接数据库连接的识别是通过连接名称 connectionName 来区分的,而不是关联的数据库。
    • 如果不输入连接名称,则该连接作为默认连接,将使用默认的连接名称qt_sql_default _connection 。
    • 用静态方法 removeDatabase(connectionName:str)可以根据连接名称删除数据库连接:
    • 用driverName()方法可以获取数据连接的驱动类型;
  • 用connectionName()方法可以获取数据库连接的名称;
    • 用静态方法 connectionNames()可以获得所有已经添加的连接的名称列表。
  • 在用open()方法打开数据库前
    • 需要分别用以下方法设置连接的数据库文件名、主机名、密码、端口号、用户名和连接参数:
      • setDatabaseName(name:str)
      • setHostName(host:str)
      • setPassword(password:str)
      • setPort(p: int)
      • ,setUserName(name:str)
      • setConnectOptions(options: str=)
    • 用open()方法打开数据库后再设置这些参数将不起作用。
      • 当然也可以先用close()方法关闭连接,设置这些参数后再用open()方法打开。
  • 在用setDatabaseName(name:str)方法打开SQLite 数据库时
    • 如果数据库不存在则创建新数据库参数name也可取:memory:在内存中临时创建数据库序运行结束后删除数据库。
    • 对于ODBC数据库:参数name是*dsn文件或连接字符串;
    • 对于Oracle 数据库name 参数是TNS 服务名称。
  • 用setConnectOptions(options:str=)方法设置数据库的参数,不同的驱动类型需要设置的参数也不同,例如 SQLite 数据库,可选参数有:
    • QSQLITE_BUSY_TIMEOUT
    • QSQLITE_OPEN_READONLY
    • QSQLITE_OPEN_URI
    • QSQLITEENABLE SHARED_CACHE
    • QSQLITE_ENABLE_REGEXP
    • QSQLITE_NOUSEEXTENDED_RESULT_CODES
    • 各参数值之间用分号“;”隔开,例如setConnectOptions(‘QSQLITE_BUSY_TIMEOUT=5.0; QSQLITE OPENREADONLY=true’)
  • 用tables(type:QSgLTableType=QSqlTables)方法获取数据库中存在的数据表名称列表,其中 type取值是QSql.TableType 的枚举值,可取:
    • QSlTables(对用户可见的所有表)
    • QSqlSystemTables(数据库使用的内部表)
    • QSlViews(对用户可见的所有视图)
    • QSqLAlITables(以上三种表和视图)。
  • 用setNumericalPrecisionPolicy(precisionPolicy: QSql. NumericalPrecisionPolicy)方法设置对数据库进行查询时默认的数值精度,参数precisionPolicy 可取:
    • QSql.LowPrecisionInt32(32位整数,忽略小数部分)
    • QSql.LowPrecisionInt64(64 位整数,忽略小数部分)
    • QSql.LowPrecisionDouble(双精度值,默认值)
    • QSqlHighPrecision(保持数据的原有精度)
  • 如果数据库支持事务操作,可以用transaction()方法开启事务;
  • 用exec(query:str-)方法或exec_(query:str=’)方法执行一条 SQL命令;
  • 用commit()方法提交事务;
    • 用rollback()方法放弃事务
  • 用lastError()方法获取最后的出错信息 QSqlError 对象用QSglError 的type()方法可以获取出错类型返回值是QSlError.ErrorType 的枚举值或-1(不能确定错误类型),QSqlError.ErrorType 的枚举值有以下值,其值分别对应0~4
    • QSqlError.NoError
    • QSqlError.ConnectionError(数据库连接错误)
    • QSqlError,StatementError(SQL 命令语法错误)
    • QSglError,TransactionError(事务错误)
    • QSqlError,UnknownError
QSqlDatabase的方法及参数类型 返回值的类型 说 明
[static]drivers() ListCstr] 获取系统支持的驱动类型
[slatic]isDriverAvailable(name: str) b001 获取是否支持某种类型的驱动
[static]addDatabase(type: str, connectionName: str = ‘ qt _ sql_ default_ connection’) QSqlDatabase 添加数据库连接
[static]database(connectionName: str=’qt_sq/ _default_connection’,open:bool=True) QSqlDatabase 根据连接名称获取数据库连接
[static]removeDatabase(connectionName: str) None 删除数据库连接
[static]connectionNames() List[str] 获取已经添加的连接名称
[static] contains(connectionName: str =’qt_sql_ default_connection’) bo01 如果connectionNames()返回值中 有指定的连接,则返回True
connectionName() Str 获取连接的名称
driverName() str 获取驱动类型名称
setDatabaseName(name:str) None 设置连接的数据库名称
databaseName() Str 获取连接的数据库名称
setHostName(host: str) None 设置主机名
hostName() S1T 获取主机名
setPassword(password:str) None 设置登录密码
password() str 获取登录密码
setPort(p:int) None 设置端口号
port() int 获取端口号
setUserName(name:str) None 设置用户名
userName() Str 获取用户名
setConnectOptions(options: str=”) None 设置连接参数
connectOptions() Str 获取连接参数
open() boo1 打开数据库
open(user:str,password:str) bool 打开数据库
isOpen() b001 获取数据库是否打开
isOpenError() bo0l 获取打开数据时是否出错
isValid() bool 获取连接是否有效
setNumericalPrecisionPolicy(precisionPolicy: QSql. NumericalPrecisionPolicy) None 设置对数据库进行查询时默认的数 值精度
tables(type: QSql. TableType=QSql. TableType. Tables) ListCstr] 根据表格类型参数、获取数据库中 的表格名称
transaction() bool 开启事务,成功则返回True
exec(query: str=”) QSqlQuery 执行SQL命令
commit() bool 提交事务成功则返回True
rollback() 6001 放弃事务,成功则返回True
lastError() QSqlError 获取最后的出错信息
record(tablename: str) QSqlRecord 获取含有字段名称的记录
close() 三 None 关闭连接

数据库查询 QSqlQuery 与实例

数据库查询 QSqlQuery 用于执行标准的 SQL 命令,例如 CREATETABLESELECTINSERTUPDATE、DELETE 等,还可执行特定的非标准的 SQL 命令。

用QSqlQuery 类创建实例对象的方法如下所示。

1
2
3
4
5
6
from PySide6.QtSql import QSqlQuery

QSqlQuery(db: PySide6.QtSql.QSqlDatabase) -> None
QSqlQuery(other: PySide6.QtSql.QSqlQuery) -> None
QSqlQuery(query: str = '', db: PySide6.QtSql.QSqlDatabase = Default(QSqlDatabase)) -> None
QSqlQuery(r: PySide6.QtSql.QSqlResult) -> None
数据库查询 QSqlQuery 的常用方法

数据库查询 QSqlQuery的常用方法如表所示,主要方法介绍如下

  • 用prepare(query:str)方法准备要执行的 SQL命令;

    • 用exec()方法或 execBatch(mode= QSqlQuery,ValuesAsRows)方法执行已经准备好的 SQL 命令,其中mode可取:
      • QSqlQuery.ValuesAsRows(更新多行,列表中的每个值作为一个值来更新下一行)
      • QSqlQuery.ValuesAsColumns(更新一行,列表作为一个值来使用);
    • 也可用exec(query:str)方法直接执行 SQL命令。
    • 对于SQLite 数据库,每个prepare(query:str)方法和exec(query:str)方法只能准备和执行一条SQL命令
      • 在用prepare(query:str)方法准备 SQL命令时,SQL命令中可以有占位符,占位符可以用问号“?”(ODBC格式),也可以用冒号“:surname”(Oracle 格式)。
      • 占位符的真实值可以用addBindValue(val:Any,type:QSqlParamType=QSql.In)方法按照顺序依次设置,
      • 也可用bindValue(placeholder:str,val;Any,type:QSql.ParamType=QSqlIn)方法根据占位符的名称设置
      • 还可以用bindValue(pos:int,val:Any,type:QSqlParamType=QSqlIn)方法根据占位符的位置设置,其中参数type可取:
        • QSqlIn(绑定参数输人到数据库中)
        • QSqLOut(定参数从数据库中接收数据)
        • QSql.InOut(既可以将数据输人到数据库中,
      • 也可以从数据库中接收数据)或QSqlBinary(数据是二进制需要将“”与以上三种参数联合使用)当一个查询完成后,查询处于活跃状态,isActive()的返回值是True
        • 用finish()方法或 clear()方法可使查询处于非活跃状态。
  • 有些数据库的查询操作能返多个结果

    • 用nextResult()方法可以放弃当前查询结果并定位到下一个结果,成功则返回 True。
    • 当返回的结果有多个记录时,需要首先定位到所需要的记录上,
      • 当isActive()方法和isSelect()方法的返回值是True时,可以用first()last()previous()和 next()方法分别定位到第一个记录、最后一个记录、前一个记录和下一个记录上,成功则返回True;
      • 用seek(index;int,relative:bool=False)方法可以定位到指定的记录上如果只是想从开始到结束浏览数据,可以设置 setForwardOnly(True),这样可以节省大量的内存。
      • 用value(index;int)方法或 value(name:str)方法获取当前记录的字段值。
        • 也可用record()方法获取当前的记录对象 QSqlRecord,QSqlRecord 是指数据表(table)或视图(view)中的一行,然后用记录对象的 value(index;int)方法或 value(name:str)方法获取字段的值,用记录对象的 count()方法获取字段的数量,用indexO(name:str)方法获取字段的索引。
QSqlQuery的方法及参数类型 返回值类型 说明
prepare(query:str) bool 准备SQL命令,成功则返回True
addBindValue(val:Any, type: QSql. ParamType=QSql.In) None 如果 prepare(query)中有占位符,则按顺序 依次设置占位符的值
bindValue(placeholder:str, val: Any, type:QSql. ParamType=QSql. In) None 如果 prepare(query)中有占位符,则根据占 位符名称设置占位符的值
bindValue(pos: int, val; Any,type: QSql. ParamType=QSql. In) None 如果 prepare(query)中有占位符,则根据占 位符位置设置占位符的值
exec() bool 执行prepare(query)准备的SQL命令
execBatch(mode=QSqlQuery. ValuesAsRows) bool 批处理用prepare()方法准备的命令
exec(query:str) bool 执行SQL命令,成功则返回True
boundValue(placeholder:str) Any 根据占位符名称获取绑定值
boundValue(pos:int) Any 根据位置获取绑定值
boundValues() List[Any] 获取绑定值列表
finish() None 完成查询,不再获取数据。一般不需要使 用该方法
clear() None 清空结果,释放所有资源,查询处于不活跃 状态
executedQuery() Str 返回最后正确执行的SQL命令
lastQuery() Str 返回当前查询使用的SQL命令
at() int 返回查询的当前内部位置,第一个记录的 位置是0,如果位置无效,则返回值是 QSqI. BeforeFirstRow(值是一1)或 QSql. AfterLastRow(值是一2)
isSelect() bool 当前 SQL命令是 SELECT命令时返 回True
isValid() bool 当前查询定位在有效记录上时返回True
first() bool 将当前查询位置定位到第一个记录
last() bool 将当前查询位置定位到最后一个记录
previous() bool 将当前查询位置定位到前一个记录
next() bool 将当前查询位置定位到下一个记录
seek(index: int, relative:bool=False) bool 将当前查询位置定位到指定的记录
setForwardOnly(forward;bool) None 当forwrad取True时,只能用next()和 seek()方法来定位结果,此时seek()参数为 正值
isForwardOnly() bool 获取定位模式
isActive() bool 获取查询是否处于活跃状态
isNull(field:int) bool 当查询处于非活跃状态、查询定位在无效 记录或空字段上时返回True
isNull(name:str) bool 同上,name是字段名称
lastError() QSqlError 返回最近出错信息
lastInsertId() Ang 返回最近插人行的对象ID号
nextResult() bool 放弃当前查询结果并定位到下一个结果
record() QSqlRecord 返回查询指向的当前记录(行)
size() int 获取结果中行的数量,无法确定、非 SELECT命令或数据库不支持该功能时返 回一1
value(index: int) Any 根据字段索引,获取当前记录的字段值
value(name:str) Any 根据字段名称,获取当前记录的字段值
numRowsAffected() int 获取受影响的行的个数,无法确定或查询 处于非活跃状态时返回一1
swap(other:QSqlQuery) None 与其他查询交换数据
数据库查询 QSqlQuery的应用实例

下面的程序创建一个 SQLite 数据库和两个数据表,用不同的方法输出占位符的值,并用不同的方法输出数据表中的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 22:38
# File_name: 02- 数据库查询 QSqlQuery的应用实例.py


from PySide6.QtSql import QSqlDatabase, QSqlQuery
import sqlite3

dbName = "./student score new.db" # 数据库保存位置和数据库名称
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(dbName)

information1 =((2001, "张1", 78, 89),(2002, "张2", 78, 89),
(2003, "张3", 78, 89),(2004, "张4", 78, 89))

information2 =((2005, "李5", 78, 89),(2006, "李6", 78, 89),
(2007, "李7", 78, 89),(2008, "李8", 78, 89))

if db.open():
db.exec('''create table score1(ID INTEGER, NAME TEXT, 语文 REAL, 数学 REAL)''')
db.exec('''create table score2(ID INTEGER, NAME TEXT, 语文 REAL, 数学 REAL)''')

print(db.tables())

if db.transaction():
query = QSqlQuery(db)

for i in information1:
query.prepare("INSERT INTO score1 VALUES(?,?,?,?)") # 占位符是?
query.addBindValue(i[0])
query.addBindValue(i[1])

query.bindValue(2, i[2])
query.bindValue(3, i[3])

query.exec()

db.commit()

for i in information2:
query.prepare("INSERT INTO score2 VALUES(:ID:name,:chinese,:math)") # 占位符是:
query.bindValue(0, i[0])
query.bindValue(1, i[1]) # 按照索引设置占位符的值
query.bindValue(':math', i[3],) # 按照名称设置占位符的值
query.bindValue(':chinese', i[2],) # 按照名称设置占位符的值

query.exec()
db.commit()
db.close()

db_new = QSqlDatabase.addDatabase("QSQLITE")
db_new.setDatabaseName(dbName)
if db_new.open():
print(query.at())
if query.exec("SELECT * FROM score1"):
while query.next():
print(query.value('ID'), query.value('name'), query.value('语文'), query.value('数学'))
db_new.close()

con = sqlite3.connect(dbName) # 用sqllite3打开
cur = con.cursor()
for row in cur.execute("select * from score2"):
print(row)

con.close()

数据库 Model/View 结构

用SQL命令对数据库进行操作并不直观,PySide 提供了对数据库进行可视化操作的Model/View 结构,通过数据库模型读入在数据库中查询到的数据,并通过视图控件(如QTableView)显示数据库模型中的数据,通过代理控件在视图控件中对数据进行新增更新、删除等操作,再通过数据模型把操作后的数据保存到数据库中。PySide 提供的数据库模型有 QSqlQueryModelQSalTableModel和 QSlRelationalTableModel,它们之间的继承关系如图5-7 所示。

数据库查询模型QSglQueryModel

数据库查询模型 QSlQueryModel 只能从数据库中读取数据,而不能修改数据,可以用视图控件,例如 QTableView 来显示查询模型 QSqlQueryModel 中的数据。

用QSglQueryModel 创建数据库查询模型对象的方法如下所示。

1
2
3
from PySide6.QtSql import QSqlQueryModel

QSqlQueryModel(parent: Union[PySide6.QtCore.QObject, NoneType] = None) -> None
数据库查询模型 QSqlQueryModel 的常用方法

数据库查询模型 QSqlQueryModel的常用方法如表所示主要方法

  • 用setQuery(query:QSqlQuery)方法或 setQuery(query:str,db;QSqlDatabase = Default(QSqlDatabase))方法设置数据库查询 QSqlQuery;
  • 用setHeaderData(section: intorientation:Qt.Orientation,value: Any;role: int=Qt.EditRole)方法设置显示数据的视图控件表头某角色的值
    • 在 orientation 取 Qt.Horizontal,并且 section 取值合适时返回True,其他情况返回 False
    • 其中 value 是某种角色的值,section 是列索引
QSqlQueryModel的方法及参数类型 返回值的类型 说明
setQuery(query:QSqlQuery) None 设置数据库查询
setQuery(query:str,db: QSqlDatabase= Default(QSqlDatabase)) None 设置数据库查询
query() QSqlQuery 获取数据查询
setHeaderData(section:int,orientation: Qt.Orientation,value: Any, role: int = Qt.EditRole) bo01 设置显示数据的视图控件(如 QTableView)表头某角色的值
headerData(section: int, orientation: Qt.Orientation, role: int = Qt.ItemDataRole. DisplayRole) Any 获取显示数据的视图控件表头某种角 色的值
record() QSqlRecord 获取包含字段信息的空记录
record(row:int) QSqlRecord 获取指定的字段记录
rowCount(parent: QModelIndex= Invalid(QModelIndex)) int 获取数据表中记录(行)的数量
columnCount(parent:QModelIndex=Invalid(QModelIndex)) int 获取数据表中字段(列)的数量
clear() None 清空查询模型中的数据
数据库查询模型QSqlQueryModel的应用实例

下面的程序用菜单打开前一节创建的 SQLite数据库文件 student score_new.db

用QTableView 控件显示出数据表中的数据用QComboBox控件显示数据库中的数据表名称在QComboBox中选择不同的数据表名称时QTableView 控件将同步显示该数据表中的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/12 23:23
# File_name: 03-数据库查询模型QSqlQueryModel的应用实例.py

from PySide6.QtWidgets import QApplication, QWidget, QComboBox, QTableView, QLabel, QHBoxLayout, QVBoxLayout, QFileDialog, QMenuBar
from PySide6.QtSql import QSqlDatabase, QSqlQueryModel
from PySide6.QtCore import Qt
import sys


class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUi()

def setupUi(self):
menuBar = QMenuBar()
fileMenu = menuBar.addMenu("文件(&F)")

fileMenu.addAction("打开(&0)").triggered.connect(self.actionOpen)
fileMenu.addSeparator()
fileMenu.addAction("关闭(&E)").triggered.connect(self.close)

label = QLabel("选择数据表:")
self.combox = QComboBox()
self.combox.currentTextChanged.connect(self.comboxTextChanged)
H = QHBoxLayout()
H.addWidget(label, stretch=0)
H.addWidget(self.combox, stretch=1)

self.tableView = QTableView()
self.tableView.setAlternatingRowColors(True)
V = QVBoxLayout(self)
V.addWidget(menuBar)
V.addLayout(H)
V.addWidget(self.tableView)

def actionOpen(self):
dbFile, fil = QFileDialog.getOpenFileName(self, dir=".", filter="SQLite(*.db *.db3)")
if dbFile:
self.setWindowTitle(dbFile)
self.combox.clear()
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName(dbFile)
self.sqlQueryModel = QSqlQueryModel(self)
if self.db.open(): # 数据库查询模型
tables = self.db.tables()
if len(tables) > 0:
self.combox.addItems(tables)

def comboxTextChanged(self, text):
self.sqlQueryModel.setQuery("SELECT * EROM form {}".format(text), self.db)

header = self.sqlQueryModel.record()
for i in range(header.count()):
self.sqlQueryModel.setHeaderData(i, Qt.Orientation.Horizontal, header.fieldName(i), Qt.DisplayRole)
self.tableView.setModel(self.sqlQueryModel) # 设置表格视图的数据模型


if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWidget()

win.show()
sys.exit(app.exec())

数据库表格模型 QSgITableModel

数据库表格模型 QSglTableModel 借助视图控件可以对查询到的数据进行修改、插入、删除和排序等操作,同时将修改后的数据更新到数据库中。

用QSqlTableModel 创建数据库表格模型的方法如下所示。

1
2
3
from PySide6.QtSql import QSqlTableModel

QSqlTableModel(parent: Union[PySide6.QtCore.QObject, NoneType] = None, db: PySide6.QtSql.QSqlDatabase = Default(QSqlDatabase)) -> None
数据库表格模型QSqlTableModel的常用方法

数据库表格模型QSqlTableModel的常用方法如表所示,主要方法介绍如下

  • 在视图控件(如QTableView)中对数据库表格模型中的数据进行修改提交时,有3种模式可供选择

    • 立即模式行模式和手动模式。用setEditStrategy(strategy:QSqlTableModel,EditStrategy)方法设置修改提交模式,参数 strategy 的取值是QSqlTableModel.EditStrategy 的枚举值,可取以下值,对应的值分别是0 1和2
      • QSalTableModel.OnFieldChange
      • QSqlTableModel.OnRowChange
      • QSglTableModel.OnManualSubmit
    • 用editStrategy()方法可获得当前的模式。
      • OnFieldChange模式表示对模型的修改会立即更新到数据库中;
      • OnRowChange 模式表示修改完一行,再选择其他行后把修改应用到数据库中;
      • OnManualSubmit模式表示修改后不会立即更新到数据库中,而是保存到缓存中,
    • 调用submitAl1()方法后才把修改应用到数据库中,
    • 调用revertAll()方法可撤销修改并恢复原状。
  • QSglTableModel 还提供了-些与修改提交模式无关的低级方法,例如…这些低级方法可以直接修改数据库

    • deleteRowFromTable(row:int)

    • insertRowIntoTable(values: QSqlRecord)

    • updateRowInTable(row: int,QSglRecord)

  • 对数据库的查询

    • 可以先用setTable(tableName:str)方法setFilter(filter:str)方法和 setSort(column:int,order:Qt.SortOrder)方法分别设置需要查询的数据表SQL的WHERE从句和SORT BY从句,最后调用select()方法,也可以直接用setQuery(query:QSqlQuery)方法进行查询。
  • 在视图控件(如QTableView)中对数据库表格模型中的数据进行修改提交时

    • 在OnManualSubmit模式下,用revert()方法撤销在代理控件中所作的更改并恢复原状;
    • 用revertAl1()方法复原所有未提交的更改;用submit()方法提交在代理控件中所作的更改;
    • 用submitA11()方法提交所有的更改。
  • 用setRecord(row:int;record;QSglRecord)方法可以对某行内容用字段进行替换

  • 用insertRecord(row:int,record:QSgIRecord)方法可以在指定行插入一条记录

    • 用insertRows(row:int,count;int)方法可以在指定的行位置处插入多个空行;
    • 用insertColumns(column:intcount;int)方法可以在指定的列位置处插人多列
  • 用removeRow(row:int)方法和removeColumn(column:int)方法可以分别删除指定的行和列;

    • 用removeRows(row:int,count;int)方法和 removeColumns(column:int,count:int)方法可以分别从指定行或列位置处删除多行和多列。
  • 用setSort(column;int,order:Qt.SortOrder)方法可以将数据模型中的数据按照某列的值进行排序,参数 order 可取:

    • Qt.AscendingOrder(升序)
    • Qt.DescendingOrder(降序)
QSqlTableModel的方法及参数类型 返回值类型 说 明
setEditStrategy(strategy: QSqlTableModel.EditStrategy) None 设置修改提交模式
database() QSqlDatabase 获取关联的数据库连接
deleteRowFromTable(row:int) bool 直接删除数据表中指定的行(记录)
fieldIndex(fieldName: str) int 获取字段的索引,一1表示没有对应的字段
insertRecord(row:int,record: QSqlRecord) bo0l 在指定行位置插人记录,row 取负值表示 在末尾位置,成功则返回True
insertRowIntoTable(values: QSqlRecord) bool 直接在数据表中插人行,成功则返回True
insertRows(row: int,count:int) bool 插人多个空行,在 OnFieldChange 和 OnRowChange 模式下每次只能插人一行, 成功则返回True
insertColumns(column:int.count:int) bool . 插人多个空列,成功则返回True
isDirty() bool 获取模型中是否有脏数据,脏数据是指修 改过但还没有更新到数据库中的数据
isDirty(index:QModelIndex) bool 根据索引获取数据是否是脏数据
primaryValues(row: int) QSqlRecord 返回指定行的含有表格字段的记录
record() QSqlRecord 返回仅包含字段名称的空记录
record(row:int) QSqlRecord 返回指定行的记录,如果模型没有初始化, 则返回空记录
removeColumn(column:int) bool 删除指定的列,成功则返回 True
removeColumns(column:int,count:int) bool 删除多列,成功则返回True
romoveRow(row:int) bool 删除指定的行,成功则返回True
removeRows(row:int,count:int) bool 删除多行,成功则返回True
[slot]revert() None 撤销代理控件所作更改并恢复原状
[slot]submit() boo1 往数据库中提交在代理控件中对行所作的 更改,成功则返回True
[slot]revertAll() None 复原所有未提交的更改
[slot]submitAll() bool 提交所有更改,成功则返回True
revertRow(row:int) None 复原指定行的更改
rowCount() int 获取行的数量
columnCount() int 获取列的数量
setData(index: QModelIndex, value: Any, role: int = Qt.ItemDataRole.EditRole) bool 设置指定索引的数据项的角色值,成功则 返回 True
data(idx: QModelIndex, role: int= Qt.ItemDataRole.DisplayRole) Any 获取角色值
setQuery(query:QSqlQuery) None 直接设置数据库查询
query() QSqlQuery 获取数据查询对象
setRecord(row: int,record: QSqlRecord) bool 用指定的记录填充指定的行
setTable(tableName: str) None 获取数据表中的字段名称
setFilter(filter:str) None 设置SELECT查询语句中WHERE从句 部分,但不包含WHERE
filter() Str 获取 WHERE 从句
setSort(column:int,order:Qt.SortOrder) None 设置SELECT语句中ORDER BY从句 部分
orderByClause() Str 获取ORDER BY从句部分
[slot]select() bool 执行SELECT命令,获取新查询结果
[slot]selectRow(row:int) bool 用数据库中的行更新模型中的数据
selectStatement() Str 获取”SELECT…WHRER…ORDER BY”
sort(column:int,order:Qt.SortOrder) None 直接对结果进行排序
updateRowInTable(row:int, QSqLRecord) bool 直接用记录更新数据库中的行
tableName() str 获取数据库中的数据表名称
setHeaderData(section:int, orientation: Qt.Orientation,value:Any,role:int= Qt.ItemDataRole.EditRole) bool 设置视图控件(如 QTableView)表头某角 色的值
index(row: int,column:int,parent: QModelIndex=Invalid(QModelIndex)) QModelIndex 获取子索引
parent(child:QModelIndex) QModelIndex 获取子索引的父索引
sibling(row:int, column: int,idx: QModelIndex) QModelIndex 获取同级别索引
clear() None 清空模型中的数据
clearItemData(index: QModelIndex) bool 根据索引清除数据项中的数据
数据库表格模型QSqlTableModel的信号

数据库表格模型QSqlTableModel 的信号如表所示

QSqlTableModel的信号及参数类型 说 二明
beforeDelete(row:int) 在调用deleteRowFromTable(row:int)方法删除指定的行之前发 送信号
beforeInsert(record: QSqlRecord) 在调用insertRowIntoTable(values:QSqlRecord)方法插入记录之 前发送信号,可以在插入之前修改记录
beforeUpdate(row: int, record: QSqlRecord) 在调用updateRowInTable(row:int,values:QSqlRecord)方法更 新指定的记录之前发送信号
primeInsert(row: int, record; QSqlRecord) 在调用insertRows(row:int,count:int)方法,对新插入的行进行 初始化时发送信号
记录 QSqlRecord 的方法

记录 QSqlRecord 表示数据表中的一行数据,一行数据中每个字段有不同的值,可用QSqlTableModel的 record(row;int)方法获取 QSqlRecord 对象,以获取数据表中的一行数据。

用QSqlRecord 创建记录实例对象的方法如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
```



QSqlRecord 的常用方法如表所示。

- 用append(field:QSglField)方法可以在末尾添加字段;
- 用insert(pos:int,field;QSalField)方法插人字段;
- 用remove(pos:int)方法移除字段;
- 用setValue(i:int,val;Any)方法或 setValue(name; str,val:Any)方法根据字段索引或字段名称设置字段的值;
- 用setGenerated(i: int,generated: bool)方法或setGenerated(name:str,generated;bool)方法根据索引或名称设置字段值是否已经生成只有已经生成的字段值才能
- 用QSqlTableModel 的 updateRowInTable(row: int,values:QSqlRecord)方法更新到数据库中,默认值是 True

| QSqlRecord的方法及参数类型 | 返回值的类型 | 说明 |
| ---------------------------------------- | ------------ | ------------------------------------------------------------ |
| append(field: QSqlPield) | None | 在末尾添加字段 |
| insert(pos: int,field: QSqlField) | None | 在指定的位置插入字段 |
| remove(pos:int) | None | 根据位置移除字段 |
| replace(pos: int, field: QSqlField) | None | 根据位置替换字段的值 |
| setValue(i: int,val: Any) | None | 根据字段索引值设置字段的值 |
| setValue(name: str,val:Any) | None | 根据字段名称设置字段的值 |
| value(i:int) | Any | 根据字段索引获取字段的值 |
| value(name: str) | Any | 根据字段名称获取字段的值 |
| setNull(i:int) | None | 根据字段索引设置空值 |
| setNull(name: str) | None | 根据字段名称设置空值 |
| isNull(i:int) | bool | 根据字段名称或位置,当指定的字段值为 |
| isNull(name:str) | bool | None或不存在该字段时返回True |
| clear() | None | 删除所有的字段 |
| isEmpty() | bo0l | 获取是否含有字段 |
| clearValues() | None | 删除所有字段的值,字段值为None |
| contains(name:str) | bool | 获取是否包含指定的字段 |
| count() | int | 获取字段的个数 |
| field(i:int) | QSqlField | 根据字段索引获取字段对象 |
| field(name:str) | QSqlField | 根据字段名称获取字段对象 |
| fieldName(i: int) | Str | 获取字段的名称 |
| indexOf(name:str) | int | 获取字段名称对应的索引 |
| keyValues(keyFields: QSqlRecord) | QSqlRecord | 获取与给定的记录具有相同字段名称的 记录 |
| setGenerated(i: int,generated: bool) | None | 根据索引或名称设置字段值是否已经生 成,只有已经生成的字段值才能被更新到 数据库中。generated 的默认值是 True |
| setGenerated(name: str,generated: boo1) | None | 根据索引或名称设置字段值是否已经生 成,只有已经生成的字段值才能被更新到 数据库中。generated 的默认值是 True |
| isGenerated(i: int) | bool | 根据索引获取字段是否已经生成 |
| isGenerated(name:str) | bool | 根据名称获取字段是否已经生成 |

##### 字段 QSqlField 的方法

字段 QSqlField 是数据表中的列,一个记录由多个字段构成。

字段的属性有字段名、字段类型和字段值等。用QSqlRecord 的 field(i:int)方法或 field(name: str)方法可获得QSqlField。

用QSqlField 创建字段的方法如下所示,其中 type 用于定义字段的类型,可取以下值,QMetaType 类在 QtCore 模块中,这里设置的类型可能与实际的不符,例如太长的整数可能存储成字符串。

```python
QMetaType.Bool、QMetaType.Int、QMetaType.UInt、QMetaType.Double,QMetaType.QString,QMetaType.QByteArray
QMetaType.Long、QMetaType.LongLong、QMetaType.Short、QMetaType.ULong、QMetaType.ULongLong、QMetaType.UShort、
QMetaType.UChar、QMetaType.Float、QMetaType.QCursor,QMetaType.QDate、QMetaType.QSize、QMetaType.Time、QMetaType.QPolygon
QMetaType.QPolygonF、QMetaType。QColor、QMetaType.QSizeF、QMetaType.QRectF、QMetaType.QLine、QMetaType.QIcon、QMetaType.QPen
QMetaType.QLineF、QMetaType.QRect、QMetaType.QPoint、QMetaType QUrl、QMetaType.QDateTime、QMetaType.QPointF、QMetaType,QPalette
QMetaType.QFont、QMetaType.QBrush、QMetaType.QRegion、QMetaType.QImage、QMetaType.QPixmap、QMetaType.QBitmap、QMetaType.QTransform

字段QSqlField 的常用方法如表所示。主要方法是

  • 用setName(name:str)方法设置字段名称;
  • 用setValue(value: Any)方法设置字段的值;
  • 用setDefaultValue(value:Any)方法设置字段的默认值;
  • 用setReadOnly(readOnly:bool)方法设置是否是只读
    • 在只读状态不能更改字段的值例如不能用setValue()方法和 clear()方法改变其值;
  • 用setRequired(required: bool)方法或 setRequiredStatus(status; QSqlField. RequiredStatus)方法设置字段的值是必须要输入的还是可选的,其中参数 status 可取:
    • QSqlField.Required
    • QSqlField.Optional
    • QSqlField.Unknown
QSqlField的方法及参数类型 返回值的类型 说明
setName(name:str) None 设置字段的名称
name() str 获取字段的名称
setValue(value:Any) None 设置字段的值,只读时不能设置值
value() Any 获取字段的值
setDefaultValue(value:Any) None 设置字段的默认值
defaultValue() Any 获取字段的默认值
setMetaType(type:QMetaType) None 设置字段的类型
metaType() QMetaType 获取存储在数据库中的类型
setReadOnly(readOnly:bool) None 设置是否是只读,只读时不能修改字段 的值
isReadOnly() bool 获取是否只读
setRequired(required:bool) None 设置字段的值是必须要输入还是可选的
setRequiredStatus(status: QSqlField.RequiredStatus) None 设置可选状态
setGenerated(gen:bool) None 设置字段的生成状态
isGenerated() bool 获取字段的生成状态
setLength(fieldLength: int) None 设置字段的长度,类型是字符串时是字符 串的最大长度,其他类型无意义
length() int 获取字段的长度,负值表示无法确定
setPrecision(precision: int) None 设置浮点数的精度,只对数值类型有意义
precision() int 获取精度,负数表示不能确定精度
set TableName(tableName: str) None 设置数据表名称
tableName() str 获取数据表名称
setAuto Value(autoVal:bool) None 将字段的值标记成是由数据库自动生成的
isAutoValue() bool 获取字段的值是否是由数据库自动生成的
isValid() bool 获取字段的类型是否有效
clear() None 清除字段的值并设置成 None
isNull() bool 如果字段的值是None,则返回True
数据库表格模型QSqITableModel的应用实例

下面的程序用菜单打开一个SQLite 数据库用QTableView 控件显示出数据表中的数据,用QComboBox 控件显示数据库中的数据表名称,可以插入记录和删除记录。在QTableView中可以修改字段的值。由于修改提交模式选择 OnFieldChange,因此对数据库的操作会自动保存到数据库中

image-20230313011041540

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/13 0:34
# File_name: 04-数据库表格模型QSqITableModel的应用实例.py


from PySide6.QtWidgets import QApplication, QWidget, QComboBox, QTableView, QLabel, QPushButton, QHBoxLayout, QVBoxLayout, QFileDialog, QMenuBar, QGroupBox, QLineEdit, QSpinBox, QDoubleSpinBox
from PySide6.QtSql import QSqlTableModel, QSqlRecord, QSqlDatabase
from PySide6.QtCore import Qt
import sys


class Mywidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

self.setupUi()

def setupUi(self): # 建立界面
menuBar = QMenuBar()
fileMenu = menuBar.addMenu("文件(&E)")

fileMenu.addAction("打开(&O)").triggered.connect(self.actionOpen)
fileMenu.addSeparator()
fileMenu.addAction("关闭(&E)").triggered.connect(self.close)
label1 = QLabel("选择数据表:")
self.combox = QComboBox()
H1 = QHBoxLayout()
H1.addWidget(label1, stretch=0)
H1.addWidget(self.combox, stretch=1)
label2 = QLabel("学号")
self.spinID = QSpinBox()
label3 = QLabel("姓名:")
self.lineEdit_name = QLineEdit()
label4 = QLabel("语文:")
self.doubleSpin_chinese = QDoubleSpinBox()
label5 = QLabel("数学")
self.doubleSpin_math = QDoubleSpinBox()
self.pushButton_add = QPushButton("在当前位置添加记录")
self.groupBox1 = QGroupBox("添加记录")
self.groupBox1.setEnabled(False)

H2 = QHBoxLayout(self.groupBox1)
H2.addWidget(label2, 0)
H2.addWidget(self.spinID, 1)
H2.addWidget(label3, 0)
H2.addWidget(self.lineEdit_name, 1)
H2.addWidget(label4, 0)
H2.addWidget(self.doubleSpin_chinese, 1)
H2.addWidget(label5, 0)
H2.addWidget(self.doubleSpin_math, 1)
H2.addWidget(self.pushButton_add)

label6 = QLabel("删除行:")
self.spin_deleteLine = QSpinBox()
self.pushButton_delete = QPushButton("删除指定的记录")
self.pushButton_delete_cur = QPushButton("删除当前记录")
self.groupBox2 = QGroupBox("删除记录")
self.groupBox2.setEnabled(False)
H3 = QHBoxLayout(self.groupBox2)
H3.addWidget(label6, 0)
H3.addWidget(self.spin_deleteLine, 1)
H3.addWidget(self.pushButton_delete)
H3.addWidget(self.pushButton_delete_cur)

self.tableView = QTableView()
self.tableView.setAlternatingRowColors(True)
V = QVBoxLayout(self)
V.addWidget(menuBar)
V.addLayout(H1)
V.addWidget(self.groupBox1)
V.addWidget(self.groupBox2)
V.addWidget(self.tableView)

# 信号与槽连接
self.combox.currentTextChanged.connect(self.comboxTextChanged)
self.pushButton_add.clicked.connect(self.pushButton_add_clicked)
self.pushButton_delete.clicked.connect(self.pushButton_delete_clicked)
self.pushButton_delete_cur.clicked.connect(self.pushButton_delete_cur_clicked)

def actionOpen(self): # 打开数据库的槽函数
dbFile, fil = QFileDialog.getOpenFileName(self, dir=".", filter="SQLite(*.db *.db3)")
if dbFile:
self.setWindowTitle(dbFile)
self.combox.clear()
self.db = QSqlDatabase.addDatabase('QSQLITE')
self.db.setDatabaseName(dbFile)
if self.db.open():
self.sqlTableModel = QSqlTableModel(self, self.db) # 数据库表格模型
self.sqlTableModel.setEditStrategy(QSqlTableModel.EditStrategy.OnFieldChange)
self.tableView.setModel(self.sqlTableModel)
tables = self.db.tables()
if len(tables) > 0:
self.combox.addItems(tables)
self.groupBox1.setEnabled(True)
self.groupBox2.setEnabled(True)

else:
self.groupBox1.setEnabled(False)
self.groupBox2.setEnabled(False)

def comboxTextChanged(self, text):
self.sqlTableModel.setTable(text)
self.sqlTableModel.select()
header = self.sqlTableModel.record()

for i in range(header.count()):
self.sqlTableModel.setHeaderData(i, Qt.Orientation.Horizontal, header.fieldName(i), Qt.DisplayRole)

def pushButton_add_clicked(self):
record = QSqlRecord(self.sqlTableModel.record())
record.setValue("ID", self.spinID.value())
record.setValue("name", self.lineEdit_name.text())
record.setValue("语文", self.doubleSpin_chinese.value())
record.setValue("数学", self.doubleSpin_math.value())
self.spinID.setValue(self.spinID.value() + 1)
currentRow = self.tableView.currentIndex().row()
if not self.sqlTableModel.insertRecord(currentRow + 1, record):
self.sqlTableModel.select()

def pushButton_delete_clicked(self):
row = self.spin_deleteLine.value()
if row > 0 and row <= self.sqlTableModel.rowCount():
if self.sqlTableModel.removeRow(row - 1):
self.sqlTableModel.select()

def pushButton_delete_cur_clicked(self):
currentRow = self.tableView.currentIndex().row()
if self.sqlTableModel.removeRow(currentRow):
self.sqlTableModel.select()


if __name__ == '__main__':
app = QApplication(sys.argv)
win = Mywidget()

win.show()
sys.exit(app.exec())

关系表格模型QSglRelationalTableModel

数据库关系表格模型 QSqlRelationalTableModel 继承自QSqlTableModel,除具有QSqlTableModel 的方法外,它还提供了外键功能。

关系表格模型 QSqlRelationalTableModel 实现了SQL的 SELECT 命令中的 INNER JOIN LEFT JOIN 能。SELECT 命令中INNERJOIN和LEFTJOIN的格式如下。

1
2
SELECT * FROM table1 INNER JOIN table2 ON tablel.fleld1 = table2.field2
SELECT * FROM table1 LEFT JOIN teble2 0N tablel.field1 = table2.field2

数据库中的数据表格之间往往有一定的联系,例如学生考试成绩数据库中,用数据表格table1 来存储学号,姓名、语文成绩、数学成绩,而物理成绩和化学成绩只是用学号来标记,并没有给出成绩,用数据表格 table2 存储学号姓名、物理成绩和化学成绩如果想通过查询数据表格 tablel 得到语文成绩、数学成绩、物理成绩和化学成绩,就可利用QSqlRelationalTableModel模型的外键功能来实现。

用QSqlRelationalTableModel类创建关系表格模型的方法如下所示

1
2
3
from PySide6.QtSql import QSqlRelationalTableModel

QSqlRelationalTableModel(parent: Union[PySide6.QtCore.QObject, NoneType] = None, db: PySide6.QtSql.QSqlDatabase = Default(QSqlDatabase)) -> None
  • 用QSqlRelationalTableModel 的 setRelation(column:int,relation: QSqlRelation)方法定义QSqlRelationalTableModel 当前数据表格(如 table1)的外键和映射关系,
    • 其中参数column 是 tablel的字段编号,用于确定 tablel 中当作外键的字段 field1
    • relation 参数是QSgIRelation的实例对象,用于确定另外一个数据表格(如 table2)和对应的字段 field2.
  • QSqlRelation实例对象的创建方法是 QSqlRelation(tableName: str,indexCol;strdisplayCol:str)
    • 其中tableName 用于确定第2个数据表格 table2,
    • indexCol用于指定table2 的字段 feld2,
    • displayCol是 table2 中用于显示在 tablel 的 field1位置处的字段 field3,用field3 的值显示在 field1 位置处,field1 的值不显示
  • 另外用QSlRelationalTableModel 的setJoinMode(joinMode: QSgIRelationalTableModel,JoinMode)方法可设置两个数据表格的数据映射模式,参数joinMode可取 :
    • QSqlRelationalTableModel.InnerJoin(内连接,值为0,只列出 tablel和 table2 中匹配的数据)
    • QSqlRelationalTableModel.LeftJoin(左连接 值为1,即使 tablel和 table2 没有匹配的数据也列出 tablel中的数据)。