QT 官网:https://www.qt.io/zh-cn/develop
用 Python 编写安卓 APK:https://zhuanlan.zhihu.com/p/398126847
1、PySide6、PyQt6、PyQt5
PySide6、PySide2、PyQt5 都是基于 Qt 库,Qt 是一组 C++ 库和开发工具,包括图形用户界面、网络、线程、正则表达式、SQL 数据库、SVG、OpenGL、XML、用户和应用程序设置、定位和定位服务、短程通信( NFC 和蓝牙)、网页浏览、3D 动画、图表、3D 数据可视化以及与应用商店的交互。,有非常强大的图形界面开发库。
那么 PyQt5、PySide2、PySide6 三者有什么区别 ?
PyQt5 与 PySide2 基本上没有太大区别,都是在 Python 环境下的一套 Qt API库,但是 PySide2 由 Qt 官方维护,不过 pyside 掉了一段时间的队,其间 pyqt 火了,导致用 pyside 的人不多。不过 pyside 的优点在于有详细的官方维护的文档,PySide6 是 PySide2 的更新版本 【Qt 5 升级到 Qt 6 后,PySide2 也跟着升级到了 PySide6 (从2直接到6)】 ,二者几乎没什么差别。它们三者之间的代码转化也非常简单。所以推荐使用 PySide6 来创建基于 Qt6 的GUI 程序。
1.1 主要概念
Qt for Python 官方文档:https://doc.qt.io/qtforpython/contents.html
1. 界面承载部分( 控件 )
2. 界面框架部分 ( 布局 )
- 主类:QLayout
- 继承类:
QGridLayout (网格布局)
QBoxLayout(简单的上下布局)
QStackedLayout (可切换widget的布局)
FlowLayout
3. 界面组件部分( 其实也是 Widget 类 )
- button
- label
- 等等
4. 界面样式部分
- color
- size
- font
- Icon
- action
- event
- signal
- slot
- connect
概念之间关系
- QWidget 作为页面的主体,挂载在 layout (布局) 上,layout (布局) 可以添加页面的组件,通过 action(动作,类似于点击),event(事件),signal(信号),slot(信号槽),connect(动作绑定)产生交互
- 通过样式类,类似于 Icon(图标),大小,颜色,字体等,修改界面的细节
- widget 上需要有 layout,layout 可以 继续添加 widget,可以一直加下去
三个 窗口基类 ( QMainWindow、QWidget、QDialoh ) 的区别
在平常 qt 开发中,通常要写自己的窗口类,那么这个窗口类该继承自哪个类呢?
- QWidget 继承于 QObject 和 QPaintDevice,
- QDialog 和 QMainWindow 则继承于 QWidget。
下面就来看下三个窗口基类的区别:
- 1. QMainWindow: QMainWindow类 提供一个有 "中央窗口部件、菜单栏、工具栏、状态栏" 的 主应用程序窗口。QMainWindow 窗口经常被继承。QMainWindow 拥有自己的布局,可以使用 QMenuBar(菜单栏)、QToolBar(工具栏)、QStatusBar(状态栏)以及QDockWidget(悬浮窗体),布局有一个可由任何种类小窗口所占据的中心区域。
- 2. QWidget:QWidet 类是所有用户界面对象的基类,窗口部件是用户界面的一个基本单元,它从窗口系统接收鼠标,键盘和其他消息,并在屏幕上绘制自己。一个窗口部件可以被他的父窗口或者是其他窗口挡住一部分。
- 3. QDialog:QDialog 类是对话框窗口的基类,对话框窗口主要用于短期任务以及和用户进行短期通讯的顶级窗口,QDialog可以是模态对话框或者是非模态对话框。QDialog 支持扩展并带有返回值,可以有默认按钮。QDialog也可以有一个QSizeGrip在它的右下角,使用setSizeGripEnabled()。
模式对话框
阻塞同一应用程序中其它可视窗口输入的对话框。模式对话框有自己的事件循环,用户必须完成这个对话框中的交互操作,并且关闭了它之后才能访问应用程序中的其它任何窗口。模式对话框仅阻止访问与对话相关联的窗口,允许用户继续使用其它窗口中的应用程序。显示模态对话框最常见的方法是调用其exec()函数,当用户关闭对话框,exec()将提供一个有用的返回值,并且这时流程控制继续从调用exec()的地方进行。通常情况下,要获得对话框关闭并返回相应的值,我们连接默认按钮,例如:”确定”按钮连接到accept()槽,”取消”按钮连接到reject()槽。另外我们也可以连接done()槽,传递给它Accepted或Rejected。
非模式对话框
和同一个程序中其它窗口操作无关的对话框。在文字处理中的查找和替换对话框通常是非模式的,允许用户同时与应用程序的主窗口和对话框进行交互。调用show()来显示非模式对话框,并立即将控制返回给调用者。如果隐藏对话框后调用show()函数,对话框将显示在其原始位置,这是因为窗口管理器决定的窗户位置没有明确由程序员指定,为了保持被用户移动的对话框位置,在closeEvent()中进行处理,然后在显示之前,将对话框移动到该位置。
半模式对话框
调用setModal(true)或者setWindowModality(),然后show()。有别于exec(),show() 立即返回给控制调用者。对于进度对话框来说,调用setModal(true)是非常有用的,用户必须拥有与其交互的能力,例如:取消长时间运行的操作。如果使用show()和setModal(true)共同执行一个长时间操作,则必须定期在执行过程中调用QApplication::processEvents(),以使用户能够与对话框交互(可以参考QProgressDialog)。
QMainWindow、QWidget、QDialoh 使用原则
- 如果需要嵌入到其他窗体中,则基于 QWidget 创建。
- 如果是顶级对话框,则基于 QDialog 创建。
- 如果是主窗体,则基于 QMainWindow 创建。
QMainWindow 使用示例:
# -*- coding: utf-8 -*-from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,QMetaObject, QObject, QPoint, QRect,QSize, QTime, QUrl, Qt
)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,QFont, QFontDatabase, QGradient, QIcon,QImage, QKeySequence, QLinearGradient, QPainter,QPalette, QPixmap, QRadialGradient, QTransform
)
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWidgets import (QApplication, QMainWindow, QMenuBar, QPushButton,QSizePolicy, QStatusBar, QWidget, QPlainTextEdit
)class Ui_MainWindow(object):def setupUi(self, MainWindow):if not MainWindow.objectName():MainWindow.setObjectName(u"MainWindow")MainWindow.resize(700, 567)self.centralwidget = QWidget(MainWindow)self.centralwidget.setObjectName(u"centralwidget")self.plainTextEdit = QPlainTextEdit(self.centralwidget) # 添加的文本框self.plainTextEdit.setObjectName(u"plainTextEdit")self.plainTextEdit.setGeometry(QRect(90, 40, 521, 311))self.pushButton = QPushButton(self.centralwidget) # 添加的按钮self.pushButton.setObjectName(u"pushButton")self.pushButton.setGeometry(QRect(330, 410, 75, 24))MainWindow.setCentralWidget(self.centralwidget)self.menubar = QMenuBar(MainWindow)self.menubar.setObjectName(u"menubar")self.menubar.setGeometry(QRect(0, 0, 700, 22))MainWindow.setMenuBar(self.menubar)self.statusbar = QStatusBar(MainWindow)self.statusbar.setObjectName(u"statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow) # 调用下面的retranslateUi(self, MainWindow)函数。QMetaObject.connectSlotsByName(MainWindow)# setupUidef retranslateUi(self, MainWindow):MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"\u81ea\u5b9a\u4e49\u7684\u6807\u9898\u680f", None))self.plainTextEdit.setPlaceholderText(QCoreApplication.translate("MainWindow", u"\u8bf7\u8f93\u5165", None))self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u70b9\u51fb", None))# retranslateUi# ================== 上面为 自动生成 的代码 ============================
# ================== 下面代码 使其显示出来 ============================
app = QApplication()
main_window = QMainWindow()auto_ui_window = Ui_MainWindow() # 实例化部件
auto_ui_window.setupUi(main_window) # 调用setupUi()方法,并传入 主窗口 参数。# 给按钮绑定调用函数。
# auto_ui_window.pushButton.clicked.connect(lambda x: print('点击了按钮'))
auto_ui_window.pushButton.clicked.connect(lambda x: auto_ui_window.plainTextEdit.appendPlainText("点击按钮"))main_window.show()
app.exec()
pass
1.2 安装 PySide6
PySide6.QtWidgets:https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/index.html#module-PySide6.QtWidgets
PySide6 库还是非常大的,有将近 200M 左右,推荐使用国内的镜像来下载。PySide6 只支持Python 3.6+版本,另外特别注意的是,它只支持 64 位的 Python。
安装:pip install PySide6
安装完成后,python安装路径下 \Lib\site-packages 里找到 designer.exe。designer 是 Python 设计里面一个非常实用的工具,使得人们编写 qt 界面可以不仅仅是使用纯代码,而可以在可视化的基础上设置,非常方便。
Pycharm 配置 Pyside6 工具
运行 Pycharm,设置 ---> 外部工具 ---> 点击 +,添加 Pyside6_Designer 和 Pyside6_UIC
- 添加 Pyside6_Designer
名称:Pyside6_Designer(可自己定义)
程序:Pyside6-Designer 的安装路径。C:\Python39\Lib\site-packages\PySide6\designer.exe
实参:不填
工作目录: $FileDir$ - 添加 Pyside6_UIC
名称:Pyside6_UIC(可自己定义)
程序:pyside6-uic 的安装路径。C:\Python39\Scripts\pyside6-uic.exe
实参:$FileName$ -o $FileNameWithoutExtension$.py
简单示例:
import sys
import random
from PySide6 import QtCore, QtWidgets, QtGuiclass MyWidget(QtWidgets.QWidget):def __init__(self):super().__init__()self.hello = ["Hallo Welt", "Hei maailma", "Hola Mundo", "Привет мир"]self.button = QtWidgets.QPushButton("Click me!")self.text = QtWidgets.QLabel("Hello World", alignment=QtCore.Qt.AlignCenter)self.layout = QtWidgets.QVBoxLayout(self)self.layout.addWidget(self.text)self.layout.addWidget(self.button)self.button.clicked.connect(self.magic)@QtCore.Slot()def magic(self):self.text.setText(random.choice(self.hello))if __name__ == "__main__":app = QtWidgets.QApplication([])widget = MyWidget()widget.resize(800, 600)widget.show()sys.exit(app.exec())
1.3 安装 PyQt6
如果使用 PySide6 进行开发,可以不用安装 PyQt6 或者 PyQt5
pip install PyQt6
pip install pyqt6-tools
安装完 "PyQt6-tools" 后,就可以在 Python 路径下的 Lib\site-packages\qt6_applications\Qt\bin 目录中找到 designer.exe 工具。
PyCharm 配置 designer.exe
- 在 " File ---> Settings ---> Tools ---> External Tools " 中点击 + 号,添加外部工具。
- 名称填写为 "Qt_Designer",这个名字可以随意填
- "程序" 中填入 "designer.exe" 的路径。
- "工作目录" 可以点击 输入框 上面的 + 号,选择预定义的目录变量,这里选择 $FileDir$
PyCharm 配置 Pyuic
PyUIC 主要是用来 " 将 Qt界面 转换成 py代码 "
- 在 " File ---> Settings ---> Tools ---> External Tools " 中点击 + 号,添加外部工具。
- 名称 填写为 "Py_UIC",这个名字可以随意填
- "程序" 中填入 "python.exe" 的路径。
- "实参" 中填入 -m PyQt6.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
说明:-m 参数就是 "将 库模块 作为脚本运行",这里 库模块 是 PyQt6.uic.pyuic,
查看 Lib\site-packages\PyQt5\uic 目录,发现 调用的是 pyuic.py
-o 参数是 输出 文件名 - "工作目录" 中填入 $FileDir$
系统自定义 宏参数( 点击 宏参数 时 可以实时显示对应当前工程 的 值 ):
1.4 命令行 执行 uic 生成 py代码
如果不填写 "实参" 这个选项时,在 Pycharm 中, 点击 .ui 文件 ---> 然后右键 ---> ExternalTools -> PyUIC 没法生成 .py 文件。只有通过命令行 生成 .py 文件:pyuic6.exe test.ui -o test.py。
只要安装对应的 QT ,就可以找到对应的 uic 可执行文件,直接命令行执行即可。
cmd 中打开 xxx.ui 所在路径例,然后执行:pyuic6 xxx.ui -o xxx.py
2、设计 UI 文件 并转换成 .py 文件
通过 Qt_Designer 设计 QT界面,然后保存为 "测试.ui" 文件
再通过 Py_UIC 会根据 "测试.ui" 文件 生成同名的 "测试.py" 文件。
如果上面 Py_UIC 配置正确,生成 .py 文件很简单:
- .ui文件 ---> 右键 -> External Tools ---> Py_UIC,即可自动生成 py 文件
生成的 .py文件 中只有一个从 object 类继承的 Ui_MainWindow 的类,无法直接运行,如果想要运行,继续往下看。
3、运行 .py 文件,出现图形界面
这个时候直接运行 .py 文件,发现图形界面不会显示。
有两种方法可以显示界面。
方法 1 :直接运行这个 .py文件 就能看到界面的方式
PySide6
在文件末尾加上这一段代码:
if __name__ == "__main__":import sysfrom PySide6 import QtWidgetsapp = QtWidgets.QApplication(sys.argv) # 创建一个QApplication,也就是你要开发的软件appMainWindow = QtWidgets.QMainWindow() # 创建一个QMainWindow,用来装载你需要的各种组件、控件# MainWindow = QtWidgets.QWidget() # 创建一个QMainWindow,用来装载你需要的各种组件、控件ui = Ui_MainWindow() # ui是你创建的ui类的实例化对象ui.setupUi(MainWindow) # 执行类中的setupUi方法,方法的参数是第二步中创建的QMainWindowMainWindow.show() # 执行QMainWindow的show()方法,显示这个QMainWindowsys.exit(app.exec_()) # 使用exit()或者点击关闭按钮退出QApplication
完整代码:
# -*- coding: utf-8 -*-################################################################################
## Form generated from reading UI file '测试.ui'
##
## Created by: Qt User Interface Compiler version 6.3.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,QMetaObject, QObject, QPoint, QRect,QSize, QTime, QUrl, Qt
)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,QFont, QFontDatabase, QGradient, QIcon,QImage, QKeySequence, QLinearGradient, QPainter,QPalette, QPixmap, QRadialGradient, QTransform
)
from PySide6 import QtWidgets
from PySide6.QtWidgets import (QApplication, QMainWindow, QMenuBar, QPushButton,QSizePolicy, QStatusBar, QWidget
)class Ui_MainWindow(object):def setupUi(self, MainWindow):if not MainWindow.objectName():MainWindow.setObjectName(u"MainWindow")MainWindow.resize(800, 600)self.centralwidget = QWidget(MainWindow)self.centralwidget.setObjectName(u"centralwidget")self.pushButton = QPushButton(self.centralwidget)self.pushButton.setObjectName(u"pushButton")self.pushButton.setGeometry(QRect(150, 160, 211, 111))MainWindow.setCentralWidget(self.centralwidget)self.menubar = QMenuBar(MainWindow)self.menubar.setObjectName(u"menubar")self.menubar.setGeometry(QRect(0, 0, 800, 22))MainWindow.setMenuBar(self.menubar)self.statusbar = QStatusBar(MainWindow)self.statusbar.setObjectName(u"statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QMetaObject.connectSlotsByName(MainWindow)# setupUidef retranslateUi(self, MainWindow):MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None))# retranslateUiif __name__ == "__main__":import sysfrom PySide6 import QtWidgetsapp = QtWidgets.QApplication(sys.argv) # 创建一个QApplication,也就是你要开发的软件appMainWindow = QtWidgets.QMainWindow() # 创建一个QMainWindow,用来装载你需要的各种组件、控件# MainWindow = QtWidgets.QWidget() # 创建一个QMainWindow,用来装载你需要的各种组件、控件ui = Ui_MainWindow() # ui是你创建的ui类的实例化对象ui.setupUi(MainWindow) # 执行类中的setupUi方法,方法的参数是第二步中创建的QMainWindowMainWindow.show() # 执行QMainWindow的show()方法,显示这个QMainWindowsys.exit(app.exec_()) # 使用exit()或者点击关闭按钮退出QApplication
PyQT5
PyQt5基本功能:http://code.py40.com/1961.html
和 PySide6 差不多,完整示例代码( temp.py ):
# -*- coding: utf-8 -*-
# @Author :
# @File : temp.py
# @Software: PyCharm
# @description : XXXfrom PyQt5 import QtCore, QtGui, QtWidgets
import sysclass Ui_MainWindow(object):def setupUi(self, Form):Form.setObjectName("Form")Form.resize(400, 300)self.pushButton = QtWidgets.QPushButton(Form)self.pushButton.setGeometry(QtCore.QRect(70, 220, 75, 23))self.pushButton.setObjectName("pushButton")self.pushButton_2 = QtWidgets.QPushButton(Form)self.pushButton_2.setGeometry(QtCore.QRect(220, 220, 75, 23))self.pushButton_2.setObjectName("pushButton_2")self.checkBox = QtWidgets.QCheckBox(Form)self.checkBox.setGeometry(QtCore.QRect(70, 180, 141, 16))self.checkBox.setObjectName("checkBox")self.lineEdit = QtWidgets.QLineEdit(Form)self.lineEdit.setGeometry(QtCore.QRect(130, 56, 181, 20))self.lineEdit.setObjectName("lineEdit")self.lineEdit_2 = QtWidgets.QLineEdit(Form)self.lineEdit_2.setGeometry(QtCore.QRect(130, 110, 181, 20))self.lineEdit_2.setObjectName("lineEdit_2")self.label = QtWidgets.QLabel(Form)self.label.setGeometry(QtCore.QRect(70, 60, 54, 12))self.label.setObjectName("label")self.label_2 = QtWidgets.QLabel(Form)self.label_2.setGeometry(QtCore.QRect(70, 110, 54, 12))self.label_2.setObjectName("label_2")self.retranslateUi(Form)QtCore.QMetaObject.connectSlotsByName(Form)def retranslateUi(self, Form):_translate = QtCore.QCoreApplication.translateForm.setWindowTitle(_translate("Form", "Form"))self.pushButton.setText(_translate("Form", "取消"))self.pushButton_2.setText(_translate("Form", "确定"))self.checkBox.setText(_translate("Form", "记住用户名和密码"))self.label.setText(_translate("Form", "用户名:"))self.label_2.setText(_translate("Form", "密码:"))if __name__ == "__main__":app = QtWidgets.QApplication(sys.argv) # 创建一个QApplication,也就是你要开发的软件appMainWindow = QtWidgets.QMainWindow() # 创建一个QMainWindow,用来装载你需要的各种组件、控件ui = Ui_MainWindow() # ui是你创建的ui类的实例化对象ui.setupUi(MainWindow) # 执行类中的setupUi方法,方法的参数是第二步中创建的QMainWindowMainWindow.show() # 执行QMainWindow的show()方法,显示这个QMainWindowsys.exit(app.exec_()) # 使用exit()或者点击关闭按钮退出QApplication
程序云截图:
PyQT6
ImportError: DLL load failed while importing QtGui: 找不到指定的程序。
准备使用 PySide6,就没再查找具体原因。
方法 2:在 别的文件 中 调用 这个模块
通过 继承 QtWidgets.QWidget 或者 QtWidgets.QMainWindow 来实现
class MyForm(QMainWindow, Ui_MainWindow):def __init__(self):super(MyForm, self).__init__()self.setupUi(self)if __name__ == '__main__':import sysapp = QApplication(sys.argv)my_form = MyForm()my_form.setWindowTitle('my_form')my_form.show()sys.exit(app.exec())pass
生成的 Python 文件只有定义主窗口以及其控件的代码,并没有程序入口的代码。为了秉持视图与逻辑分离的原则,可以再编写一个新的脚本来调用这个文件,并且创建一个窗口。这个和 方法 1 中的 右键 run 就能显示界面的方式 并不冲突,只是要在别的文件中调用这个模块。调用文件的写法( main.py ):
# -*- coding: utf-8 -*-
# @Author :
# @File : main.py
# @Software: PyCharm
# @description : XXXimport sys
from temp import Ui_MainWindow
from PyQt5 import QtWidgets# 这个类继承界面UI类
class MyWindow1(QtWidgets.QWidget, Ui_MainWindow):def __init__(self):super(MyWindow1, self).__init__()self.setupUi(self)# 这个类继承界面UI类
class MyWindow2(QtWidgets.QMainWindow, Ui_MainWindow):def __init__(self):super(MyWindow2, self).__init__()self.setupUi(self)# 调用show
if __name__ == "__main__":app = QtWidgets.QApplication(sys.argv)form_1 = MyWindow1()form_1.setWindowTitle('form_1')form_1.show()form_2 = MyWindow2()form_2.setWindowTitle('form_2')form_2.show()sys.exit(app.exec_())
被调用文件( temp.py )和上面 temp.py 文件一样。承了Ui_MainWindow类,使用其构造方法构造主窗口,并定义了程序的入口,通过创建 QApplication 对象来创建Qt窗口
程序运行截图:
4、PyQT5 之 Qt Designer 介绍与入门
在 PyQt 中编写 UI 界面可以直接通过代码来实现,也可以通过 Qt Designer 来完成。Qt Designer的设计符合 MVC 的架构,其实现了视图和逻辑的分离,从而实现了开发的便捷。Qt Designer中的操作方式十分灵活,其通过拖拽的方式放置控件可以随时查看控件效果。
Qt Designer 随 PyQt5-tools 包一起安装,其安装路径在 "Python安装路径\Lib\site-packages\PyQt5\Qt5\bin" 下。若要启动 Qt Designer 可以直接到上述目录下,
- 双击 designer.exe打开 Qt Designer;
- 或将上述路径加入环境变量,在命令行输入designer 打开;
- 或在 PyCharm 中将其配置为外部工具打开。
Qt Designer 生成的.ui文件(实质上是XML格式的文件)可以通过 pyuic5 工具转换成 .py 文件。
Qt Designer 界面简介
点击 QtDesigner 打开 QtDesigner 的界面,弹出如下图所示的窗口。
创建新的 Form 给出了5个模板,其中 Widget 与 MainWindow 最为常用。这里创建一个 MainWindow 。上面界面的最左侧菜单为 Widget Box,Widget Box 中包含所有 Widget 组件,从左侧的 Widget Box 中拖拽出诸如 Button、View 和 Input 等组件到中间的窗口中。
点击 菜单栏 ---> 窗体 ---> 预览 ( 快捷键为Ctrl+R ) ,可以预览设计好的界面,也可以 "预览与" 来选择在相应的主题风格下预览。
现在拖拽一个 Label 与 Button 进入主窗口(Main Window)。
此时在右上角的 Object Inspector(对象检查器)中可以看到主窗口中的已放置的对象( label 与pushButton )以及其相应地 Qt 类。以 Label 为例,点击 Main Window 中的 label 或是在 Object Inspector 中选取 label 后,查看右侧的一块区域 Property Editor( 属性编辑器 ),其主要包含属性有如下:
名称 | 含义 |
---|---|
objectName | 控件对象名称 |
geometry | 相应宽和高与坐标 |
sizePolicy | 控件大小的策略 |
minimumSize | 最小的宽和高 |
maximumSize | 最大的宽和高 |
font | 字体 |
cursor | 光标 |
... | ... |
PS:将 minimumSize 和 maximumSize 设为一样的数值之后,则窗口的大小固定。
最右下角的部分则为 Resource Browser(资源浏览器),资源浏览器中可以添加相应地如图片素材,作为 Label 或 Button 等控件的 背景图片 等。
Qt Designer 的 UI 文件
使用 Qt Designer 设计程序界面,然后保存的文件为 .ui格式的文件。通过保存并使用记事本等软件打开,可以看到.ui文件的内容如下:
从 .ui文 件的第一行我们便能看出,其实质是一个XML文件。ui文件中存放了在主窗口中的一切控件的相关属性。使用 XML 文件来存储UI文件,具有高可读性和移植性,因此我们可以方便地将.ui文件转换到.py文件,从而使得我们可以使用 Python 语言在设计的 GUI 上面编程。
5、PyQT5 速成教程 --- 3 布局管理
Qt Designer 布局:https://blog.csdn.net/qq_22238533/article/details/78952706
使用 Qt Designer 设计界面:https://blog.csdn.net/a10929/article/details/78114261
养薛定谔的猫 简书:https://www.jianshu.com/u/bf82b363ae88
布局(Layout)管理
Qt Designer中,在工具箱中最上方可以看到有4种布局。分别是
- 垂直布局
- 水平布局
- 网格布局
- 表单布局
布局名称 | 布局含义 |
---|---|
垂直(Vertical)布局 | 布局内的控件按照从上到下的顺序纵向排列 |
水平(Horizontal)布局 | 布局内的控件按照从左到右的顺序横向排列 |
栅格(Grid)布局, 也 叫网格布局 | 将控件放入栅格中,然后划分成若干行与若干列,并且将每个窗口控件放在合适的单元中 |
表单(Form)布局 | 控件以两列布局在表单中,左列包含标签,右列包含输入控件 |
在 Qt Designer 中实现布局有两种方式,
- 通过 布局管理器 进行布局
- 通过 容器控件 进行布局。
通过 布局管理器 进行布局
在左侧的工具箱中随意拖动一些控件,例如:按钮、标签、输入框等控件 到 主窗口中。
由于刚才是随意拖拽至主窗口,因此所有控件的排放是乱七八糟的。此时,我们不选中任何控件,在空白处点击右键,找到弹出菜单最下方的 Layout 布局。
可以看到,在右键菜单中可以指定布局的方式以及相应布局方式的快捷键。这里我们选择 Lay Out Vertically(垂直布局),整个主窗口内的所有控件一瞬间都垂直着排列整齐了。
此时如果需要调整垂直布局的顺序,只需按住待调整的控件,上下拖动即可。但是这样布局是针对整个窗口的,有时我们需要让不同的布局有父子关系的继承。那么这时就不能单纯地在空白的地方点击右键来布局了。
再次 "点击右键 -> 布局 -> 拆分布局", 然后选中需要水平布局的2个控件,选中后点击右键,水平布局。再选中另外两个控件,选择水平布局。此时的主窗口应该如图所示:
最后,我们再将两个布局选中,点击右键垂直布局,来排列两个水平布局。
最后在空白区域再次使用垂直布局。这样即使我们缩放窗口,整个窗口内的控件也会跟着窗口的变化做出相应改变了。
在上述操作的过程中,我们的一系列操作有决定这些物体的父子关系(层级关系)。而其层级关系在对象查看器中可以直观地看出。
布局管理 生成 代码
把布局保存为.ui文件,并使用 PyUIC 转换为 .py 文件。
使用 容器 进行布局
容器(Container)指的就是能容纳其他子控件的一个控件。使用容器控件可以将容器控件中的所有控件归为一类,从而区别于其他的控件。当然,正如上文提到过的,使用容器也可以对控件进行布局。
首先,从左侧的 Container 中拖出一个 Frame 控件到主窗口中,再拖出一些其他控件到 Frame 中。如下图:
选中 Frame 中空白地方,点击右键 -> 布局 -> 水平布局,则会自动水平排列 Frame 中的控件。
当我们需要变更 Frame 的位置的时候,可以直接拖动 Frame 到相应地位置,这样管理更加方便。使用容器进行布局的实质也是使用容器管理器进行布局的。
绝对布局
前面学习了布局管理器。但是最简单的布局则是之间输入控件的 Geometry 属性值。
在属性编辑器中,可以修改 X、Y 值来将控件放置在相应的位置,修改 Width 和 Height 来更改控件高度。
名称 | 值 | 含义 |
---|---|---|
X | 290 | 控件的最左上角距离主窗口的左侧290px |
Y | 140 | 控件的最左上角距离主窗口的上方140px |
Width | 93 | 按钮的宽度为93px |
Height | 28 | 按钮的高度为23px |
而上述的 Geometry 属性在 .py 代码中如下:
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(290, 140, 93, 28))
self.pushButton.setObjectName("pushButton")
可以看到,上述代码的第二行通过 setGeometry 方法指定了 Geometry 属性的四个值。通过以上的方法,我们可以对任何一个控件进行布局。
6、Designer 实战 --- 计算器界面
使用网格布局(Grid Layout)
首先分析整数计算器需要的一些按钮:
数字键:0-9共10个。
操作符:+ - * / = CE共6个
在 Designer 的主窗口中创建 16 个按钮之后,按照4行4列的顺序进行摆放。
并且修改按钮的属性中的 objectName 为相对于的名称。如数字 0 的 objectName 设置为 Num_0,操作符 + 的 objectName 设置为 OP_plus。对于按钮的显示名称的修改,在主窗口中双击相应按钮则可以快速修改。由于计算器中的按钮是正方形(通常选择正方形),而且不想让这些按钮根据窗口的大小进行变化,通过全选16个按钮(在主窗口中使用鼠标左键拖出选择框,选中16个按钮)在右侧找到 mininumSize 和 maximumSize 属性。点击其左面的箭头符号展开选项,将其宽和高固定为 60。这样就不会因为缩放窗口而造成按钮的大小变化了。
在对所有按钮完成相应操作之后,我们选中16个按钮,点击右键,使用网格布局来实现布局。
使用 Spacer 增加空白间隔
在 输入控件 面板中,拖一个 line Edit 控件到计算器窗口上,用来显示输入结果与计算结果。
通过在空白地方右键,对主窗口使用Vertical Lay Out。
此时,我们实现了一个计算器的布局。但显示框与下面的按钮距离太近。这时便需要使用左侧工具箱内的 Spacer 控件。
Spacer 顾名思义 "分隔器" 。可以通过以占位的形式来将布局中的不同控件分开部分举例。
此时,我们拖动一个 Vertical Spacer 到 Line Edit 与下面的键盘之间。同样,Horizontal Spacer也可以用来水平地分离控件之间的距离。
虽然 Spacer 在我们的 Qt Designer 编辑器中是以蓝色的类似弹簧的外观存在的,但是在真正的窗体中,Spacer 是隐形的。
但这时的 Spacer 大小和 Line Edit 的大小都不是想要的,而且也无法通过鼠标来拖动。如果想要改变这些,则需要进一步了解这些控件的一些属性。
sizePolicy 尺寸策略
在 Designer 中,控件的尺寸是可以变化的。每个控件都拥有 sizeHint 和 minisizeHint 两个尺寸。sizeHint 即尺寸提示;minisizeHint 则是最小尺寸。尺寸提示也是控件的期望尺寸,最小尺寸即窗口可以被压缩到的最小的尺寸。sizePolicy 与 sizeHint 和 minisizeHint 息息相关。
对于布局管理器中的布局无法满足的要求的时候,sizePolicy 属性便派上了用场。
sizePolicy 可以实现控件的微调。sizePolicy 中共有如下几种水平和垂直策略。
参数说明:
在 sizePolicy 的 Horizontal Policy 和 Vertical Policy 下面还有 Horizontal Stretch 和 Vertical Stretch 两个属性。现在找到 Spacer,并修改其属性的 Height 为 10。
并将其 sizeType 修改为 Fixed 固定。此时,观察左面的计算器的主界面显示栏 Line Edit 与下面的键盘之间的间距变小了。