文章目录(Table of Contents)
简介
使用 PyQt 创建 GUI 的程序大致上有两种方式,1. 使用 Qt Designer 进行设计;2. 直接使用 Python 代码来写 GUI,就像我们上一篇所讲的那样。
一个 GUI 程序主要包含一个 main windows 和若干个 diglogs。QT Designer 可以帮助我们快速生成这些窗口。在这篇教程中,我们会介绍如何使用 Qt Designer 来制作带有 GUI 的应用。
这一篇的内容主要参考自,Qt Designer and Python: Build Your GUI Applications Faster。这里的内容会更加完善一些,可以看完这一篇再看一下他的原文。
Qt Designer 介绍
Qt Designer 简单了解
Qt Designer 是一个「所见即所得」的创建 GUI 的工具。我们可以通过拖拽 QWidget,并且自定义布局等信息来创建界面。Qt Designer 不依赖于任何编程语言,他会生成一个 .ui
的文件,这是 XML 类型的文件,里面包含所有组件,布局等的详细信息。
我们可以使用 pyuic5
来将 .ui
的文件转换为 python 的代码。这部分会在后面的例子中有讲到。
Qt Designer 的安装和运行
我们可以直接通过安装 pyqt5
和 pyqt5-tools
。其中 pyqt5-tools
中会包含一些 Qt 的工具,其中就包含 Qt Designer
。
- pip install pyqt5 pyqt5-tools
当我们安装完毕 Qt Designer
之后,可以在类似下面的路径中找到应用:
- ...Python/Python38/Lib/site-packages/qt5_applications/Qt/bin/designer.exe
打开应用,就可以看到如下的界面,一开始创建的时候,可以有 5 种类型的模板是可以选择的:
Qt Designer 的主界面
在打开 Qt Designer 后会出现创作的主界面(main window),其中会包含一些 dock windows,提供了不同功能,主要有下面这 6 种:
- Widget Box(部件框)重要
- Object Inspector(对象查看器)重要
- Property Editor(属性编辑器)重要
- Resource Browser(资源浏览器)
- Action Editor(动作编辑器)
- Signal/Slot Editor(信号/槽编辑器)
Widget Box 提供了许多关于组件,布局等可选的内容。我们可以直接通过拖拽进行使用。如下图所示,我们可以选择不同的 Layout,不同的 Buttons 等。我们也可以通过搜索框直接进行搜索。
Object Inspector 提供了一个树状的视图来看当前表单中所有的对象。我们可以使用 Object Inspector 对组件进行重命名,修改组件的属性等。下图是一个 Object Inspector 的例子:
Property Editor 用来修改对象的属性的值。如下所示,Property Editor 提供了一个比较好的方式来帮助我们修改对象的属性,例如大小,所在位置等。
最后,在整个界面的最下方,会有三个窗口以 tab 的形式进行展现,这些分别是:
- Resource Browser,增加资源文件,例如图标,图片,或是视频文件等。
- Action Editor,增加 action 并添加到应用中。
- Signal/Slot Editor,连接信号与插槽,即 action 与实际运行的功能进行连接。
使用 Qt Designer 创建一个记事本应用
创建 Main Windows 式应用
创建 Main Menu
当我们创建了一个 Main Windows 的默认模板的时候,他在顶部会提供一个空的菜单按钮(会看到「在这里输入」的字样)。我们双击所在位置,输入一些内容,并按下回车。这样就会创建出一个新的按钮。我们也可以创建下拉菜单的内容,和旁边的按钮,现在获得以下的内容:
之后,我们可以使用 Ctrl+R
来进行预览。或是点击「窗体」->「预览」来进行预览。点击预览之后,我们可以看到如下的效果图:
当我们创建上面内容的时候,可以在 Object Inspector 中看到 QMenu Object
。
同时在动作编辑器中,也可以看到自动添加了一些 action。我们可以双击这些 action 进行自定义,例如修改图标等。
如下图所示,我们添加一些图标(图标可以在这个网站进行下载,Flaticon Icons)。
Create a Toolbar(添加工具栏)
我们可以在 Qt Designer 中添加任意数量的工具栏。我们右键点击,选择「添加工具栏」即可。添加完成之后,我们可以拖动这些工具栏,来移动位置。
接着我们可以从「动作编辑器」中拖动 action 到工具栏中。在工具栏上右键,可以添加分隔符。这一步骤完成之后,整个界面如下所示:
自定义 Central Widget
在使用 Main Windows 的模板时,Central Widget 默认是 QWidget
。我们可以在其上面再放置其他的 Widget
。对于一个记事本应用,我们希望中间是可以编辑文本,进行复制和粘贴操作的区域。于是我们可以将 QTextEdit 拖拽到中间,并设置 vertical layout 作为 central widget 的 layout。
我们在对象查看器中可以看到如下的效果:
添加状态栏
状态栏在整个窗口的底部,通常会用来显示一些信息等。我们可以在 QAction 中设置 statusTip,这样在鼠标放在该图标上的时候,下面状态栏可以显示相应的文字。
完成这些步骤之后,我们就会获得一个文本编辑器的主界面,如下所示,注意状态栏显示的提示内容,这个也是提前设置好的:
创建 Dialog 类型应用
Dialogs 通常是一个比较小的窗口,用来与用户进行交互,或是显示一些信息。我们使用 Dialog without Buttons
模板,并拖动小组件,形成下面的样子(先不用考虑布局)。
接着我们对上面的内容进行布局。一共分为三个部分,如下所示。需要注意的是,最后一部分需要对整个 QDialog 进行 layout 的设置。
经过了上面所有的设置,我们可以得到如下的界面。
连接 Signals 和 Slots
在前面所有的操作中,我们都是在 Widget mode
中。在这个模式,我们可以增加组件,编辑组件的属性等。我们也可以切换为 Edit Signals/Slots
的模式。我们通过上面的按钮进行切换,如下所示:
用户的一些操作,例如点击等,在 PyQt 中被称作事件(event)。当一个事件发生的时候,组件会发出一个信号。这使得我们可以做出相应的动作来响应这个事件。
在 PyQt 中包含一些默认的 event(例如点击)和默认的动作(例如取消等)。我们可以使用鼠标,从 signal-provider widget 拖动到 slot-provider widget。例如下面,我们要设置 Cancel 的功能,我们就从这个按钮拖动到自己,如下所示:
完成了这些操作之后,我们在预览里,点击 Cancel 就可以完成取消这个动作了。
将 Main Windows 与 Dialog 的 UI 文件进行转换
在完成了上面的步骤之后,我们已经创建了一个 Main Window 和 Dialogs。这一小节,我们会将上面设计的两部分 GUI 转换为 Python 可以使用的代码。有两种方式使用上面生成的 .ui
文件:
- Translating the content of your
.ui
files into Python code usingpyuic5
- Loading the content of the
.ui
files dynamically usinguic.loadUi()
第一种方式是使用 pyuic5
来将 .ui
文件转换为 python 代码。使用这种方式的一个好处是效率比较高,但是每次我们使用 Qt Designer 修改了 .ui
文件,都需要重新进行转化。
第二种方式是使用 uic.loadUi
动态的加载 .ui 文件。这种方式会比较适合与不占大量加载事件的小型 GUI,或是适合开发阶段,需要经常对 GUI 进行变化。
下面我们会将上面两种方式都进行尝试。现在我们有两个 .ui
文件,分别是:
main_window.ui
with the GUI of a sample text editor applicationfind_replace.ui
with the GUI of a Find and Replace dialog
算上所有的 icon 图标,我们的文件目录可以像下面这样进行设计:
- xxxxxxxx/
- │
- └── ui/
- ├── resources/
- │ ├── cabinet.png
- │ ├── vector.png
- │
- ├── find_replace.ui
- └── main_window.ui
一般情况下,主界面也就是 main_window.ui
会比较复杂,所以我们首先使用 pyuic5
进行转换。我们使用下面的代码进行转换:
- pyuic5 -o main_window_ui.py ui/main_window.ui
上面的命令会生成一个 main_window_ui.py
的文件。这个文件中包含着从 main_window.ui
中转换来的文件。一般情况下,自动生成的文件,我们是不进行修改的,后面会直接进行使用。
在生成的 main_window_ui.py
的文件中,包含 Ui_Editor
这个类。其中包含所有生成主界面的代码。其中 .setupUi()
包含创建所有组件和布局的代码。.retranslateUi() 会包含一些翻译的内容。这部分我们没有涉及。
对于 find_replace.ui
文件来说,这个文件会相对而言比较小,因此我们采用 uic.loadUi()
的方式进行导入。
将 Main Window 与 Dialog 组合在一起
下面是最后一步,我们需要将上面创建的所有内容组合在一起。我们创建一个新的文件为,app.py
. 该文件的完整的代码如下所示:
- import sys
- from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow, QMessageBox
- from PyQt5.uic import loadUi
- from main_window_ui import Ui_Editor
- class FindReplaceDialog(QDialog):
- """在 Dialog 窗口上的 button 上增加 action, 可以显示消息
- """
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- loadUi('D:/SenseTime/pyqt_learn/text_edit/ui/find_replace.ui', self)
- self.FindButton.clicked.connect(self.about) # 绑定按钮
- def about(self):
- QMessageBox.about(
- self,
- "This is Find and Replace",
- "<p>Q Message Box</p>"
- "<p>{}</p>".format(self.FindlineEdit.text()),
- )
- class Window(QMainWindow, Ui_Editor):
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self.setupUi(self) # 初始化组件和布局
- self.connectSignalsSlots() # 绑定触发的动作
- def connectSignalsSlots(self):
- self.actionAbout.triggered.connect(self.about) # 点击 about 会触发介绍
- self.actionFind.triggered.connect(self.findAndReplace) # 点击 find 触发一个 Dialog
- def findAndReplace(self):
- dialog = FindReplaceDialog(self)
- dialog.show()
- dialog.exec()
- def about(self):
- QMessageBox.about(
- self,
- "About Sample Editor",
- "<p>A sample text editor app built with:</p>"
- "<p>- PyQt</p>"
- "<p>- Qt Designer</p>"
- "<p>- Python</p>",
- )
- if __name__ == "__main__":
- app = QApplication(sys.argv)
- win = Window()
- win.show()
- sys.exit(app.exec())
在上面的代码中我们分别写了两个类,分别对应 Dialog
窗口和 Main Windows
窗口。具体的可以查看上面的代码。目前整个文件目录的结构如下所示:
- D:.
- │ app.py
- │ main_window_ui.py
- │ __init__.py
- │
- ├─ui
- │ │ find_replace.ui
- │ │ main_window.ui
- │ │
- │ └─resources
- │ cabinet.png
- │ vector.png
运行 app.py
文件,会得到如下的运行效果,分别是:
- 点击 Help-->About,弹出一个对话框;
- 点击 Edit-->Find,会弹出一个 Dialog;
- 在弹出的 Dialog 中,点击 Find,也会弹出一个对话框;
- 微信公众号
- 关注微信公众号
- QQ群
- 我们的QQ群号
评论