python小白从零开始pyqt5项目实战汇总篇(完整例程)(代码片段)

youcans youcans     2023-01-19     249

关键词:

本系列面向 Python 小白,从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战。不跳过一个细节,不漏掉一行代码,不省略一个例图。
本系列从软件安装、环境配置开始,介绍了基本应用:菜单和工具栏、基本控件,核心机制:信号与槽连接、高级应用:布局管理、窗口切换和折叠侧边栏,并通过项目实战案例介绍各种应用的详细操作过程。本文汇总相关内容,并给出项目实战的完整例程。


1. PyQt5 和 PyDesigner 的安装与环境配置

关于PyQt5 及PyDesigner 工具的安装与环境配置,具体请详见:Python 小白从零开始 PyQt5 项目实战(1)安装与环境配置

1.1 安装 PyQt5 和QtTools

QT 是最强大的 GUI 库之一,PyQt5 是 Python 绑定 QT5 应用的框架,具有简单好用,功能强大, 跨平台支持,文档齐全,稳定性高,生态支持,开源免费的优点。

Qt Designer 通过人机交互的排版方式进行界面设计,非常方便、直观。

pip 安装 PyQt5:

pip install pyqt5 -i https://mirrors.aliuyun.com/pypi/simple

pip 安装 QtTools:

Qt Tools 包含:

  • 图形界面设计工具 Qt Designer,用于设计图形界面,生成 .ui文件,以 xml 格式存储界面和控件的属性;

  • UI 文件转换工具 PyUic,用于将 .ui 文件解析为 .py 文件的工具。

Qt Tools 可以使用 pip 方式安装:

pip install pyqt5-tools  -i https://mirrors.aliuyun.com/pypi/simple

1.2 QtDesigner 和 PyUIC 的环境配置

使用 PyCharm 集成开发工具的小白,在安装 QtTools 库以后,还要对 QtDesigner 和 PyUIC 进行环境配置,将其集成到 PyCharm 中。


1.2.1 在 PyCharm 添加 Create Tools

运行 PyCharm;

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

在 CreateTool 窗口依次填写:

  • Name:填写 “QtDesigner”
  • Program:填写 designer.exe 的路径

注意:此处填写刚才 pip 安装的 pyqt5-tools 工具包的路径。如果小白的 Python 或 Anaconda3 安装在其他路径下,则从对应的目录找到 “qt5_applications\\Qt\\bin\\designer.exe”,或者在资源管理器中搜索 “designer.exe” 文件找到安装路径。

  • Arguments:不用填写
  • Working directory:填写生成 UI 文件的保存路径
    例如,要将 .ui 文件保存在当前 Project 的路径下,则填写 “$ProjectFileDir$”;要将 .ui 文件保存在当前 Project 路径下的 \\program 子目录中,则填写 “$ProjectFileDir$\\program”。

填好 CreateTool 窗口后,点击 “OK” 即可完成 QtDesigner 工具的添加。


1.2.2 添加 PyUIC 工具

在 CreateTool 窗口依次填写:

  • Name:填写 “PyUIC”
  • Program:填写 python.exe 的路径

注意:此处填写 IDE 使用的 Python Interpreter的路径。如果小白的 Python 或 Anaconda3 安装在其他路径下,或者选择其它路径中的 python.exe 作为 Python Interpreter,可以从 Pycharm -> Settings -> Project -> Python Interpreter 打开配置窗口,从右侧上方 “Python Interpreter:” 选项框找到 python.exe 的路径。

  • Arguments:填写"-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py”
  • Working directory:填写将 .ui 文件转换为 .py 文件的保存路径
    例如,要将 .py 文件保存在当前 Project 的路径下,则填写 “$ProjectFileDir$”;要将 .py 文件保存在当前 Project 路径下的 \\program 子目录中,则填写 “$ProjectFileDir$\\program”。

填好 CreateTool 窗口后,点击 “OK” 即可完成 QtDesigner 工具的添加。

安装和环境配置完成。



2. 菜单和工具栏

关于菜单与工具栏的操作,具体内容请详见:Python 小白从零开始 PyQt5 项目实战(2)菜单和工具栏

2.1 创建主窗口

新建应用程序窗口,通常可以选择 MainWindow 创建主窗口的图形界面。

QtDesigner 创建的 “MainWindow” 是一个空白的图形窗口,包括 centralwidget、menubar、statusbar 三个基本控件,可以在右侧上方 “对象查看器” 查看这些控件及结构。

在 QtDesigner 中用鼠标选中主窗口,或者在右侧的 “对象查看器” 中选中对象 “MainWindow”,此时右侧中部的 “属性编辑器” 将显示对象 “MainWindow” 的属性。在 “属性编辑器” 内可以对对象的属性进行编辑和修改。

在 QtDesigner 菜单中选择:窗体 -> 预览,就可以预览设计的图形界面,还可以选择预览不同操作系统的显示效果。这使我们不需要编写主程序就可以预览图形界面的显示效果,以便进行修改。


2.2 建立菜单栏

创建一级菜单:

QtDesigner 创建的 “MainWindow” 图形窗口,自动生成了顶部菜单栏 menubar,在图形窗口左上角显示有文本输入框 “在这里输入”。

输入菜单对象(menu)的标题(title):

  • 鼠标点击文本输入框 “在这里输入”,再双击选中的控件,出现激活的文本输入框;
  • 输入菜单标题后回车结束,就建立了一个一级菜单,例如:将菜单标题设为 “文件”。

输入菜单对象的标题,以及修改菜单对象的属性,更通用的方法是:

  • 在 QtDesigner 右侧的 “对象查看器” 中选中对象 “menu”,此时右侧中部的 “属性编辑器” 将显示对象 “menu” 的属性。
  • 在 “属性编辑器” 内选择 “title” 属性,将其修改为菜单标题:“文件”。

创建二级菜单:

QtDesigner 创建二级菜单,实际上是将动作(action)添加到一级菜单。

  • 鼠标点击一级菜单对象 “文件”,从下拉菜单选项选中 “在这里输入”,输入二级菜单的标题。
  • 编辑动作 actionOpen 的属性,可以将属性 “text” 由 “Open” 修改为中文 “打开”。这时再点击菜单 “文件”,下拉菜单中的动作 actionOpen 就显示为中文 “打开”。
  • 点击二级菜单/动作 “打开”,在其右侧有个 “+” 按钮,点击后可以创建新的下一级菜单。

2.3 建立工具栏

工具栏/工具条是图形界面中的常用组件,将一组按钮控件排成一行放在图形窗口的顶部。

添加工具栏

  • 单击鼠标右键,选择 “添加工具栏”。
  • 也可以选择 “Add Toolbar to Other Area”,将工具栏添加到窗口的左侧、右侧或底部。

添加和编辑动作对象

添加/编辑动作对象步骤为:

  • 点击 “动作编辑器” 子窗口工具栏的第一个图标按钮 “新建”,则弹出 “新建动作” 对话框;
  • 双击 “动作编辑器” 中的动作对象,则弹出 “编辑动作” 对话框,可以编辑已有动作对象的属性;

“新建动作” 与 “编辑动作” 对话框的结构是相同的,对照已有动作对象的属性更容易理解 “新建动作” 对话框中属性选项的含义:

  • “文本” 指动作的标题,是控件的显示内容,可以是中文或英文,例如 “打开(Open)”;
  • “对象名称” 指动作的名称,是程序中调用对象的名称,只能是英文,例如 “actionOpen”;
  • “图标” 指工具栏中所显示的动作图标,点击 “ ▽ \\triangledown ” 按钮,选择 “选择文件” 选项,可以从文件夹中选择图标文件。


3. 信号与槽(Signals and slots)的连接

关于信号与槽的操作,具体内容请详见:Python 小白从零开始 PyQt5 项目实战(3)信号与槽的连接

信号与槽机制是 PyQt 的核心机制,用于对象之间的通信,也就是实现函数之间的自动调用。

3.1 信号与槽的原理

简单地说,将信号与槽函数连接后,当信号被触发时,槽函数将被自动调用。

分析这个过程,涉及到几个基本概念和关系:

  • 信号:信号可以是一个动作,也可以是对象的一种状态,用于触发所连接的槽。
  • 槽:槽就是一个函数,可以由连接的信号触发。
  • 发射信号:信号被发射时,自动调用信号连接的槽函数。通常,在对象的状态改变时发射信号。
  • 信号可以带有参数,但必须与槽函数的参数相对应。
  • 一个信号可以连接多个槽函数,多个信号也可以连接到一个槽函数。
  • 一个信号可以连接到另一个信号上。
  • 很多窗口部件(控件)内置了一下信号和槽,可以直接调用。也可以按需求自定义信号和槽。

3.2 信号发送者与槽的接收者

信号的发送者通常是一个控件对象,在控件对象的状态发生变化时发送信号。常见的发送者是图形窗口中的各种控件对象,但也可以是动作对象。

槽的接收者通常也是控件对象。槽函数是一个自定义的槽函数,或控件内置的槽函数。一般地,槽函数也有一个对象作为主体,即对于接受者这个控件对象执行函数定义的操作。例如槽函数执行的功能是关闭,哪么究竟是关闭那个控件呢?关闭对象就是接受者。

为了方便讲解信号与槽的连接,我们用 QtDesigner 在上节设计的图形窗口 uiDemo3.ui 的基础上,增加几个按钮对象和文本行编辑对象:

  • 打开 PyCharm,从 Tools -> ExternalTools -> QtDesigner 打开 QtDesigner,打开 uiDemo3.ui 文件。

  • 鼠标点击选中 QtDesigner 左侧控件栏 Buttons 中的 PushButton,按住鼠标不放,将其拖动到中间的图形界面后松开鼠标,就在图形界面中创建了一个 PushButton 控件。

  • 鼠标点击选中 QtDesigner 左侧控件栏 InputWidget 中的 LineEdit,按住鼠标不放,将其拖动到中间的图形界面后松开鼠标,就在图形界面中创建了一个 LineEdit 控件。

  • 重复以上步骤,再建立几个 PushButton 控件和 LineEdit 控件。

    • 注意在 QtDesigner 右侧 “对象查看器” 中所显示的控件名称和属性,多个 PushButton、LineEdit 被自动赋予不同的命名(objectName),如:LineEdit_1、LineEdit_2、LineEdit_3,这就如同桌子有几个抽屉分别标记为 “抽屉1”、“抽屉2”、“抽屉3” 以便识别。
    • 控件的名称和其它属性都可以在 “属性编辑器” 中编辑修改。
  • 鼠标选中在图形界面中创建的 PushButton 控件或 LineEdit 控件,可以拖动控件调整位置。

  • 鼠标双击 PushButton 按钮,可以编辑按钮控件的标签即按钮上的显示内容。
    为了便于讲解,本例将各 PushButton 控件的显示内容(text 属性)修改为:“1# 按钮”~“4# 按钮”,将各 LineEdit 控件的显示内容(text 属性)修改为:“文本编辑行-1”~“文本编辑行-3”。

3.3 QtDesigner 建立信号与槽的连接

信号与槽的连接有几种不同情况:

  • 不同的发送者与接收者,槽函数为控件的内置函数;
  • 不同的发送者与接收者,槽函数为自定义函数;
  • 相同的发送者与接收者,槽函数为控件的内置函数;
  • 发送者是动作对象。


4. PyQt5 的基本控件

关于基本控件的操作,具体内容请详见:Python 小白从零开始 PyQt5 项目实战(4)基本控件

4.1 PyQt5 的控件简介

控件也称控件对象,是 Qt用户界面上最基本的组件类型,也是构成用户界面的基本结构。用户界面上显示的所有内容都是控件,例如按钮、标签、文本框,又如菜单栏、工具栏、状态栏,甚至整个窗口本身也是控件。

QWidget 类是 PyQt5 的基类,也是所有控件的父类。所有的 Qt 控件都是 QWidget 类的子类,因此都继承了 QWidget 类的特性,可以接收用户的输入事件,如鼠标和键盘输入,并可以在用户界面上显示控件内容,还可以存放其它控件。

4.2 编辑控件的属性

控件具有属性。不同类型的控件具有部分相同的属性,也具有一些不同的专有属性。

控件的相同属性包括:名字,形状,位置,大小,设置格式。控件的专用属性包括:展示内容,接受输入,用户交互,日期,框架,等等。

所有的 Qt 控件都是 QWidget 类的子类,继承了 QWidget 类的属性。因此,我们学习控件可以按类进行学习,先学习其继承的父类的通用属性,再学习控件所特有的专有属性。对于控件的学习就是一个类的继承关系的结构图。

我们以图形界面 uiDemo5.ui 为例,介绍控件的通用属性,并对控件的属性进行编辑修改。

如前所述,QtDesigner 右侧上方的 “对象查看器” 显示了界面中的控件名称和结构,下方的 “属性编辑器” 显示了选中的控件对象的各种属性。在图形界面中选择某个控件,或者在 “对象查看器” 中选择某个控件,在"属性编辑器" 就会显示该控件对象的属性。


不论是窗口对象 MainWindow、菜单栏 menubar、工具栏 toolBar,还是按钮 pushButton、编辑行 lineEdit,都有一些相同的属性,例如:

  • objectName:控件名,非常重要。准确的说是控件的 ID,Python 程序中访问控件、控件交互都是使用 objectName。所有控件都必须具有唯一的 objectName,不能重名。不能使用中文字符。
  • geometry:控件的大小和位置。
    • 控件的宽度和高度可以修改,对于 MainWindow 来说控件的宽度/高度就是图形界面程序窗口的宽度/高度。
    • 控件位置 (X, Y) 是控件在窗口控件的坐标值,MainWindow 的控件位置不能修改,其它控件的位置 (X, Y) 可以根据需要修改。
    • minimumSize、maximumSize 是主窗口大小拉伸后,控件对象的最小尺寸、最大尺寸。
  • font:控件显示的字体选择,包括字体、字号、风格、效果等选项。

4.3 PyQt5 的控件类型

要了解 QtWidgets 类的子类,可以使用 “subclasses()” 将所有的子类打印出来,共有约 30个子类。

    import PyQt5
    print(QtWidgets.QWidget.__subclasses__())

这些控件类型,总体上可以分类如下:

  • 输入控件:

    • 按钮:QPushButton(按键按钮),QToolButton(工具按钮),QRadioButton(单选框),QCheckButton(多选框),QCommandLinkButton(连接命令的按钮)
    • 键盘输入控件:QlineEdit(单行输入),QTextEdit(多行输入),QPlainTextEdit(普通多行输入),QkeySequenceEdit(快捷键输入)
    • 调节输入控件:QAbstractSpinBox(步长调节输入),QDateEdit(日期输入),QTimeEdit(时间输入),QDateTimeEdit(日期和时间输入)
    • 数字调节框控件:QSpinBox(整型数字调节框),QDoubleSpinBox(浮点数字调节框)
    • 滑动输入控件:QDial(旋转拖滑输入),QSlider(直线拖动输入),QScrollBar(滚动条),QRubberBand(橡皮筋拖拽)
    • 下拉输入控件:QComboBox(组合框下拉选项),QSlider(直线拖动输入),QScrollBar(滚动条),QRubberBand(橡皮筋拖拽)
    • 对话框输入控件:QDialog(对话框),QColorDialog(颜色对话框),QFileDialog(文件对话框),QFontDialog(字体对话框),QInputDialog(输入对话框)
    • 日历控件:QCalendarWidget(日期选择部件)
  • 显示控件:

    • 内容显示控件:QLabel(显示框),QLCDNumber(液晶显示器),QProgressBar(进度条)
    • 对话框显示控件:QMessageBox(信息提示框),QErrorMessage(错误提示框),QProgressDialog(进度提示框)
  • 高级控件:

    • 容器控件:QToolBox,QDialogButtonBox,QGroupBox,QMdiSubWindow
    • 结构控件:QMainWindow,QTabwidget,QStackedWidget,QSplitter,QDockWidget
    • 滚动控件:QTextBrowser,QScrollArea,QAbstractItemView,QMdiarea,QGraphicsView
    • 辅助控件:QFocusFrame,QSizeGrip,QDesktopWidget
    • 其它控件

在 QtDesigner 左侧的 “WidgetBox” 工具栏中,将常用的控件按类别进行分组。用鼠标将工具栏中的控件图标拖拽到 QtDesigner 中间的图形界面编辑窗口,就在图像界面创建了一个所选择的控件。



5. PyQt5 的基本布局管理

关于 PyQt5 的布局管理,具体内容请详见:Python 小白从零开始 PyQt5 项目实战(5)布局管理

5.1 什么是布局管理

布局管理就是管理图形窗口中各个部件的位置和排列。

网站、报纸要对发布的文章设置栏目、布局管理,使页面整齐有序、美观大方。图形窗口中的大量部件也需要通过布局管理,对部件进行整理分组、排列定位,才能使界面友好。

图形窗口中部件的位置有两种模式来管理:绝对定位和局部类。

绝对定位就是指定部件相当于窗口的位置坐标 (X,Y) 和部件的高度、宽度。我们在此前文章中的例程,都是直接设置控件的位置和大小来管理的。

布局类则是使用各种布局方案进行布局管理。

PyQt5 提供了四种布局管理器:水平布局、垂直布局、栅格布局和表单布局。

在 QtDesigner 左侧工具栏中,第一组工具 “Layout” 就是布局管理器,分别提供了 4种布局管理的工具按钮:垂直布局(Vertical Layout)、水平布局(Horizontal Layout)、栅格布局(Grid Layout)和表单布局(Form Layout)。


5.2 水平布局(Horizontal Layout)

水平布局将多个控件在水平方向排列,控件之间的间隔相同。

QtDesigner 创建水平布局有两种使用方法:方法一是先创建水平布局中的各个控件,然后将控件加入水平布局;方法二是先创建一个水平布局,再在该水平布局内依次创建各个控件。

以方法一为例创建水平布局:

  • 先在窗口中创建几个按钮控件,控件位置可以任意布置,图形窗口显示与上图绝对定位时类似;
  • 点击鼠标左键并拖拽拉伸,全部选中创建的几个按钮控件,此时每个按钮控件周围都出现定位小方块,这些按钮控件都处于选中状态;
  • 点击鼠标右键,唤出下拉菜单,选择 “布局” -> “水平布局” 选项;或者直接按 “Ctrl+1” 快捷键,就为选中的控件创建了一个水平布局。

添加到水平布局框中的控件,其大小和位置是由水平布局框自动设置的。布局框中控件的大小和位置属性,不能在 “属性编辑器” 中直接进行编辑修改。

如果自动布局的按钮位置不合适,可以在布局框中添加间隔控制器 “Horizontal Spacer”,以调整按钮控件的间隔。

如下图所示,在上方的水平布局框中,多个按钮控件在水平方向排列,控件之间的间隔相同。在下方的水平布局框的顶部和底部分别添加了一个间隔控制器,将按钮控件调整到所需的位置。


5.3 垂直布局(Vertical Layout)

垂直布局将多个控件在垂直方向排列,控件之间的间隔相同。

与水平布局类似,QtDesigner 创建垂直布局有两种使用方法:方法一是先创建垂直布局中的各个控件,然后将控件加入垂直布局;方法二是先创建一个垂直布局,再在该垂直布局内依次创建各个控件。

以方法二为例创建垂直布局:

  • 在 QtDesigner 左侧工具栏的 “Layout” 类中,鼠标点击选择垂直布局按钮 “Vertical Layout” 后,将其拖动至中间的图形窗口内;
  • 此时在图形窗口中出现一个红色直线矩形框,表示所创建的垂直布局框。鼠标选中垂直布局框,在控件边界处出现几个蓝色的小方块,拖动蓝色方块可以调整布局框大小;
  • 从 QtDesigner 左侧工具栏中,选择按钮控件或其它控件,并拖动到图形窗口中的垂直布局框区域内,就将创建的控件添加到垂直布局框。

添加到垂直布局框中的控件,其大小和位置是由垂直布局框自动设置的。布局框中控件的大小和位置属性,不能在 “属性编辑器” 中编辑修改。

如果自动布局的按钮位置不合适,可以在布局框中添加间隔控制器 “Vertical Spacer”,以调整按钮控件的间隔。

如下图所示,在左侧的垂直布局框中,多个按钮控件在垂直方向排列,控件之间的间隔相同。在右侧的垂直布局框的顶部和底部分别添加了一个间隔控制器,将按钮控件调整到所需的位置。


5.4 嵌套布局

嵌套布局是指在一个布局内嵌套其它布局,可以实现在一个窗口中综合应用多种布局。

例如,整个窗口采用水平布局,分为左右两部分,左侧采用垂直布局,右侧采用栅格布局。但如下图所示,布局效果不尽人意。窗口水平布局虽然分为左右两部分,但水平布局器自动设置为等幅面、等间隔。即使使用间隔器进行调整,也难以达到满意的效果。


5.5 容器布局

容器布局将容器控件(Container)与布局管理器结合,先用容器控件将窗口分为若干区域,再在每个区域内加入布局管理器。

建立容器控件后,可以直接将其它控件加入容器控件内;也可以在容器控件加入布局管理器,再向布局管理器加入多个控件,使多个控件按布局要求放在容器中。

  • 首先在 QtDesigner 左侧工具栏的 “Containers” 类中,选择 “Frame” 控件或 “Widget” 控件将其拖动至中间的图形窗口中,创建容器控件。
  • 对图形窗口中的容器控件 “Frame” 或 “Widget”,可以选中后用鼠标拖动、拉伸来调整控件的位置和大小,或者在 “属性编辑器” 中设置 (X, Y)、宽度、高度属性。
  • 对于需要进行布局管理的容器控件,从在 QtDesigner 左侧工具栏的 “Laytout” 类中选择所需的布局管理器控件,将其拖动至容器控件中,创建容器控件的布局管理器。

容器布局就像网站、报刊中的栏目、子版,可以按照编辑的要求便捷、自由地进行布局。例如,我们要将程序窗口按照十字分割方案分为上下和左右四个部分,就在窗口先创建四个 “Frame” 容器控件,并调整其位置和大小,然后向一个或几个 “Frame” 容器控件加入所需的布局管理控件。如下图所示,可以实现对程序窗口的自由分割和布局。

进一步地,对每个 “Frame” 容器控件,依次添加输入输出控件。对于设置布局管理的容器,添加的控件按照布局设置自动排列在容器的空间内。



6. 多窗口切换的堆叠布局

关于 PyQt5 的布局管理,具体内容请详见:Python 小白从零开始 PyQt5 项目实战(6)窗口切换的堆叠布局

6.1 什么是堆叠布局(Stacked Layout)

布局管理就是管理图形窗口中各个部件的位置和排列。图形窗口中的大量部件也需要通过布局管理,对部件进行整理分组、排列定位,才能使界面友好。上一篇文中我们介绍了基本的水平布局、垂直布局、栅格布局、表格布局和进阶的嵌套布局和容器布局。

在容器布局中,通过容器控件(Containers)与布局管理器(Layouts)的结合,可以实现对程序窗口的分割和布局,就可以自由设计各种丰富的图形界面。

在实际的软件项目中,通常需要多种/多个不同的图形界面,以适应不同的任务场景。如何实现多窗口图形界面的需求呢?大致来说有几种思路:

  • 使用弹出窗口。主窗口提供基本界面,通过弹出窗口实现子任务界面,子任务结束后关闭弹出窗口回到主窗口。
    这是一种可行的,也比较简单的处理方案,很多应用程序中都设有弹出窗口。但是频繁弹出和关闭窗口的用户体验不好,而且在窗口之间的切换不方便。

  • 重建图形界面。当调用新的图形界面时,关闭后删除现有界面上的所有控件,再新建需要的各种控件。
    这种方案虽然可行,但是编程复杂、浪费资源、容易出错,难以适应多窗口相互切换的要求,因此很少使用。在 QtDesigner 中也不支持这种方案的操作。

  • 通过堆叠布局实现多窗口切换。堆叠布局是在窗口的整体或局部区域设置多组图形界面,根据需要使用指定的图形界面。

打个比方,这就好比戏剧或拍照中准备了多种背景幕布,需要什么场景,就展开所需的场景幕布,而把其它幕布收起来。

QStackedLayout 类提供了多页面切换的堆叠布局。

  • 选项卡控件(QTackedWidget)提供了选项卡对话框,外观类似于浏览器页面打开多个标签页。选项卡控件允许创建多个对话框页面,每个页面带有自己的标签。使用时点击标签行进行选择,就打开对应的对话框页面,不需要另外编程。
  • 堆叠窗口控件(QStackedWidget)提供了更加通用和灵活的多窗口、多页面切换的解决方案。QStackedWidget 控件可以添加在整个窗口或窗口中的任意区域,允许在堆叠窗口区域内设计多个页面,在程序控制使用指定的窗口界面。
  • 堆叠窗口控件(QStackedWidget)需要在主程序中通过编程来控制显示的图形界面,相对于选项卡控件(QTackedWidget) 来说比较复杂,但因此也更加灵活。

6.2 创建多窗口切换的堆叠布局

  • (1)以上文 uiDemo6.ui 为基础:图形窗口的左侧上部为垂直布局的按钮控件区域 leftLayout_1,设有多个按钮控件,用于选择不同的业务;左侧下部为垂直布局的文本区域 leftLayout_2,设有文本显示框。
  • (2)将图形窗口右侧的主体区域设计为堆叠窗口,用于设计多个图形界面,以适应不同的业务场景:
    • 在 QtDesigner 左侧工具栏 “Containers” 类中,选择 “Stacked Widget” 控件,将其拖动至设计的图形窗口中,创建堆叠布局的容器控件。
    • 对窗口中的堆叠容器 “Stacked Widget”,选中后可以用鼠标拖动、拉伸来调整控件的位置和大小,或者在 “属性编辑器” 中设置 (X, Y)、宽度、高度属性。
    • 堆叠容器 “Stacked Widget” 自动建立了 2个页面。鼠标位于堆叠容器 “Stacked Widget” ,右键唤出下拉菜单,选择 "插入页"可以插入新的页面,选择 “改变页顺序” 可以调整各页面的顺序。
    • 在控件的右上角显示有一对黑色三角符号,可以在多个页面之间切换,也可以在 “对象查看器” 中选择要编辑的页面。
  • (3)堆叠容器 “Stacked Widget” 中各页面的设计,具体设计内容是根据业务需要确定的。
    • page_0 的设计:标签控件 label_1 用于显示封面图片,按钮控件 pushButton_6~8 用于控制翻页;
    • page_1 的设计:水平布局的标签控件 label_2、label_3 用于显示原始图片和处理图片,控件用于控制处理方法和参数,按钮控件 pushButton_9~11 用于控制翻页;
    • page_2 的设计:表格控件 tableWidget 控件用于显示表格数据,按钮控件用于控制。

6.3 堆叠布局的主程序设计

使用堆叠窗口控件(QStackedWidget)建立的堆叠布局界面,要在主程序中通过编程控制显示哪一个图形界面。

6.3.1 多页面切换的方法

QStackedWidget 类继承自 QFrame类。QStackedWidget 类提供了多页面切换的布局,一次只能看到一个界面。

使用如下程序可以设置 page_0 为当前显示的页面:

    pageNo = 0  # 设置 page_0 为索引页(第一页面)
    self.stackedWidget.setCurrentIndex(pageNo)  # 设置使用 pageNo=0 作为当前显示页面

需要注意的是,不论我们为每个页面控件设置的名称(objectName)是什么,在 QStackedWidget 类中定义的页面索引 index 都是一个从 0 开始计数,即:第一页面的索引值 index=0,第二页面的索引值 index=1,…。

因此,为了避免混淆,建议将 StackedWidge 控件的第一页面命名为 objectName: page_0,第二页面命名为 objectName: page_1,…


6.3.2 建立信号/槽连接

建立信号/槽连接,既可以在 QtDesigner 中设置,也可以在主程序中通过程序实现。


6.3.3 页面控制程序

通过编程控制堆叠窗口控件的显示页面,就是说当前显示哪一个图形界面。

一种简单的方法是,在任务场景的子程序中,直接使用 setCurrentIndex() 设置选择堆叠控件的显示页面。通俗的说就是,任务需要使用哪个场景时,就在程序中编写页面设置语句进行选择。例如:

def click_pushButton_1(self):  # 点击 pushButton_1 触发
    self.textEdit.append("当前动作:click_pushButton_1")
    self.textEdit.append("选择堆叠布局页面:page_0")
    self.stackedWidget.setCurrentIndex(0)  # 打开 stackedWidget > page_0
    self.label_1.setPixmap(QtGui.QPixmap("../image/fractal01.png"))
    return

6.3.4 堆叠布局中的控件操作

控件操作包括控件发出信号和在槽函数中进行操作。

在用户编写的程序中,需要接收控件信号、或在槽函数中对控件进行操作,都要通过控件的 objectName 来实现。

例如,点击按钮 “第一章”(pushButton_1),就选择堆叠布局页面 “page_0”;要在标签控件 “label_1” 显示图片 “…/image/fractal01.png”,就使用以下的程序:

    self.label_1.setPixmap(QtGui.QPixmap("../image/fractal01.png"))

而对于堆叠布局页面 “page_0” 中的按钮控件 “上一张”、“下一张”、“返回”,要实现点击按钮时执行相应的任务,则应以控件的 objectName 建立触发信号与槽函数的连接。



7. 折叠侧边栏的实现

关于折叠侧边栏的实现,具体请详见:Python 小白从零开始 PyQt5 项目实战(7)折叠侧边栏的实现

7.1 什么是折叠侧边栏

折叠侧边栏在实际项目中也非常实用,可以实现软件功能或目录的导航。

折叠侧边栏,是指可折叠的多级菜单式状态栏,位于于窗口的左右侧边。

折叠侧边栏也称为垂直多级菜单,因此其外观、功能与操作与菜单栏基本相似。

折叠侧边栏通常只展开第一级目录(根目录)的内容,可以显示文本、图标和按键,点击上一级目录可以展开或折叠下一级的目录。点击最底层目录可以完成指定的操作,如执行所连接的槽函数。

折叠侧边栏的形式多样,如网站导航、资源管理器的目录形式,或手风琴形式、滑动菜单形式、按键列表形式。

QtDesigner 提供了多种部件,可以实现不同形式的折叠侧边栏。

树结构部件 Tree View 和 Tree Widget 可以建立目录树结构的侧边栏,二者分别基于模型(Model)和项目(Item), Tree Widget 是 Tree View 的子类。

抽屉结构部件 ToolBox 是一种容器布局控件,可以建立菜单形式或按键列表形式的侧边栏。


7.2 目录结构的折叠侧边栏

目录结构的折叠侧边栏的外观和使用类似于资源管理器中的目录管理。

使用 QtDesigner 建立目录结构的折叠侧边栏的步骤如下:

  • (1)以上文 uiDemo8.ui 为基础,在图形窗口的左侧创建一个垂直布局器 leftLayout,在图形窗口的中间和右侧创建一个堆叠布局器 stackedWidget。堆叠布局的页面布局和设计详见上文,本文不作赘述。
  • (2)在 QtDesigner 左侧工具栏 “ItemWidgets” 类中,选择树窗口部件 “Tree Widget”,将其拖动至垂直布局器 leftLayout 中,就创建一个树窗口部件,将部件名(objectName)设为 “treeWidget”。
  • (3)树窗口部件 “treeWidget” 的属性编辑:
    • 树窗口部件 “treeWidget” 的大小、位置属性编辑与其它控件类似,选中后可以用鼠标拖动拉伸,或在属性编辑器中修改;
    • 鼠标选中树结构控件 “treeWidget”,右键唤出下拉菜单,选择 “编辑项目”,弹出 “编辑树窗口部件” 对话框;
    • 对话框中 “列©” 选项:“treeWidget” 可以设置一列或多列,本例中只需要设置一列,编辑列名,如:“章节目录”;
    • 对话框中 “项目(I)” 选项:通过对话框左下方的按钮添加具体的目录信息,其中 “+” 用于添加项目,"-" 用于删除项目,“L+” 用于建立并添加下一级的目录信息。编辑完成后点击 “OK” 保存。

通常我们希望用户在点击侧边栏的目录项目时,应用程序能自动执行该项目的操作,这就需要通过编程实现信号/槽的连接。

对树窗口部件 “treeWidget”,可以将鼠标单击或双击作为触发信号连接到槽函数。例如,点击树窗口部件的目录项 item 时触发信号 itemClicked,执行自定义的槽函数 click_treeWidget()。

但是,树窗口部件 “treeWidget” 是以其整体作为一个控件,不能将目录中每一个项目(item)的鼠标单击或双击作为触发信号连接到一个槽函数,进而执行每个项目各自定义的功能操作。因此,需要在槽函数中判别鼠标所点击的当前项 currentItem,然后再分别执行对应的操作。

相关例程可参见:Python 小白从零开始 PyQt5 项目实战(7)折叠侧边栏的实现


7.3 垂直菜单结构折叠侧边栏

垂直菜单结构的折叠侧边栏类似于多级菜单管理,可以实现手风琴、滑动菜单、按键列表形式的侧边栏。

使用 QtDesigner 建立垂直菜单结构的折叠侧边栏的步骤如下:

  • (1)以上文 uiDemo8.ui 为基础,在图形窗口的左侧创建垂直菜单结构的折叠侧边栏,在图形窗口的中间和右侧创建一个堆叠布局器 stackedWidget。堆叠布局的页面布局和设计详见上文,本文不作赘述。
  • (2)在 QtDesigner 左侧工具栏 “Containers” 类中,选择抽屉部件 “Tool Box”,将其拖动至图形窗口的左侧的适当位置,就创建一个垂直菜单部件,将部件名(objectName)设为 “toolBox”。
    • 新建的垂直菜单部件 “toolBox” 中建立了两个菜单形状的页面,显示为 “Page 1”、“Page 2”,相当于一级菜单的显示内容;
    • 添加菜单页面:鼠标选中垂直菜单部件 “toolBox”,右键唤出下拉菜单,选择 “插入页” ->“在当前页之后/前”,可以插入菜单页面;
    • 整理菜单页面:鼠标选中垂直菜单部件 “toolBox”,右键唤出下拉菜单,选择 “页 *” 可以删除菜单页面,选择 “改变页次序” 可以唤出对话框改变各页面的顺序;
    • 切换当前菜单项:在编辑或使用状态下,都可以点击每个菜单项而将其切换为当前项。当前项的下方有一块空白区域可以插入下级菜单或控件,而非当前项的菜单栏是折叠的。
  • (3)垂直菜单部件 “toolBox” 的属性编辑:
    • 垂直菜单部件 “toolBox” 的大小、位置属性编辑与其它控件类似,选中后可以用鼠标拖动拉伸,或在属性编辑器中修改;
    • 鼠标选中垂直菜单部件 “toolBox”,点击 “Page 1” 后从 QtDesigner 右侧的 “属性编辑器” 中找到 QToolBox -> currentItemName 可以修改当前项 “Page 1” 的 objectName(该属性不是所显示的文本内容,不支持中文)、QToolBox -> currentItemText 修改当前项 “Page 1” 的显示内容(支持中文);
    • 类似地,鼠标选中垂直菜单部件 “toolBox”,点击 “Page 2”、… 后可以在 QtDesigner 右侧的 “属性编辑器” 中修改当前项 “Page 2”、… 的 objectName 及显示内容 “currentItemText”;
  • (4)创建下级菜单控件:
    • 垂直菜单部件 “toolBox” 只建立一级菜单(根目录),并不建立下级菜单;
    • 建立下级菜单控件:点击 “toolBox” 中的菜单项将其切换为当前项,当前项的下方出现一块空白区域,在该空白区域内可以自由添加布局、容器或控件。
    • 本例中向 “toolBox” 中的每个菜单项添加一个垂直布局器(Vertical Layout),再向该垂直布局器中插入一个或多个按键控件(Push Button)作为二级菜单。

上述的创建垂直菜单部件和二级菜单控件的步骤如下图所示:

上节所建立垂直菜单结构的折叠侧边栏,可折叠的一级菜单是由抽屉部件 “Tool Box” 实现的,而二级菜单是由一组按键控件 “Push Button” 实现的。

如同堆叠布局各页面中的每个按键控件是相互独立的不同的控件,垂直菜单结构中的二级菜单按键控件也都是相互独立的不同的控件。这些控件必须具有唯一的 objectName,但可以具有相同的显示内容 “Button Text”。换句话说,在不同的一级菜单项下可能会出现相同显示内容的按键控件,但将被定义为不同 objectName 的按键控件。

由于这种垂直菜单结构的二级菜单都是独立的按键控件,因此建立信号/槽连接的方法,与图形界面中的普通控件的操作是相同的。

对二级菜单按键控件建立了信号/槽连接,就可以在相应的槽函数执行所需的各种操作,而不需要任何判别或控制程序。



8. 项目实战完整例程

8.1 项目图形界面效果

8.2 UI程序(uiDemo11.py)

# Form implementation generated from reading ui file 'uiDemo11.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.
# Copyright 2021 youcans, XUPT


from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1080, 768)
        MainWindow.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("C:/Users/David/.designer/image/youcans.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.line = QtWidgets.QFrame(self.centralwidget)
        self.line.setGeometry(QtCore.QRect(150, 0, 20, 680))
        self.line.setFrameShape(QtWidgets.QFrame.VLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.stackedWidget = QtWidgets.QStackedWidget(self.centralwidget)
        self.stackedWidget.setGeometry(QtCore.QRect(170, 0, 900, 680))
        self.stackedWidget.setObjectName("stackedWidget")
        self.page_0 = QtWidgets.QWidget()
        self.page_0.setObjectName("page_0")
        self.label_1 = QtWidgets.QLabel(self.page_0)
        self.label_1.setGeometry(QtCore.QRect(50, 0, 800, 600))
        self.label_1.setText("")
        self.label_1.setPixmap(QtGui.QPixmap("../image/iconJpeg.png"))
        self.label_1.setAlignment(QtCore.Qt.AlignCenter)
        self.label_1.setObjectName("label_1")
        self.stackedWidget.addWidget(self.page_0)
        self.page_1 = QtWidgets.QWidget()
        self.page_1.setObjectName("page_1")
        self.label_2 = QtWidgets.QLabel(self.page_1)
        self.label_2.setGeometry(QtCore.QRect(20, 20, 400, 查看详情  

python小白从零开始pyqt5项目实战基本控件(代码片段)

本系列面向Python小白,从零开始实战解说应用QtDesigner进行PyQt5的项目实战。什么叫从零开始?从软件安装、环境配置开始。不跳过一个细节,不漏掉一行代码,不省略一个例图。PyQt5提供了丰富的输入输出控件。... 查看详情

python小白从零开始pyqt5项目实战基本控件(代码片段)

本系列面向Python小白,从零开始实战解说应用QtDesigner进行PyQt5的项目实战。什么叫从零开始?从软件安装、环境配置开始。不跳过一个细节,不漏掉一行代码,不省略一个例图。PyQt5提供了丰富的输入输出控件。... 查看详情

python小白从零开始pyqt5项目实战菜单和工具栏(代码片段)

本系列面向Python小白,从零开始实战解说应用QtDesigner进行PyQt5的项目实战。什么叫从零开始?从软件安装、环境配置开始。不跳过一个细节,不漏掉一行代码,不省略一个例图。本文详细解读通过QtDesigner创建主窗... 查看详情

python小白从零开始pyqt5项目实战窗口切换的堆叠布局(代码片段)

本系列面向Python小白,从零开始实战解说应用QtDesigner进行PyQt5的项目实战。什么叫从零开始?从软件安装、环境配置开始。不跳过一个细节,不漏掉一行代码,不省略一个例图。软件项目中经常需要多种不同的图... 查看详情

python小白从零开始pyqt5项目实战信号与槽的连接(代码片段)

本系列面向Python小白,从零开始实战解说应用QtDesigner进行PyQt5的项目实战。什么叫从零开始?从软件安装、环境配置开始。不跳过一个细节,不漏掉一行代码,不省略一个例图。本文讲解信号与槽的连接机制,... 查看详情

python小白从零开始pyqt5项目实战折叠侧边栏的实现(代码片段)

...了一个比较完整的应用程序的UI和程序框架。欢迎关注『Python小白从零开始PyQt5项 查看详情

python大白从零开始opencv项目实战图像读取与显示(代码片段)

...向小白同学,也欢迎“大白”批评指正。本系列面向Python小白,从零开始实战解说OpenCV项目实战。本节介绍图像的读取、保存和显示。除基本方法和例程外,还给出了从网络读取图像、读取/保存中文路径图像、按指... 查看详情

python小白的pyqt5项目实战安装与环境配置(代码片段)

1.PyQt5图形界面开发工具1.1从CLI到GUICLI:命令行用户接口,CommandLineUserInterface。早期的DOS命令行操作是典型的CLI界面,小白开始学习计算机语言编写的程序通常也是CLI界面;需要记忆操作命令,操作不直观。GUI&... 查看详情

python大白从零开始opencv学习课-1.安装与环境配置(代码片段)

...向小白同学,也欢迎“大白”批评指正。本系列面向Python小白,从零开始实战解说OpenCV项目实战。什么叫从零开始?从软件安装、环境配置开始。不跳过一个细节,不漏掉一行代码,不省略一个例图。1.OpenCV计... 查看详情

代码实战——从零开始搭建自己的diffusionmodels/score-basedgenerativemodels

DiffusionModels专栏文章汇总:入门与实战前言:这个系列曾经写过三篇文章专门讲代码,分别从数据集、超参数、loss设计、参数计算、Unet结构、正向过程、逆向过程等部分详细介绍了如何搭建DDPM。Diffusionmodels领域发展神速,最近... 查看详情

python大白从零开始opencv学习课-3.图像的创建与修改(代码片段)

从零开始OpenCV学习课-3.图像的创建与修改本系列面向Python小白,从零开始实战解说OpenCV项目实战。OpenCV中图像的数据结构是ndarray多维数组,对图像的任何操作本质上都是对ndarray多维数组的操作和运算。本节介绍图像的格... 查看详情

python大白从零开始opencv学习课-4.图像的叠加与混合(代码片段)

从零开始OpenCV学习课-4.图像的加法与叠加本系列面向Python小白,从零开始实战解说OpenCV项目实战。本节介绍图像的加法、叠加与混合,提供完整例程和运行结果:加法运算,加权加法,图像混合、切换、遮罩... 查看详情

从零开始vue项目实战-项目结构

现在在浏览器中输入http://localhost:8083,可以看到初始的“WelcometoYourVue.jsApp”页面了目录结构├──README.md项目介绍├──index.html入口页面├──build构建脚本目录│├──build-server.js运行本地构建服务器,可以访问构建后的页... 查看详情

python入门到精通资料大汇总,不啰嗦,全是珍藏资料!速度收藏

今天闲来无事,把手里积累了这么久的Python入门资料整理了一下,发现其实,有了这些,python入门真的不难,每天花点时间学,真的不会影响工作。下面一起来看看这些资料吧!Python编程女匠入门资料列表目录:Python入门书籍资... 查看详情

课题报告opencv抠图项目实战评价指标

Python小白的课题报告—OpenCV抠图项目实战(9)本系列是Python小白的课题作业《基于OpenCV的图像分割和抠图》。需要说明的是,本系列并不能算是OpenCV的抠图项目教程,只是以此为主题的课题报告。其中包括了一个... 查看详情

关东升的《从零开始学swift》3月9日已经上架

     大家一直期盼的《从零开始学Swift》于3月9日已经上架,它是关东升老师历时8个月的呕心沥血所编著,全书600多页,此本书基于Swift2.x,通过大量案例全面介绍苹果平台的应用开发。全书共分5部分,包括Swif... 查看详情

课题总结报告opencv抠图项目实战图像轮廓(代码片段)

Python小白的课题报告—OpenCV抠图项目实战(8)本系列是Python小白的课题作业《基于OpenCV的图像分割和抠图》。需要说明的是,本系列并不能算是OpenCV的抠图项目教程,只是以此为主题的课题报告。其中包括了一个... 查看详情