Qt简介
Qt是由 C++ 底层实现的,它支持的操作系统很多,如Windows、Linux、Unix、Android、iOS、嵌入式等等,而 PyQt 是由 Python 调用 Qt 实现的,PyQt 由 Riverbank Computing 开发,采用以下许可:
- GPLv3:开源版本使用此协议,要求衍生作品也采用 GPLv3。
- 商业许可:用于闭源或商业应用,需向 Riverbank Computing 购买许可证。
Python 官方 Wiki 中关于 PyQt 的介绍:PyQt - Python Wiki Qt官方网站:Qt Documentation | Home
PyQt环境准备
创建虚拟环境(可选)
在dos命令窗中导航到想要创建虚拟环境的目录,执行创建虚拟环境命令:
python -m venv 环境名称
此处我以环境名为py3_qt_test为例:
python -m venv py3_qt_test
安装PyQt5库命令
创建好虚拟环境后直接在当前目录下安装所需的pyqt5库:
pip install pyqt5 -i https://pypi.tuna.tsinghua.edu.cn/simple/
安装完成后可以查看模块安装列表,检查是否安装成功,检查安装列表命令如下:
pip list

也可以在当前安装PyQt的虚拟环境中执行包含如下的测试代码文件:
# 若能能够正常执行,则表明环境搭建成功
from PyQt5 import QtWidgets
# 可以查看PyQt版本信息
from PyQt5.QtCore import *
print(QT_VERSION_STR)
模块介绍
PyQt中存在非常多的功能模块,开发中最常用的功能模块主要由三个:
- QtCore:包含了核心的非GUI的功能,主要和时间、文件与文件夹、各种数据流、URLs、mime类文件、进程、线程等一起使用
- QtGui:包含了窗口系统、事件处理、2D图像、基本绘画、字体和文字类
- QtWidgets:包含了一些列创建桌面应用的UI元素
Qt5的官方参考文档: Qt 5.15
基本UI
新建一个窗口
首先创建一个QApplication对象(只要是Qt制作的app,必须有且只有一个QApplication对象,sys.argv 当作参数的目的是将运行时的命令参数传递给QApplication对象),再使用创建窗口的QWidget()方法创建窗口,在创建前需要导入需要的模块及方法,如下代码案例:
首先进行导包:
import sys
from PyQt5.QtWidgets import QApplication,QWidget
创建第一个Qt程序:
if __name__ == '__main__':
# 创建一个应用实例
app = QApplication(sys.argv) # argv用来获取命令行参数列表
# 创建一个窗口
w = QWidget()
# 设置窗口标题
w.setWindowTitle('第一个PyQt5程序')
# 展示窗口
w.show()
# 程序进行循环等待状态,直到用户关闭窗口
app.exec_() # 等同于tkinter的mainloop()
设置窗口或控件的大小
同时设置大小和位置
QWidget 对象有一个 setGeometry() 方法用于同时设置窗口或控件的大小和位置,代码如下:
# setGeometry 的参数依次为: x,y,width,height
w.setGeometry(20,20,300,300) # w 为QWidget对象
设置大小
QWidget 对象也提供了一个 resize() 方法用于设置窗口或控件的大小,代码如下:
# resize 的参数: width,height
w.resize(300,300) # w 为QWidget对象
setGeometry 和 resize 的区别
| 区别点 | setGeometry() | resize() |
|---|---|---|
| 位置控制 | 同时设置位置和大小 | 仅设置大小,不改变位置 |
| 默认位置 | 若未调用 move(),窗口会出现在指定位置 | 窗口默认出现在系统决定的位置(通常是屏幕左上角附近) |
| 与布局管理器配合 | 可能干扰布局管理器的自动调整 | 更适合与布局管理器配合(仅调整内容区域大小) |
创建按钮
QtWidgets库中提供了QPushButton()方法用来创建按钮,可以通过QPushButton对象.信号(如click).connect(槽函数) 的方式绑定点击事件。代码如下:
'''在w窗口中创建一个按钮'''
# 创建一个按钮
btn = QPushButton("登录")
# 为按钮设置父控件
btn.setParent(w)
# 设置按钮的位置
btn.move(50,100) # 也可以使用setGeometry方法
除了上述创建控件的方式,即先创建控件再绑定父控件的方式之外,还可以直接再创建控件的同时绑定父控件,代码如下所示:
'''在w窗口中创建一个按钮'''
# 创建按钮同时绑定父控件
btn = QPushButton("登录",w)
# 设置按钮的位置
btn.move(50,100)
在创建按钮控件以及其他控件时也需要导入对应的UI元素方法,如下所示:
from PyQt5.QtWidgets import QPushButton, QLineEdit,QLabel
以上两种创建方式也适用于
QLineEdit、QLabel等其他的控件
创建标签
QtWidgets库中提供了QLabel()方法用来创建按钮。代码如下:
'''在w窗口中创建一个标签'''
# 先创建后绑定父控件
user = QLabel('账户:')
user.setParent(w)
user.setStyleSheet("font-size:16px;color:blue") # 对组件进行属性设置
user.move(50,50)
# 创建的同时并绑定父控件
password = QLabel('密码:',w)
password.move(50,70)
创建输入框
QtWidgets库中提供了QLineEdit()方法用来创建输入框。可以使用QLineEdit所提供的setPlaceholderText(str) 的方法,创建输入框的提示词。代码如下:
'''在w窗口中创建一个输入框'''
# 创建的同时并绑定父控件
edit = QLineEdit(w)
edit.setPlaceholderText('请输入用户名') # 提示词
w.move(100,50)
创建单选按钮
QtWidgets库中提供了QRadioButton()方法用来创建按钮,复选框的创建并不复杂,重点在于如何对这些控件进行布局排版,例如其代码如下:
# 在w窗口添加性别复选框
h = QHBoxLayout() # 创建一个水平布局
group = QGroupBox('性别') # 创建性别组
v = QVBoxLayout() # 创建一个垂直布局
btn1 = QRadioButton('男') '''创建单选按钮的命令就这两句'''
btn2 = QRadioButton('女') '''其他的代码都是为了布局'''
v.addWidget(btn1)
v.addWidget(btn2)
group.setLayout(v) # 将垂直布局与组绑定
h.addWidget(group)
w.setLayout(h)
布局方式
盒子布局(QBoxLayout)
PyQt提供的盒子布局存在两种方式,分别是:
- 水平布局 使用
QHBQoxLayout方法 - 垂直布局 使用
QVBQoxLayout方法
垂直布局(QVBQoxLayout)
QtWidgets库中提供了QVBQoxLayout()方法用来创建一个垂直布局,QVBQoxLayout对象所提供的一些方法:
addWidget(控件对象)方法将控件添加入布局中addLayout(布局对象)方法将其他布局嵌入当前布局中addStretch(int)方法可以添加伸缩因子进行排版
具体实操代码如下所示:
layout = QVBoxLayout() # 创建一个垂直布局
btn1 = QPushButton('按钮1')
btn2 = QPushButton('按钮2')
# 以下的addSretch最终达到的效果为btn1与btn2的分布为1:2
layout.addWidget(btn1) # 将按钮1加入垂直布局
layout.addStretch(1) # 添加一个伸缩因子
layout.addWidget(btn2) # 将按钮2加入垂直布局
layout.addStretch(2) # 再添加一个伸缩因子
# 在对垂直布局操作完成后记得为该布局添加父控件,例在w上显示垂直布局
w.setLayout(layout)
水平布局(QHBQoxLayout)
QtWidgets库中提供了QHBQoxLayout()方法用来创建一个水平布局,QHBQoxLayout对象也所提供的一些方法:
addWidget(控件对象)方法将控件添加入布局中addLayout(布局对象)方法将其他布局嵌入当前布局中addStretch(int)方法可以添加伸缩因子进行排版
具体实操代码如下所示:
layout = QHBoxLayout() # 创建一个水平布局
btn1 = QPushButton('按钮1')
btn2 = QPushButton('按钮2')
# 以下的addSretch最终达到的效果为btn1与btn2的分布为1:2
layout.addWidget(btn1) # 将按钮1加入水平布局
layout.addStretch(1) # 添加一个伸缩因子
layout.addWidget(btn2) # 将按钮2加入水平布局
layout.addStretch(2) # 再添加一个伸缩因子
# 在对水平布局操作完成后记得为该布局添加父控件,例在w上显示水平布局
w.setLayout(layout)
网格布局(QGridLayout)
QtWidgets库中提供了QGridLayout()方法用来创建一个网格布局(也称九宫格布局),QGridLayout对象提供了addWidget(控件,行,列)方法用来向网格布局中添加内容,示例代码如下:
h = QVBoxLayout()
inp = QLineEdit() # 添加输入框
inp.setPlaceholderText('请输入式子')
h.addWidget(inp)
w.setWindowTitle('九宫格布局')
data = {
0:['7','8','9','+'],
1:['4','5','6','-'],
2:['1','2','3','*'],
3:['.','0','=','/']
}
grid = QGridLayout() # 创建网格布局
for key,value in data.items():
for i,v in enumerate(value):
btn = QPushButton(v)
grid.addWidget(btn,key,i) # 添加内容
h.addLayout( grid)
w.setLayout(h)
表单布局(QFromLayout)
QtWidgets库中提供了QFromLayout()方法用来创建一个表单布局,示例代码如下:
v = QVBoxLayout() # 创建垂直布局
from_layout = QFormLayout() # 创建表单布局
edit1 = QLineEdit() # 创建输入框1
edit1.setPlaceholderText('请输入用户名')
from_layout.addRow('用户名', edit1) # 向表单布局添加一行
edit2 = QLineEdit() # 创建输入框1
edit2.setPlaceholderText('请输入密码')
from_layout.addRow('密码', edit2)
v.addLayout(from_layout) # 将表单布局嵌入垂直布局
v.addWidget(QPushButton('登录'), alignment=Qt.AlignCenter)
w.setLayout(v) # 将垂直布局与窗口绑定
抽屉布局(QStackedLayout)
QtWidgets库中提供了QStackedLayout()方法用来创建一个抽屉布局,示例代码如下:
v = QVBoxLayout()
stack_layout = QStackedLayout()
win1 = win_1()
win2 = win_2()
stack_layout.addWidget(win1)
stack_layout.addWidget(win2)
btn1 = QPushButton('抽屉1')
btn2 = QPushButton('抽屉2')
# 绑定点击事件 对象.信号.connect(槽函数)
btn1.clicked.connect(btn_press1)
btn2.clicked.connect(btn_press2)
v.addLayout(stack_layout)
v.addWidget(btn1)
v.addWidget(btn2)
w.setLayout(v)
调用的函数部分的结果如下所示:
def win_1():
'''函数体'''
def win_2():
'''函数体'''
def btn_press1():
stack_layout.setCurrentIndex(0) # 设置当前索引为0
def btn_press2():
stack_layout.setCurrentIndex(1)
在执行这些代码的过程中,它都处于如下框架内:
app = QApplication(sys.argv)
w = QWidget()
'''设置窗口'''
w.show()
sys.exit(app.exec_())
在使用这些布局时记得导入,导入方式如下所示:
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit, QVBoxLayout, QFormLayout, QStackedLayout, QGroupBox, QRadioButton, QHBoxLayout, QLabel
窗口居中
获取中央位置坐标
QtWidgets库中提供了QDesktopWidget().screenGeometry().center()方法用来获取屏幕的中央位置,返回值为一个坐标对象Qpoint。可以使用Qpoint对象.x,Qpoint对象.y来获取到该坐标的数值。如下代码所示:
# 使用QDesktopWidget方法
center_pointer = QDesktopWidget().screenGeometry().center()
x = center_pointer.x()
y = center_pointer.y()
将窗口居中显示
当获取到中央位置后可以减去窗口的宽和高,再使用w.move(x-width//2,y-height//2)打掉将窗口居中显示的效果。例如当窗口w大小为(600,400)
w.move(x-600//2, y-400//2) # w.resize(600,400)
上述的计算中央坐标的方式需要手动输入窗口的大小,为了方便,我们可以使用自动计算居中,其中使用到了QWidget对象的frameGeometry()方法以获得QWidget对象的窗口大小及位置 ,以元组的形式返回。如下代码所示:
"""自动计算居中"""
# 使用frameGeometry方法获取窗口坐标对象
print(type(w.frameGeometry()),w.frameGeometry()) # 得到的QRect对象
# 使用QRect对象的getRect方法得到坐标的元组
tup = w.frameGeometry().getRect()
print(type(w.frameGeometry().getRect()),w.frameGeometry().getRect())
w.move(x-tup[2]//2, y-tup[3]//2)
创建窗口的形式
窗口的创建形式主要分为三种:
- QWidget(基础窗口类)
- QMainWindow(主窗口类)
- QDialog(对话框类)
QWidget
QWidget是所有用户界面元素的基类,即控件和窗口的父类,是最基础的窗口组件,可独立作为窗口,也可作为其他组件的容器,自由度高(什么东西都没有),多应用于小型工具窗口、自定义控件的载体。示例代码如下所示:
import sys
from PyQt5.QtWidgets import QApplication,QWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
''''此处补充窗口设置代码'''
w.show()
app.exec_()
QMainWindow
QMainWindow专门用于创建应用程序的主窗口,继承自QWidget,是QWidget的子类,自带标准布局,包含菜单栏、工具栏、状态栏、标题栏等,中间部分为主窗口区域。多应用于文本编辑器、浏览器等拥有完整菜单和工具条的应用程序主界面。QMainWindow提供了一些方法如下:
menuBar:菜单栏toolBar:工具栏statusBar:状态栏centralWidget:中心部件
以menuBar为例,当使用menuBar创建一个对象后,该对象将可以使用它包含的几个方法:
addMenu(str):向menuBar中添加选项addAction(str):向各个选项中添加动作setNativeMenuBar(False):使mac系统菜单栏失效,让其按照Windows菜单栏样式显示
示例代码如下所示:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QMainWindow()
# 创建菜单栏
menu = w.menuBar()
menu.setNativeMenuBar(False)
file_menu = menu.addMenu("文件")
file_menu.addAction("新建")
file_menu.addAction("打开")
user_menu = menu.addMenu("用户")
user_menu.addAction("登录")
user_menu.addAction("注册")
w.setMenuBar(menu)
# 设置主窗口区域
label = QLabel("这是主区域",w)
w.setCentralWidget( label)
w.show()
sys.exit(app.exec_())
QDialog
QDialog用于创建对话框窗口,继承自QWidget,主要用于与用户进行短期交互(如提示、设置、确认等),多应用于打开文件对话框、设置对话框、确认删除等提示框。QDialog主要有两种特点:
- 模态(阻塞父窗口操作),通过
exec()方法显示模态对话框 - 非模态(不阻塞父窗口操作),通过
show()显示非模态对话框
| 特性 | 模态对话框 (Modal) | 非模态对话框 (Modeless) |
|---|---|---|
| 阻塞行为 | 阻塞父窗口,必须关闭后才能操作其他窗口 | 不阻塞父窗口,可同时操作多个窗口 |
| 创建方法 | exec() 或 setModal(True)+show() | show() |
| 使用场景 | 必须立即处理的交互(如确认删除) | 辅助工具(如浮动搜索框) |
模态对话框 (阻塞式),打开对话框后,无法点击主窗口的任何部分。示例代码如下:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QPushButton, QVBoxLayout, QLabel
class ModalDialog(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("模态对话框")
layout = QVBoxLayout()
layout.addWidget(QLabel("我是模态对话框!关闭我才能操作主窗口"))
self.setLayout(layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("主窗口")
self.setGeometry(300, 300, 300, 200)
btn = QPushButton("打开模态对话框", self)
btn.clicked.connect(self.open_modal)
self.setCentralWidget(btn)
def open_modal(self):
dialog = ModalDialog()
dialog.exec() # 关键:使用exec()阻塞主窗口
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
非模态对话框 (非阻塞式),对话框和主窗口可同时操作,互不影响。示例代码如下:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QPushButton, QVBoxLayout, QLabel
class ModelessDialog(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("非模态对话框")
layout = QVBoxLayout()
layout.addWidget(QLabel("我是非模态对话框!可同时操作主窗口"))
self.setLayout(layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("主窗口")
self.setGeometry(300, 300, 300, 200)
btn = QPushButton("打开非模态对话框", self)
btn.clicked.connect(self.open_modeless)
self.setCentralWidget(btn)
self.dialog = None # 防止对话框被垃圾回收
def open_modeless(self):
if not self.dialog:
self.dialog = ModelessDialog()
self.dialog.show() # 关键:使用show()不阻塞
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
提示:非模态对话框需保存引用(如
self.dialog),否则可能被Python垃圾回收机制销毁。模态对话框因exec()会保持对象存活。