一、介绍
PyQt基于QT库的python封装,是一个图形用户界面(GUI)工具包,允许用户使用python语言创建桌面应用程序。目前,不同版本中,PyQt5是较为流行的版本,支持python 2.7 和 python 3.x 。
PyQt支持两种开发方式,可视化和编程化。
- 编程式创建界面无需多说,pip安装成功以后,有较深基础功底的可直接上手编码。
- 可视化方式对新手非常友好,用户可基于Qt Designe工具包进行组件拖拽、布局管理等操作。
上述图片来自[Python GUI PyQt] PyQt5快速入门_python 如何使用pyqt5-CSDN博客博主的文章
————————————————
二、安装
在我们自己的python虚拟环境中,pip安装依赖包PyQt5, pyqt5_tools
pyqt5_tools 包含一些辅助 PyQt5 的开发工具,其中就有我们要用的 Qt Designer
1 pip install PyQt5 PyQt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple 2 3 可以带上国内的镜像源,会快一点,也不会报错
安装成功以后,win+R 搜索"designer",出现图标表示成功。
2.2 Pycharm配置
python语言开发,大部分使用Pycharm集成开发工具,这里在Pycharm工具中配置QT designer外部工具,在工程开发中让界面设计和解析变得容易。
打开Pycharm,File -> Settings ->Tools -> External Tools,点击加号添加,Program我这里添加的是安装包路径,因为我安装了PyQt_tools,找不到designer。Working directory设置保存ui文件的文件,$FileDir$表示当前文件所在目录
新接触该模块,相关该模块的部分文章中提到designer.exe的文件夹位置大多都找不到,可能原因是版本更新。现提供该文件的位置。
(基本上都在自己python环境下Lib文件夹中)我是用conda创建的虚拟环境,所以我要一层一层找下去,查找方式基本上都一样
C:\Users\19225\.conda\envs\dev_env\Lib\site-packages\qt5_applications\Qt\bin\designer.exe
添加 PyUIC 工具
1 在 CreateTool 窗口依次填写: 2 3 Name:填写 “PyUIC” 4 Program:填写 python.exe 的路径 5 注意:此处填写 IDE 使用的 Python Interpreter的路径。如果小白的 Python 或 Anaconda3 安装在其他路径下,或者选择其它路径中的 python.exe 作为 Python Interpreter,可以从 Pycharm -> Settings -> Project -> Python Interpreter 打开配置窗口,从右侧上方 “Python Interpreter:” 选项框找到 python.exe 的路径。 6 7 8 Working directory:填写将 .ui 文件转换为 .py 文件的保存路径 9 例如,要将 .py 文件保存在当前 Project 的路径下,则填写 “$FileDir$”。
配置Pyrcc
1 Program:python的安装目录下的Scripts文件夹的pyrcc5.exe文件 2 Arguments:$FileName$ -o $FileNameWithoutExtension$_rc.py
ui转py的过程:
选中文件,鼠标右击,打开扩展,选择PyUIC,它会生成.py文件
1 python -m PyQt5.uic.pyuic demo.ui -o demo.py
————————————————
三、界面设计介绍
打开外部工具,会弹出窗口提示,如果不想每次启动都弹,在该窗口左下角设置去掉即可。
先整体认识下designer工具,左侧是不同类型组件,右侧可查看ui结构以及设置每个组件的属性,中间灰色地带为画布。
3.1 组件
组件是构建图像界面基本的模块,pyqt提供了多种组件,这里介绍一些使用频率较高的组件
PyQt5的常用基本控件
3.1.1 菜单类组件
菜单栏组件包含 菜单栏+状态栏+工具栏 三部分
在designer中,先创建一个主窗口, 文件->新建->Main Window
查看主窗口右侧ui结构,自带的菜单栏,状态栏,缺少工具栏ToolBar,选中MainWindow右击添加
四.PyQt基本UI
1 只要是Qt制作的app,必须有且只有1个QApplication对象 2 sys.argv当作参数的目的是将运行时的命令参数传递给QApplication对象 3 创建了一个QWidget对象(这是一个白框),将它的标题设置为”第一个”PyQt“ 4 然后调用show方法显示出来 5 开始运行程序,直到关闭了窗口,这里相当于是一个while(True)的循环等待机制,异步的
另外一种运行脚本方式:
1 python 文件名.py
4.1.PyQt资料查询方式
PyQt中有非常多的功能模块,开发中最常用的功能模块主要有三个:
QtCore:包含了核心的非GUI的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime类文件、进程与线程一起使用
QtGui:包含了窗口系统、事件处理、2D图像、基本绘画、字体和文字类
QtWidgets:包含了一些列创建桌面应用的UI元素
可以参考PyQt官网的所有模块,地址:https://www.riverbankcomputing.com/static/Docs/PyQt5/module_index.html#ref-module-index
————————————————
4.2.控件
1.按钮
按钮对应的控件名称为QPushButton,位于PyQt5.QtWidgets里面:
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QPushButton 3 4 if __name__ == '__main__': 5 app = QApplication(sys.argv) 6 w = QWidget() 7 # 设置窗口标题 8 w.setWindowTitle("第一个PyQt") 9 # 在窗口里面添加控件 10 btn = QPushButton("按钮") 11 # 设置按钮的父亲是当前窗口,等于是添加到窗口中显示 12 btn.setParent(w) 13 # 展示窗口 14 w.show() 15 # 程序进行循环等待状态 16 app.exec()
2.文本
纯文本控件名称为QLabel,位于PyQt5.QtWidgets里面,纯文本控件仅仅作为标识显示而已,类似输入内容前的一段标签提示(账号、密码)
3.调整窗口
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QLineEdit, QDesktopWidget 3 4 if __name__ == '__main__': 5 app = QApplication(sys.argv) 6 w = QWidget() 7 # 设置窗口标题 8 w.setWindowTitle("第一个PyQt") 9 # 设置窗口大小 10 w.resize(300, 300) 11 # 调整窗口在屏幕的中央显示 12 center_pointer = QDesktopWidget().availableGeometry().center() 13 x = center_pointer.x() 14 y = center_pointer.y() 15 old_x, old_y, width, height = w.frameGeometry().getRect() 16 w.move(int(x - width / 2), int(y - height / 2)) 17 w.show() 18 app.exec_()
4.设置窗口的图标
五.布局
1 在Qt里面布局分为四个大类: 2 3 QBoxLayout:盒子布局,一般使用它的两个子类QHBoxLayout和QVBoxLayout负责水平和垂直布局。 4 5 QGridLayout: 网格布局,有的人称之为九宫格布局 6 7 QFormLayout:用于提交数据form表单。比如:登录,注册类似的场景 8 9 QStackedLayout:多页面切换的布局,一次只能看到一个界面。这个布局叫做抽屉布局
=========================================布局布好以后,右键布局---打破布局,然后就好啦
5.1.QBoxLayout垂直布局实例
1 import sys 2 from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget, QPushButton, QGroupBox, QMainWindow 3 4 5 class MyWindow(QWidget): 6 def __init__(self): 7 # 切记一定要调用父类的__init__方法,因为它里面有很多对UI空间的初始化操作 8 super().__init__() 9 # 设置大小 10 self.resize(300, 300) 11 # 设置标题 12 self.setWindowTitle("垂直布局") 13 # 创建一个垂直布局器 14 layout = QVBoxLayout() 15 # 作用是在布局器中增加一个伸缩量,里面的参数表示QSpacerItem的个数,默认值为零 16 # 会将你放在layout中的空间压缩成默认的大小 17 layout.addStretch(1) 18 # 按钮1,这里没有设置父对象 19 btn1 = QPushButton("按钮1") 20 # 添加到布局器中 21 # 不设置父对象而是直接设置布局器 22 layout.addWidget(btn1) 23 layout.addStretch(1) 24 # 按钮2 25 btn2 = QPushButton("按钮2") 26 # 添加到布局器 27 layout.addWidget(btn2) 28 layout.addStretch(1) 29 # 按钮3 30 btn3 = QPushButton("按钮3") 31 # 添加到布局器 32 layout.addWidget(btn3) 33 layout.addStretch(2) 34 # 让当前的窗口使用这个布局器来排列 35 self.setLayout(layout) 36 37 38 if __name__ == '__main__': 39 app = QApplication(sys.argv) 40 # 创建一个QWidget子类 41 w = MyWindow() 42 w.show() 43 app.exec()
5.1.1水平布局的代码如下
这里我们将垂直布局与水平布局综合到一起,但是一个Widget只能设置一个布局器,如何解决呢?通过布局器的嵌套,一个大的布局器中嵌套两个小的布局器,一个垂直一个水平。
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QGroupBox, QVBoxLayout, QHBoxLayout, QRadioButton 3 4 5 class MyWindow(QWidget): 6 def __init__(self): 7 super().__init__() 8 self.init_ui() 9 10 def init_ui(self): 11 # 最外层的垂直布局,包含两部分:爱好和性别 12 container = QVBoxLayout() 13 # -----创建第1个组,添加多个组件----- 14 # hobby 主要是保证他们是一个组。 15 hobby_box = QGroupBox("爱好") 16 # v_layout 保证三个爱好是垂直摆放 17 v_layout = QVBoxLayout() 18 btn1 = QRadioButton("抽烟") 19 btn2 = QRadioButton("喝酒") 20 btn3 = QRadioButton("烫头") 21 # 添加到v_layout中 22 v_layout.addWidget(btn1) 23 v_layout.addWidget(btn2) 24 v_layout.addWidget(btn3) 25 # 把v_layout添加到hobby_box中 26 hobby_box.setLayout(v_layout) 27 # -----创建第2个组,添加多个组件----- 28 # 性别组 29 gender_box = QGroupBox("性别") 30 # 性别容器 31 h_layout = QHBoxLayout() 32 # 性别选项 33 btn4 = QRadioButton("男") 34 btn5 = QRadioButton("女") 35 # 追加到性别容器中 36 h_layout.addWidget(btn4) 37 h_layout.addWidget(btn5) 38 # 添加到 box中 39 gender_box.setLayout(h_layout) 40 # 把爱好的内容添加到容器中 41 container.addWidget(hobby_box) 42 # 把性别的内容添加到容器中 43 container.addWidget(gender_box) 44 # 设置窗口显示的内容是最外层容器 45 self.setLayout(container) 46 47 48 if __name__ == '__main__': 49 app = QApplication(sys.argv) 50 w = MyWindow() 51 w.show() 52 app.exec()
5.2.QGridLayout
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLineEdit, QGridLayout 3 4 5 class MyWindow(QWidget): 6 7 def __init__(self): 8 super().__init__() 9 self.init_ui() 10 11 def init_ui(self): 12 self.setWindowTitle("计算器") 13 # 准备数据 14 data = { 15 0: ["7", "8", "9", "+", "("], 16 1: ["4", "5", "6", "-", ")"], 17 2: ["1", "2", "3", "*", "<-"], 18 3: ["0", ".", "=", "/", "C"] 19 } 20 # 整体垂直布局 21 layout = QVBoxLayout() 22 # 输入框 23 edit = QLineEdit() 24 edit.setPlaceholderText("请输入内容") 25 # 把输入框添加到容器中 26 layout.addWidget(edit) 27 # 网格布局 28 grid = QGridLayout() 29 # 循环创建追加进去 30 for line_number, line_data in data.items(): 31 # 此时line_number是第几行,line_data是当前行的数据 32 for col_number, number in enumerate(line_data): 33 # 此时col_number是第几列,number是要显示的符号 34 btn = QPushButton(number) 35 # grid.addWidget(btn) 36 grid.addWidget(btn, line_number, col_number) 37 # 把网格布局追加到容器中 38 layout.addLayout(grid) 39 self.setLayout(layout) 40 41 42 if __name__ == '__main__': 43 app = QApplication(sys.argv) 44 w = MyWindow() 45 w.show() 46 app.exec()
5.3.QFormLayout
1 import sys 2 from PyQt5.QtCore import Qt 3 from PyQt5.QtWidgets import QVBoxLayout, QFormLayout, QLineEdit, QPushButton, QApplication, QWidget 4 5 6 class MyWindow(QWidget): 7 def __init__(self): 8 super().__init__() 9 self.init_ui() 10 11 def init_ui(self): 12 # 设定当前Widget的宽高(可以拉伸大小) 13 # self.resize(300, 200) 14 # 禁止改变宽高(不可以拉伸) 15 self.setFixedSize(300, 150) 16 # 外层容器 17 container = QVBoxLayout() 18 # 表单容器 19 form_layout = QFormLayout() 20 # 创建1个输入框 21 edit = QLineEdit() 22 edit.setPlaceholderText("请输入账号") 23 form_layout.addRow("账号:", edit) 24 # 创建另外1个输入框 25 edit2 = QLineEdit() 26 edit2.setPlaceholderText("请输入密码") 27 form_layout.addRow("密码:", edit2) 28 # 将from_layout添加到垂直布局器中 29 container.addLayout(form_layout) 30 # 按钮 31 login_btn = QPushButton("登录") 32 login_btn.setFixedSize(100, 30) 33 # 把按钮添加到容器中,并且指定它的对齐方式 34 container.addWidget(login_btn, alignment=Qt.AlignRight) 35 # 设置当前Widget的布局器,从而显示这个布局器中的子控件 36 self.setLayout(container) 37 38 39 if __name__ == '__main__': 40 app = QApplication(sys.argv) 41 w = MyWindow() 42 w.show() 43 app.exec()
5.4.QStackedLayout
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QStackedLayout, QLabel 3 4 5 class Window1(QWidget): 6 def __init__(self): 7 super().__init__() 8 QLabel("我是抽屉1要显示的内容", self) 9 self.setStyleSheet("background-color:green;") 10 11 12 class Window2(QWidget): 13 def __init__(self): 14 super().__init__() 15 QLabel("我是抽屉2要显示的内容", self) 16 self.setStyleSheet("background-color:red;") 17 18 19 class MyWindow(QWidget): 20 def __init__(self, parent=None): 21 super().__init__(parent) 22 self.create_stacked_layout() 23 self.init_ui() 24 25 def create_stacked_layout(self): 26 # 创建堆叠(抽屉)布局 27 self.stacked_layout = QStackedLayout() 28 # 创建单独的Widget 29 win1 = Window1() 30 win2 = Window2() 31 # 将创建的2个Widget添加到抽屉布局器中 32 self.stacked_layout.addWidget(win1) 33 self.stacked_layout.addWidget(win2) 34 35 def init_ui(self): 36 # 设置Widget大小以及固定宽高 37 self.setFixedSize(300, 270) 38 # 1. 创建整体的布局器 39 container = QVBoxLayout() 40 # 2. 创建1个要显示具体内容的子Widget 41 widget = QWidget() 42 widget.setLayout(self.stacked_layout) 43 widget.setStyleSheet("background-color:grey;") 44 # 3. 创建2个按钮,用来点击进行切换抽屉布局器中的Widget 45 btn_press1 = QPushButton("抽屉1") 46 btn_press2 = QPushButton("抽屉2") 47 # 给按钮添加事件(即点击后要调用的函数) 48 btn_press1.clicked.connect(self.btn_press1_clicked) 49 btn_press2.clicked.connect(self.btn_press2_clicked) 50 # 4. 将需要显示的空间添加到布局器中 51 container.addWidget(widget) 52 container.addWidget(btn_press1) 53 container.addWidget(btn_press2) 54 # 5. 设置当前要显示的Widget,从而能够显示这个布局器中的控件 55 self.setLayout(container) 56 57 def btn_press1_clicked(self): 58 # 设置抽屉布局器的当前索引值,即可切换显示哪个Widget 59 self.stacked_layout.setCurrentIndex(0) 60 61 def btn_press2_clicked(self): 62 # 设置抽屉布局器的当前索引值,即可切换显示哪个Widget 63 self.stacked_layout.setCurrentIndex(1) 64 65 66 if __name__ == "__main__": 67 app = QApplication(sys.argv) 68 win = MyWindow() 69 win.show() 70 app.exec()
上述关于布局还有一种简单的方法:
(1)先移组件,再布局。
放置五个按钮,让这五个按钮等宽的,随便排列
(全部选中–>鼠标右键–>布局–>水平布局 预览)