Qt Designer 是一款工具软件,它允许用户通过拖放控件到窗体上,以可视化的方式构建 PyQt 应用程序的图形用户界面(GUI),而无需手动编写布局代码。在 Python 中,可以将这些设计保存为”.ui”文件并将其加载到应用程序中,这可以显著加快 GUI 开发速度。

1] Qt Designer 简介

Qt Designer 是一个 Qt 工具,它提供所见即所得(WYSIWYG)的用户界面,让用户能够高效地为 PyQt 应用程序创建图形用户界面(GUI)。使用此工具,可以通过在空白窗体上拖放 QWidget 对象来创建 GUI。之后,还可以使用不同的布局管理器将它们排列成一个统一的 GUI。

Qt Designer 还允许用户使用不同的样式和分辨率预览 GUI,连接信号和槽,创建菜单和工具栏等。

Qt Designer 与平台和编程语言无关。它不生成任何特定编程语言的代码,而是生成”.ui”文件。这些文件是 XML 文件,其中包含有关生成基于 Qt 的 GUI 的详细描述。

可以使用 pyuic6(PyQt 自带的命令行工具)将”.ui”文件的内容转换为 Python 代码。然后,就可以在 GUI 应用程序中使用这些 Python 代码。还可以直接读取”.ui”文件并加载其内容以生成相关的 GUI。

安装和运行 Qt Designer

安装 Qt Designer 的方法有多种,具体方法取决于所使用的平台。事实上,Qt Designer 是一个独立的应用程序,因此需要分别安装两个部分:代码将使用的 PyQt6 软件包,以及 Qt Designer 应用程序本身。

首先,创建并激活一个 Python 虚拟运行环境,并使用 pip 工具安装 PyQt6 软件包:

$ python3 -m venv ./venv
$ source venv/bin/activate
(venv) $ python -m pip install pyqt6

以上命令将创建并激活一个 Python 虚拟环境并安装 PyQt6 以及所需的 Qt 库软件。它还会提供 pyuic6,这是一个命令行工具,可以使用它来将”.ui”文件转换为 Python 代码。

注意:在 PyQt5 中,是通过 pyqt5-tools 包安装 Qt Designer 的。在 PyQt6 中,pyqt6-tools 已停止维护,并且无法在当前的 Python 版本上安装,因此需要单独安装 Qt Designer。

然后,安装 Qt Designer 应用程序。由于 Qt Designer 将其工作保存在与绑定无关的”.ui”文件中,因此可以选择最适合使用平台的方式获取该工具。

即使应用程序代码使用了 PyQt6,获取 Qt Designer 的最快跨平台方法是安装 PySide6,它自带一个可直接运行的 Qt Designer:

(venv) $ python -m pip install pyside6
(venv) $ pyside6-designer

运行”pyside6-designer”命令会启动与直接从 Qt 获取的相同的 Qt Designer。可以在此设计 GUI,然后通过 PyQt6 加载生成的”.ui”文件。

当然,也可以通过针对特定平台的方式安装 Qt Designer:

  • Linux:在基于 Debian 的发行版(如 Ubuntu)上,可以使用”sudo apt install designer-qt6″进行系统级安装
  • macOS:如果使用 Homebrew(命令为”brew install qt”)安装 Qt,同时将获得 Qt Designer 以及其他 Qt 6 工具
  • Windows:下载适用于所用平台的 Qt 在线安装程序(Qt Online Installer),并按照屏幕上的说明进行操作,使用该方式时需要一个免费的 Qt 账户来完成安装

如果使用了上述”pyside6-designer”命令,Qt Designer 应该已经在运行了。如果启用成功,屏幕上就会出现以下两个窗口:

图.1 Qt Designer 启动界面

前景中的窗口是 Qt Designer 的”新建窗体(New Form)”对话框,背景中的窗口则是 Qt Designer 的主窗口。

使用 Qt Designer 的”新建窗体”对话框

启动 Qt Designer 时,首先会看到应用程序的主窗口以及”新建窗体”对话框。在该对话框中,可以从五种可用的 GUI 模板中进行选择。这些模板提供了创建对话框、主窗口和自定义部件(widgets)的选项:

模板 窗体类型 组件 基类
Dialog with Buttons Bottom Dialog 包含确定和取消按钮水平排列在右下角的对话框 QDialog
Dialog with Buttons Right Dialog 包含确定和取消按钮垂直排列在右上角的对话框 QDialog
Dialog without Buttons Dialog 空白对话框 QDialog
Main Window Main Window 包含顶部菜单栏和底部状态栏的主窗体 QMainWindow
Widget Widget 空白部件 Widget

默认情况下,运行 Qt Designer 时,”新建窗体”对话框会显示在最前面。如果未显示,可以单击 Qt Designer 工具栏上的”新建”按钮;也可以单击主菜单中的”文件”→”新建”,或按键盘上的 Ctrl+N。

在”新建窗体”对话框中,可以选择要使用的窗体模板,然后单击”创建”按钮生成新窗体。

需要注意的是,前两个对话框模板自带默认按钮。这些是包含在”QDialogBu​​ttonBox”中的标准按钮;该类会自动处理不同平台上按钮的位置或排​​列顺序。

例如,如果使用取消(Cancel)和确定(OK)按钮,macOS 上的标准做法是按该顺序排列,即先显示取消;而在 Windows 上,顺序则相反,先显示确定,后显示取消。在 Linux 上,惯例取决于桌面环境:GNOME 遵循 macOS 的规范,而 KDE 则遵循 Windows 的规范。QDialogBu​​ttonBox 会自动处理这些差异。

使用 Qt Designer 的主窗口

Qt Designer 的主窗口提供了一个菜单栏,其中包含用于保存和管理窗体、编辑窗体及切换编辑模式、布局和预览窗体,以及调整应用程序设置和访问帮助文档的选项。

图.2 Qt Designer 主窗口菜单

主窗口还提供了一个工具栏,其中显示常用选项。在编辑和布局窗口控件时会用到其中的大部分选项。这些选项在主菜单中也可用,尤其是在文件、编辑和表单菜单中:

图.3 Qt Designer 主窗口工具栏

Qt Designer 的主窗口还包含若干停靠窗口,提供了丰富的功能与工具:

  • 窗口部件盒(Widget Box)
  • 对象检查器(Object Inspector)
  • 属性编辑器(Property Editor)
  • 资源浏览器(Resource Browser)
  • 动作编辑器(Action Editor
  • 信号/槽编辑器(Signal/Slot Editor)

窗口部件盒提供了各种布局管理器、间隔器、标准部件及其他对象,用来为对话框和窗口构建图形用户界面 (GUI):

图.4 Qt Designer 窗口部件盒

窗口部件盒在窗口顶部提供了一个筛选选项。可以输入特定对象或组件的名称,以便快速找到它们。这些对象按其具体用途进行了分类。点击类别标签旁边的控制柄,即可显示或隐藏该类别下的所有可用对象。

在创建窗口时,可以使用鼠标指针从窗口部件盒中选取对象,然后将其拖放到窗口对象上,以构建图形用户界面(GUI)。

窗口部件盒还在窗口底部提供了一个空白的”便条”(Scratchpad)区域。在此区域中,就可以将常用对象归入一个单独的类别。我们可以将表单上现有的组件拖放回窗口部件盒中,从而将其添加到便条类别里。若要从便条类别中移除组件,只需右键点击该组件,并在弹出的上下文菜单中选择移除(Remove)即可。

对象检查器(Object Inspector)以树状视图显示当前窗口上的所有对象。对象检查器顶部也设有筛选框,方便在树状结构中查找对象。可以使用对象检查器来设置窗口及其部件的名称和其他属性。此外,右键点击任意组件即可调出包含更多选项的上下文菜单:

图.5 Qt Designer 对象检查器

利用对象查看器(Object Inspector),可以管理窗体上的部件(widgets)。用以重命名控件、更新其部分属性、将其从窗体中移除,等等。对象查看器中的树状视图展示了当前窗体上各控件与对象之间的父子层级关系。

属性编辑器(Property Editor)是 Qt Designer 主窗口中显示的另一个可停靠窗口。该窗口包含一个双列表格,列出了当前选中对象的各项属性及其对应的值。顾名思义,可以使用属性编辑器来编辑对象的属性值。

图.6 Qt Designer 属性编辑器

属性编辑器(Property Editor)提供了一种便捷的方式来访问和编辑当前选中对象的属性值,例如名称、尺寸、字体、图标等。编辑器中显示的属性列表会根据你在窗体上选中的对象而动态变化。

属性是按照类层次结构从上到下排列的。例如,如果在窗体上选中了一个”QPushButton”,属性编辑器会先显示”QWidget”的属性,接着是”QAbstractButton”的属性,最后是”QPushButton”自身的属性。请注意,编辑器中的行会显示不同的颜色,以便在视觉上区分它们所属的基类。

最后,还有三个通常以选项卡形式显示在右下角的停靠窗口:

  • 资源浏览器(Resource Browser):提供了一种快速向应用程序添加资源(如图标、翻译文件、图像及其他二进制文件)的方法
  • 动作编辑器(Action Editor):提供了一种创建动作并将其添加到窗体中的方法
  • 信号/槽编辑器(Signal/Slot Editor):提供了一种在窗体中连接信号与槽的方法

这三个停靠窗口完善了 Qt Designer,提供了用于创建和自定义对话框和窗口 GUI 的工具和选项集。

使用 Qt Designer 还是手动编写 GUI 代码

使用 PyQt 创建窗口或对话框的 GUI 至少有两种选择:可以使用 Qt Designer,也可以使用纯 Python 代码手动编写 GUI。两种方法各有优缺点,有时很难决定何时使用哪一种方法。

Qt Designer 提供了一个用户友好的图形界面,可以快速创建 GUI,从而提高开发效率并缩短开发周期。

另一方面,手动编写 GUI 代码可以更好地控制它们。使用这种方法,添加新组件和功能不需要代码编辑器或 IDE 之外的任何额外工具,这在某些开发环境中非常方便。

使用 Qt Designer 还是手动编写 GUI 代码取决于个人选择。以下是关于这两种方法的一些一般性考虑因素:

 

特性需求 Qt Designer 手动编码
开发效率 高(熟悉 PyQt,则效率高;否则效率低)
GUI 逻辑与业务逻辑分离度
对 GUI 组件的控制
动态添加和删除控件的能力
探索、学习、原型设计和草图绘制的灵活性
使用自定义控件的灵活性
模板代码质量

除了以上几点,如果是 PyQt 新手,Qt Designer 可以帮助了解可用的控件、布局管理器、基类、属性及其典型值等。

使用 Qt Designer 和手动编写 GUI 的最后一个区别在于,使用 Qt Designer 需要额外执行一个步骤:将”.ui”文件转换为 Python 代码。

2] 使用 Qt Designer 和 Python 构建主窗口

使用 PyQt,可以构建主窗口式( main window–style)和对话框式(dialog-style)应用程序。主窗口式应用程序通常包含一个带有菜单栏的主窗口、一个或多个工具栏、一个中央控件和一个状态栏。它们还可以包含多个对话框,但这些对话框独立于主窗口。

Qt Designer 允许使用预定义的”主窗口”模板快速构建主窗口的 GUI。创建基于该模板的窗体后,就可以使用以下工具执行相应操作:

  • 创建主菜单
  • 添加和填充工具栏
  • 布局控件

Qt Designer 的”主窗口”模板还在窗口底部提供了一个默认的中央控件和一个状态栏:

图.7 使用主窗口模板创建主窗口

Qt Designer 将窗体保存为”.ui”文件,这是 XML 格式的文件,其中包含了日后在应用程序中重建该 GUI 所需的所有信息。

若要保存窗体,请依次点击”文件”→”保存”(File → Save),在弹出的窗体另存为(Save Form As)对话框中输入”main_window.ui”,选择保存目录,然后点击”保存”(Save)。也可以通过按下键盘上的 Ctrl+S 快捷键来打开”窗体另存为”对话框。

创建主菜单

Qt Designer 的主窗口模板在窗体顶部提供了一个空白菜单栏。可以使用”菜单编辑器”向该菜单栏添加菜单。菜单是选项的下拉列表,用于快速访问应用程序的各项功能。回到 Qt Designer 中刚才创建的主窗口。在窗体顶部,就会看到一个带有”在此处输入”(Type Here)占位符文本的菜单栏。

双击该占位符文本或按下回车键(Enter),即可输入第一个菜单的名称。输入完成后,再次按下回车键即可确认该菜单项的名称。

假设我们要创建一个文本编辑器。通常,此类应用程序会包含一个”文件”(File)菜单,其中至少包含以下部分菜单选项:

  • 新建(New):用于创建新文档
  • 打开(Open):用于打开现有文档
  • 最近打开(Open Recent):用于打开最近查看过的文档
  • 保存(Save):用于保存文档
  • 退出(Exit):用于退出应用程序

下面介绍如何使用 Qt Designer 创建该菜单。

Qt Designer 的菜单编辑器(Menu Editor)可以直观便捷地向菜单栏添加菜单。在输入菜单或菜单选项的名称时,可以在某个字母前加上”&”符号,从而设置键盘快捷键。

例如,如果在 File(文件)菜单的”F”字母前加上”&”符号,就可以通过按下 Alt+F 键来访问该菜单。同样地,如果您在 New(新建)选项的”N”字母前加上”&”符号,那么在打开 File 菜单后,只需按下 N 键即可访问”New”选项。

利用菜单编辑器,还可以向菜单中添加分隔符。这是在视觉上区分菜单选项并按逻辑进行分组的有效方法。若要添加分隔符,只需要在菜单编辑器中双击当前菜单末尾的 Add Separator(添加分隔符)选项。若要移除现有的分隔符,请右键点击该分隔符,然后在弹出的上下文菜单中选择 Remove Separator(移除分隔符);该上下文菜单同时也允许添加新的分隔符。

如果需要将分隔符移动到菜单中的其他位置,只需将其拖动到目标位置并释放鼠标即可。系统会显示一条红线,指示分隔符将要放置的位置。

我们还可以为某个菜单选项添加子菜单。为此,请点击该菜单选项右侧的图标(就像上述示例中 Open Recent 选项的方式一样)。

若要预览窗体,请选择 Form(窗体)→ Preview(预览),或按下键盘上的 Ctrl+R 组合键。

图.8 预览菜单栏

创建菜单(例如示例中的 File 菜单)时,系统会自动向菜单栏添加一个新的 QMenu 对象。向菜单添加选项时,实际上就是创建了一个动作(action)。Qt Designer 提供了”Action Editor”(动作编辑器)来创建、自定义和管理这些动作。该工具提供了一些实用的选项,方便对动作进行微调:

图.9 使用动作编辑器编辑菜单项更多选项

使用操作编辑器,可以微调、更新或设置以下选项:

  • 操作文本(将显示在菜单选项和工具栏按钮上)
  • 对象名称(您将在代码中使用该名称引用操作对象)
  • 菜单选项和工具栏按钮上显示的图标
  • 操作的可勾选属性
  • 键盘快捷键(为用户提供快速访问操作的方式)

菜单选项文本末尾的省略号(…)是一种广泛使用的命名约定,用于表示那些不会立即执行操作,而是会弹出对话框以执行进一步操作的选项。

对于图标,可以将它们作为独立文件与应用程序一起打包,或者创建一个资源文件(即 “.qrc”文件)。

准备好图标文件后,可以在”main_window.ui”文件旁边创建一个”resources”目录,并将图标复制到该目录中。随后,使用动作编辑器(Action Editor),按如下方式为各个动作添加图标:

图.10 使用动作编辑器为菜单项添加图标

使用菜单项的动作编辑器,在图标栏的下拉列表中选择”Choose Resource”使用资源文件或”Choose File”使用图标文件来为菜单项添加图标。

创建工具栏

可以使用 Qt Designer 向主窗口的 GUI 添加任意数量的工具栏。为此,请在窗体上右键单击,并从上下文菜单中选择添加工具栏(Add Tool Bar)。这会在窗口顶部添加一个空白工具栏。或者,也可以通过选择”将工具栏添加到其他区域”(Add Tool Bar to Other Area),预先指定放置特定工具栏的区域:

图.11 Qt Designer 向主窗口添加工具栏

设置好工具栏后,就可以向其中添加按钮了。为此,您需要使用动作(Actions),而不是直接从部件盒(Widget Box)中选取特定的工具栏按钮。可以使用动作编辑器(Action Editor)将动作添加到工具栏中。动作可以在菜单项和工具栏按钮之间共享;因此,我们可以复用之前在构建菜单时创建的那些动作。若要向工具栏添加动作,可以在动作编辑器中点击某个动作,然后将其拖放到工具栏上。此外,在工具栏上右键点击,还可以添加分隔符,以便在视觉上区分各个工具按钮。

布局组件

Qt Designer 使用 QMainWindow 类来构建其主窗口模板。该类提供了一个默认布局,允许创建菜单栏、一个或多个工具栏、一个或多个停靠控件、状态栏以及一个中心控件。默认情况下,Qt Designer 使用 QWidget 对象作为主窗口模板的中心控件。

使用一个基本的 QWidget 对象作为主窗口 GUI 的中心控件是一个不错的选择,因为可以在该控件之上放置一个或多个控件,并保持布局的一致性。

例如,在之前的示例文本编辑器中,可能希望使用一个控件为用户提供一个工作区,以便他们输入、复制、粘贴和编辑文本。为此,可以使用 QTextEdit 控件,然后添加一个垂直(或水平)布局作为中心控件的布局:

图.12 布局单个中央组件

在此示例中,首先将一个 QTextEdit 控件拖放到窗体上。接着,点击窗体以选中中心部件(central widget)。最后,点击 Qt Designer 工具栏上的垂直布局(Lay Out Vertically)按钮,为中心部件应用垂直布局。

由于 QTextEdit 周围的间距看起来不太合适,还可以使用对象查看器(Object Inspector)将布局的边距(margins)从 9 像素调整为 1 像素。

利用 Qt Designer,就可以使用各种布局管理器快速排列控件。可以说,使用 Qt Designer 设计 GUI 时,最便捷的布局方式是利用主工具栏上的布局相关功能区进行快速布局调整。

从左到右,可以找到以下选项来创建不同类型的布局:

选项 控件排列 布局类 键盘快捷键
Lay Out Horizontally(水平布局) 单行多列 QHBoxLayout Ctrl+1
Lay Out Vertically(垂直布局) 单列多行 QVBoxLayout Ctrl+2
Lay Out Horizontally in Splitter(水平分隔符布局) 可调整大小的水平分隔符布局 QSplitter Ctrl+3
Lay Out Vertically in Splitter(垂直分隔符布局) 可调整大小的垂直分隔符布局 QSplitter Ctrl+4
Lay Out in a Grid(网格布局) 多行多列的网格布局 QGridLayout Ctrl+5
Lay Out in a Form(表单布局) 两列表格布局 QFormLayout Ctrl+6

Qt Designer 工具栏中的最后两个选项与布局相关,但不会创建布局:

  • “打破布局”允许打破现有布局,一旦控件排列在布局中,就无法单独移动或调整它们的大小,因为它们的几何形状由布局控制。要修改单个控件,需要打破布局并在以后重新创建。要访问此选项,可以按键盘上的 Ctrl+0
  • “调整大小”会调整布局的大小,以容纳其中包含的控件,并确保每个控件都有足够的空间可见。要使用此选项,可以按键盘上的 Ctrl+J

当然,还可以通过 Qt Designer 的主菜单栏中的”窗体”菜单访问所有这些与布局相关的选项。

布局复合中心控件

创建主窗口时,可能会遇到需要将多个控件组合成一个中心控件的情况。由于 Qt Designer 的主窗口模板自带一个 QWidget 对象作为中心控件,就可以利用这一点创建自定义的控件排列,并将其设置为该中心控件的顶级布局。

如果您需要为主窗口的 GUI 创建复合控件布局,可以按照以下步骤操作:

  • 将控件拖放到窗体上,并尝试将它们放置在所需位置附近
  • 选择需要由特定布局管理的控件
  • 使用 Qt Designer 的工具栏或主菜单,或者使用窗体的上下文菜单应用相应的布局

虽然可以先将布局拖到窗体上,然后再将控件拖到布局上,但最佳实践是先拖动所有控件和间隔符,然后反复选择相关的控件和间隔符,将布局应用到它们。

例如,假设正在构建一个计算器应用程序。就需要一个位于窗体顶部的 QLineEdit 对象来显示运算及其结果。在行编辑框下方,需要几个 QPushButton 对象来显示数字和运算。这样就得到了一个类似这样的窗口:

图.13 未调整布局的计算器界面

这看起来有点像计算器,但其图形用户界面(GUI)显得杂乱无章。若要将其调整为更精致的计算器界面,可以使用网格布局(grid layout)来排列按钮,并采用垂直盒式布局(vertical box layout)作为计算器的顶层布局:

图.14 调整布局后的计算器界面

需要说明的是,对于占用多网络布局中占用多行或都多列的控件(例如示例中的”=”号),可以选中该控件,在其属性编辑器中找到”sizePolicy”,将其中的水平策略和垂直策略由”Fixed”调整为”Expanding”或”MinimumExpanding”。

虽然再在的计算器还需要进一步完善,但外观已经好多了。若想让它更趋完美,可以使用”属性编辑器”微调按钮的各项属性值(例如最大和最小尺寸),还可以设置计算器主窗口的固定尺寸等。不妨自己动手试一试吧!

使用状态栏

Qt Designer 的主窗口模板默认提供了一个状态栏。状态栏是一个水平面板,通常位于 GUI 应用程序主窗口的底部,其主要作用是显示有关应用程序当前状态的信息。

可以将状态栏划分为多个区域,并在每个区域显示不同的信息。状态栏上的信息可以是临时的,也可以是永久的,且通常以文本消息的形式呈现。显示这些信息的目的是让用户随时了解应用程序当前正在执行的操作及其总体状态。

我们还可以利用状态栏显示帮助提示——即简短的说明信息,用于描述特定按钮或菜单项的功能。当用户将鼠标指针悬停在工具栏按钮或菜单项上时,此类消息便会显示在状态栏中。

3] 使用 Qt Designer 和 Python 创建对话框

对话框是一种小型窗口,通常用于提供辅助功能(例如”首选项”对话框),或者通过显示错误信息及操作相关的一般性提示来与用户进行交互。此外,对话框还可用于向用户索取必要信息,或确认即将执行的某项操作。

PyQt 提供了丰富的内置对话框,可直接应用模板。其中大多数对话框均可从”PyQt6.QtWidgets”模块导入。以下是相关概览:

对话框类 目的
QFontDialog 选择和设置给定文本的字体
QPrintDialog 指定打印机设置(从 PyQt6.QtPrintSupport 导入)
QProgressDialog 显示进程运行操作的进度
QColorDialog 选择和设置颜色
QInputDialog 从用户获取单个值
QFileDialog 选择文件和目录
QMessageBox 显示消息,例如错误、常规信息、警告和问题
QErrorMessage 显示错误消息

所有这些内置对话框都可以直接在代码中使用,大多数对话框都提供类方法,可根据需求构建特定类型的对话框。除了这些内置对话框之外,PyQt 还提供了 QDialog 类。这样就可以使用此类在代码中创建自定义对话框,也可以使用 Qt Designer 快速创建对话框。

创建对话框 GUI

要使用 Qt Designer 创建自定义对话框,请从”新建窗体”对话框中选择合适的对话框模板。将所需的控件拖放到窗体上,正确布局,然后将窗体保存为”.ui”文件,以便稍后在应用程序中使用。

返回示例文本编辑器,假设想要添加一个类似如下的”查找和替换”对话框,可以先将所有控件都拖拽至对话框窗口中,然后再调整其布局。

图.15 使用Qt Designer 创建查找替换对话框

首先,使用”无按钮对话框”(Dialog without Buttons)模板创建一个空对话框,并在”对象查看器”(Object Inspector)中将窗口标题设置为”查找和替换”(Find and Replace)。接着,利用”窗口部件盒”(Widget Box)将两个 QLabel 对象拖放到窗体上;这些标签用于提示用户输入需要查找和替换的文本,而用户将在标签旁的相应 QLineEdit 对象中输入这些内容。

随后,将三个 QPushButton 对象拖放到窗体上;这些按钮将允许用户在当前文档中执行查找和替换操作。最后,添加两个 QCheckBox 对象,以提供”区分大小写”(Match Case)和”全字匹配”(Match Whole Word)选项。

将所有控件放置到窗体上后,请务必将其摆放在与最终对话框预期布局相似的位置。之后,就可以开始对这些控件进行布局了。

图.16 调整查找与替换对话框窗口布局

在这里,使用鼠标指针选择标签、行编辑框和复选框,并为其应用网格布局。之后,在”替换”和”取消”按钮之间添加垂直间距,使它们在视觉上保持分离。

最后一步是设置对话框的顶层布局。在本例中,可以使用水平布局管理器。完成!我们就已经使用 Qt Designer 构建了查找和替换对话框的 GUI。将其保存为 Dialog.ui 文件。

我们还可以使用 Qt Designer 调整对话框中的许多其他属性和功能。例如,可以设置输入控件的 Tab 键顺序,以改善用户使用键盘导航对话框的体验。还可以提供键盘快捷键、连接信号和槽等。

连接信号和消息槽

到目前为止,我们一直使用的是 Qt Designer 的默认模式—— 编辑控件模式。在此模式下,可以向窗体添加控件、编辑控件属性、在窗体上布局控件等。同时,Qt Designer 还提供了四种不同的模式,以便处理窗体的不同功能:

模式 用途 菜单选项 键盘快捷键
Edit Widgets 编辑部件 编辑 → 编辑部件 F3
Edit Buddies 设置键盘快捷键 编辑 → 编辑伙伴
Edit Signals/Slots 连接内置信号与槽 编辑 → 编辑信号/槽 F4
Edit Tab Order 设置部件的 Tab 键切换顺序 编辑 → 编辑 Tab 顺序

可以通过点击 Qt Designer 工具栏中”模式”相关区域的对应按钮来进入这些模式。若要编辑部件和窗体的内置信号与槽,首先需要切换到”编辑信号/槽”模式。

在 PyQt 中,用户对控件(widget)或窗体(form)进行的操作(例如点击或按键)被称为事件(event)。当事件发生时,相关的控件会发出一个信号(signal)。这种机制允许对事件执行相应的操作;这些操作被称为槽(slot),它们本质上是方法或函数。

若要响应事件并执行槽函数,需要选择控件因该事件而发出的信号,并将其连接到目标槽函数。

大多数控件(包括对话框和窗口)都实现了内置信号,这些信号会在控件上发生特定事件时触发。此外,控件还提供内置槽,允许执行某些标准化的操作。

若要使用 Qt Designer 在两个控件之间建立信号与槽的连接,需要用鼠标选中发出信号的控件,然后将其拖放到提供槽函数的控件上。这将打开 Qt Designer 的”配置连接”(Configure Connection)对话框。接下来,切换到 Qt Designer 的”编辑信号/槽”(Edit Signals/Slots)模式,然后将”取消”(Cancel)按钮拖放到窗体上:

图.17 将信号以可视方式连接到槽

连接会显示为从信号提供程序控件指向槽提供程序控件的箭头,表示连接已建立。同时还会看到刚刚连接的信号和槽的名称。

在本例中,将”取消”按钮的 clicked() 信号连接到了对话框的 reject() 槽。现在,当单击”取消”按钮时,操作将被忽略,对话框将关闭。

要修改连接,请双击箭头或其中一个标签。这将显示”配置连接”对话框,就可以在其中根据需要更改连接中涉及的信号或槽。

要删除连接,先选择表示连接的箭头或标识信号和槽的标签,然后按 Del 键即可。

设置控件的 Tab 键顺序

为了提升对话框的易用性,可以为输入控件设置合理的 Tab 键切换顺序(Tab order)。该顺序决定了当用户在键盘上按下 Tab 键或 Shift+Tab 组合键时,表单上的控件获取焦点的先后次序。

如果使用 Qt Designer 创建窗口,控件的默认切换顺序取决于在窗口上放置它们的先后次序。有时这种默认顺序并不理想,导致按下 Tab 键或 Shift+Tab 键时,焦点跳转到了意料之外的控件上。我们可以修改对话框中输入控件的 Tab 键切换顺序。请在 Qt Designer 中切换到”编辑 Tab 键顺序”(Edit Tab Order)模式,将看到类似下图的界面:

图.18 设置控件的 Tab 顺序

在”编辑 Tab 键顺序”模式下,窗口中的每个输入控件都会显示一个数字,用于标识其在 Tab 键切换顺序链中的位置。可以通过按期望的顺序点击这些数字来更改该顺序。可以通过按期望的顺序点击数字来更改输入控件的 Tab 键顺序。请注意,当选中某个数字时,它会变为红色,表示这是 Tab 键顺序链中当前正在编辑的位置。尚未设置的数字显示为蓝色,而已设置的数字则显示为绿色。如果操作有误,可以通过表单的上下文菜单选择”重新开始”(Restart)来重新进行排序。

提供键盘快捷键

键盘快捷键是一种按键组合,通过它,可以快速将焦点移动到对话框或窗口中的特定控件(widget)上。此类快捷键由 Alt 键与一个字母组成,该字母用于标识想要访问的控件或选项。使用快捷键有助于提升应用程序的易用性。

若要为带有标签的控件(例如按钮或复选框)设置键盘快捷键,只需在标签文本中打算用作快捷键的字母前加上”&”符号即可。例如,在”查找和替换”对话框的取消(Cancel)按钮标签中的字母”C”前面加上”&”符号。按下键盘上的 Alt+C 组合键,即可选中”取消”按钮并关闭对话框。

要为不包含标签的控件(例如行编辑框)定义快捷键,需要将该控件与某个标签对象关联。创建关联关系需要执行以下四个步骤:

  1. 在标签文本中选择一个字母来标识关联关系并提供快捷键
  2. 在标签文本中选定的字母前加上 & 符号
  3. 在 Qt Designer 中切换到”编辑伙伴”模式
  4. 将标签拖放到关联控件上

例如,以下是如何在”查找”标签及其关联的行编辑框之间创建关联关系:

图.19 通过编辑关联关系为输入框添加快捷键

若要建立标签(label)与控件(widget)之间的”伙伴”关联,请用鼠标选中该标签,并将其拖放到您希望设为”伙伴”的输入控件上。这样,标签与输入控件便建立了关联。此后,只需按下 Alt 键并配合标签文本中指定的字母,即可将焦点切换至相应的控件。

请务必注意,在同一个窗体中,不应存在两个使用相同键盘快捷键的控件。这需要为每个键盘快捷键选择一个唯一的字母。

4] 在应用程序中集成窗口与对话框

至此,我们已经学会了如何使用 Qt Designer 为主窗口和对话框创建 GUI。之后,我们将学习如何将这些 GUI 集成到 Python 代码中,从而构建一个实际的应用程序。在 PyQt 中,主要有两种实现方式:

  • 使用 pyuic6 将 .ui 文件的内容转换为 Python 代码
  • 使用 uic.loadUi() 动态加载 .ui 文件的内容

第一种方法使用 pyuic6(这是 PyQt 安装包中包含的一个工具),它可以将 .ui 文件的内容转换为 Python 代码。这种方法因其高效性而被广泛采用。不过,它也有一个缺点:每当使用 Qt Designer 修改 GUI 时,都需要重新生成代码。

第二种方法利用 uic.loadUi() 将 .ui 文件的内容动态加载到应用程序中。这种方法适用于 GUI 规模较小、不会产生显著加载耗时的场景。

准备使用窗口与对话框

现在,是时候为实际应用程序(本例中为一个简单的文本编辑器)配置窗口和对话框了。如果一直按照本教程操作,那么应该至少拥有两个”.ui”文件:

  • “main_window.ui”:包含简单文本编辑器应用程序的 GUI
  • “dialog.ui”:包含”查找与替换”对话框的 GUI

请创建一个名为”sample/”的新目录。在该目录下,再创建一个名为”ui/”的子目录,并将所有的”.ui”文件复制进去。此外,还要将包含菜单选项和工具栏按钮图标的”resources/”目录复制到 “sample/ui/”目录下。此时,应用程序目录结构应如下所示:

sample/

└── ui/
├── resources/
│ ├── edit-copy.png
│ ├── edit-cut.png
│ ├── edit-paste.png
│ ├── file-exit.png
│ ├── file-new.png
│ ├── file-open.png
│ ├── file-save.png
│ └── help-content.png

├── dialog.ui
└── main_window.ui

由于主窗口的 GUI 相对复杂,可以使用 pyuic6 将 main_window.ui 的内容转换为 Python 代码。pyuic6 工具随 PyQt6 一起提供,鉴于我们的应用程序代码使用的是 PyQt6,因引它是此处最合适的转换工具。

现在,打开终端并进入”sample/”目录。进入该目录后,运行以下命令:

$ pyuic6 -o main_window_ui.py ui/main_window.ui

该命令会根据”ui/main_window.ui”文件生成一个名为”main_window_ui.py”的 Python 模块,并将其存放在”sample/”目录下。”-o”选项用于指定输出文件名,因此需要保证该名称与稍后使用 “from main_window_ui import Ui_MainWindow”语句导入时所用的模块名一致。该模块包含了用于构建主窗口 GUI 的 Python 代码。以下是该代码的一个简短示例:

# Form implementation generated from reading ui file 'ui/main_window.ui'
#
# Created by: PyQt6 UI code generator 6.11.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again.  Do not edit this file unless you know what you are doing.

from PyQt6 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(413, 299)
        self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
        # Skip...

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Sample Editor"))
        self.menu_File.setTitle(_translate("MainWindow", "&File"))
        # Skip...

Ui_MainWindow 包含了用于生成示例编辑器主窗口 GUI 的所有代码。注意,”.setupUi()”中包含了创建所有必要控件并将其布局到 GUI 上的代码;而”.retranslateUi()”则包含了用于国际化和本地化的代码。

注意:如果 pyuic6 无法正常运行,请检查当前的 PyQt 安装情况。如果是在 Python 虚拟环境中安装的 PyQt,则可能需要先激活该环境;或者,也可以进入虚拟环境所在的目录,直接在该目录下运行 pyuic6(通常该程序位于 bin/ 目录下)。

如果是在系统层面安装的 PyQt,那么应该可以直接在命令行中运行 pyuic6,而无需激活虚拟环境。

由于”查找和替换”对话框相对简单,则可以直接使用”uic.loadUi()”从”.ui”文件加载其 GUI。该函数接收一个指向”.ui”文件路径的字符串作为参数,并返回一个实现了该 GUI 的”QWidget”子类。

这种动态加载”.ui”文件的方式在实际开发中并不常用,但适用于那些加载开销较小的简单对话框。采用这种方法,每当使用 Qt Designer 修改”.ui”文件时,无需重新生成对应的 Python 代码,这在某些情况下有助于提高开发效率并简化维护工作。

既然已经确定了各个 GUI 的构建策略,接下来就可以将它们整合到一个完整的应用程序中了。

应用程序中动态加载界面文件

既然构建示例文本编辑器的各项要素已准备就绪,就可以创建应用程序,并编写必要的代码来实现主窗口以及”查找和替换”对话框的功能了。在”sample/”目录下新建一个名为”app.py”的文件,并将以下代码添加到其中:

1     import sys
2     
3     from PyQt6.QtWidgets import (
4         QApplication, QDialog, QMainWindow, QMessageBox
5     )
6     from PyQt6.uic import loadUi
7     
8     from main_window_ui import Ui_MainWindow
9     
10    class Window(QMainWindow, Ui_MainWindow):
11        def __init__(self, parent=None):
12            super().__init__(parent)
13            self.setupUi(self)
14            self.connectSignalsSlots()
15    
16        def connectSignalsSlots(self):
17            self.action_Exit.triggered.connect(self.close)
18            self.action_Find_Replace.triggered.connect(self.findAndReplace)
19            self.action_About.triggered.connect(self.about)
20    
21        def findAndReplace(self):
22            dialog = FindReplaceDialog(self)
23            dialog.exec()
24    
25        def about(self):
26            QMessageBox.about(
27                self,
28                "About Sample Editor",
29            )
30    
31    class FindReplaceDialog(QDialog):
32        def __init__(self, parent=None):
33            super().__init__(parent)
34            loadUi("ui/dialog.ui", self)
35    
36    if __name__ == "__main__":
37        app = QApplication(sys.argv)
38        win = Window()
39        win.show()
40        sys.exit(app.exec())

这段代码的作用如下:

  • 第 3 行导入构建应用程序和 GUI 所需的 PyQt 类
  • 第 6 行从 uic 模块导入 loadUi() 函数。该函数提供了一种动态加载 .ui 文件内容的方法
  • 第 8 行导入 Ui_MainWindow 类,该类包含主窗口的 GUI
  • 第 10 行定义 Window 类,该类将提供应用程序的主窗口,在本例中,该类使用了多重继承,它从 QMainWindow 类继承主窗口功能,从 Ui_MainWindow 类继承 GUI 功能
  • 第 13 行调用 .setupUi() 函数,该函数创建主窗口的完整 GUI
  • 第 16 行定义 .connectSignalsSlots() 函数,该函数连接所需的信号和槽
  • 第 21 行定义 .findAndReplace() 函数,该方法创建并执行查找和替换对话框的实例
  • 第 25 行定义了”.about()”,它会创建并启动一个小型对话框,提供有关应用程序的信息,在本例中,使用的是基于 QMessageBox 的内置对话框
  • 第 31 行定义了”FindReplaceDialog”,它提供了查找和替换对话框
  • 第 34 行调用”loadUi()”从文件”ui/dialog.ui”加载对话框的 GUI
  • 最后,在第 37 行到第 40 行,创建了应用程序,创建并显示了主窗口,并通过调用应用程序对象的”.exec()”来运行应用程序的主循环

需要注意的是,Qt Designer 中操作的命名可能与上述代码中的略有不同。例如,有时可能会看到”.actionE_xit”而不是”.action_Exit”来指代”退出”操作。因此,为了使此示例正常工作,都需要确保使用正确的名称。

如果想使用自己的名称而不是 Qt Designer 生成的名称,则可以转到属性编辑器并将 .objectName 属性更改为合适的名称。

大功告成!我们已经利用 Qt Designer 创建了一个具备基础功能的简单文本编辑器。值得注意的是,实现该应用程序仅需编写 40 行 Python 代码;相比之下,若要从零开始手写同类应用的图形用户界面(GUI),则需要编写多得多的代码。

在开发 PyQt 应用程序时,通常需要构建主窗口及若干对话框。如果采用手写代码的方式来构建这些窗口和对话框的 GUI,往往会耗费大量时间。幸运的是,Qt 提供了 Qt Designer 这一强大工具,它利用直观易用的图形化界面,助你快速、高效地创建 GUI。

借助 Qt Designer,我们可以将所需的各种控件拖放到空白窗体上并进行布局,从而在极短时间内完成 GUI 的构建。这些 GUI 会被保存为”.ui”文件,可以将其转换为 Python 代码并集成到应用程序中。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注