一、PyQt简介&环境搭建
1. PyQt简介
PyQt是一套Python的GUI开发框架,即图形用户界面开发框架.
Python中经常使用的GUI控件集有PyQt、Tkinter、wxPython、Kivy、PyGUI和Libavg
其中PyQt是Qt(c++语言实现的)为Python专门提供的扩展
1.1 Qt
Qt 是一个1991年由Qt Company开发的跨平台C++图形用户界面开发框架。
2008年,Qt Company被诺基亚公司收购,Qt也因此成为诺基亚旗下的编程语言工具。
2012年,Qt被Digia收购。
2014年4月,跨平台集成开发环境Qt Creator 3.1.0正式发布
1.2 PyQt
- 基础高性能的Qt的图形界面控件集
- 能够跨平台运行在windows、linux和macos等系统上
- 使用
信号/槽(signal/slot)
机制进行通信(其它语言采用回调方式) - 对Qt库的完全封装
1.3 通过pip安装PyQt5
pip install PyQt5
安装PyQt5
pip install PyQt5-tools
安装Qt
工具软件pip install PyQt5-stubs
安装PyQt5语法检测包(可选)
如果安装缓慢,请配置pip源:
pip config set global.index-url https://mirror.baidu.com/pypi/simple
二、PyQt创建窗口
1. 第一个PyQt窗口
from PyQt5.QtWidgets import QApplication,QWidget
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
执行代码,就会显示PyQt5窗口:
2. PyQt模块简介
PyQt中有非常多的功能模块,开发中最常用的功能模块主要有三个:
- QtCore:包含了核心的非GUI的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime类文件、进程与线程一起使用
- QtGui:包含了窗口系统、事件处理、2D图像、基本绘画、字体和文字类
- QtWidgets:包含了一些列创建桌面应用的UI元素
3. 窗口标题和图标
应用程序图标是一个小的图像,通常在标题栏的左上角显示。
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtGui import QIcon
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 设置窗口标题
w.setWindowTitle('窗口')
# 设置窗口尺寸
w.resize(400, 300)
# 设置图标
w.setWindowIcon(QIcon('qq.png'))
w.setToolTip('这个一个气泡提示')
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
三、PyQt文本和图片
1. 文本控件
文本控件是QLabel
from PyQt5.QtWidgets import QWidget, QApplication, QLabel
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('文本展示')
label = QLabel()
label.setText('第一个文本')
# 将文本控件添加到窗口中
label.setParent(w)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
2. 图片控件
QLabel 控件既可以显示文本,也可以显示图片
from PyQt5.QtWidgets import QWidget, QApplication, QLabel
from PyQt5.QtGui import QPixmap
import sys
def init_widget(w: QWidget):
# 修改窗口标题
w.setWindowTitle('图片展示')
# 展示图片
label = QLabel()
pixmap = QPixmap('img.png')
label.setPixmap(pixmap)
# 显示到窗口中
label.setParent(w)
# 改变窗口大小
w.resize(pixmap.width(), pixmap.height())
if __name__ == '__main__':
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
init_widget(w)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
四、PyQt输入框
1. 单行文本输入框
QLineEdit控件可以输入单行文本
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QVBoxLayout
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
def init_widget(w: QWidget):
# 修改窗口标题
w.setWindowTitle('单行输入框')
# 设置窗口大小
w.resize(480, 320)
layout = QVBoxLayout()
# 展示单行输入框
edit = QLineEdit()
# 设置输入框提示
edit.setPlaceholderText('请输入用户名')
# 设置文本
edit.setText('张三')
# 获取单选框的文字
text = edit.text()
print(text)
# 设置输入框最大字符数
edit.setMaxLength(10)
layout.addWidget(edit)
edit3 = QLineEdit("Password")
edit3.setPlaceholderText('请输入密码')
edit3.setEchoMode(QLineEdit.Password)
layout.addWidget(edit3)
w.setLayout(layout)
if __name__ == '__main__':
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
init_widget(w)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
QLineEdit的方法
方法 | 说明 |
|
|
| 设置文本框浮显文字 |
| 设置文本框内容 |
| 设置文本框所允许输入的最大字符数 |
2. 多行文本输入框
QTextEdit
控件用来输入多行文本
from PyQt5.QtWidgets import QApplication,QWidget,QTextEdit
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('多行输入框')
# 多行输入框
edit = QTextEdit()
# 设置提示内容
edit.setPlaceholderText('请输入发表的内容')
# 设置文本内容
edit.setPlainText('武汉疫情')
# 获取输入的内容
print(edit.toPlainText())
edit.clear()
# 显示多行输入框
edit.setParent(w)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
QTextEdit的方法
方法 | 说明 |
| 设置多行文本框的文本内容 |
| 返回多行文本框的文本内容 |
| 设置多行文本框的内容为HTML文档 |
| 返回多行文本框的HTML文档内容 |
| 清空多行文本框的内容 |
五、PyQt按钮
常见的按钮实现类包括:QPushButton
、QRadioButton
和QCheckBox
QPushButton
是最普通的按钮控件,可以响应一些用户的事件
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
import sys
def func():
print("按下按钮啦,火箭发射!")
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('普通按钮')
# 显示普通按钮
btn = QPushButton()
# 添加按钮提示
btn.setText('发射')
# 给按钮添加点击事件
btn.clicked.connect(func)
# 展示按钮
btn.setParent(w)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
六、PyQt信号和槽
1. 信号和槽简介
信号和槽机制是 QT 的核心机制,应用于对象之间的通信
- 信号和槽是用来在对象间传递数据的方法
- 当一个特定事件发生的时候,
signal
会被emit
出来,slot
调用是用来响应相应的signal
的 - Qt中对象已经包含了许多预定义的
signal
(基本组件都有各自特有的预定义的信号) - 槽函数绑定了信号,信号一旦发出,就会自动调用绑定的槽函数
2. 信号和槽绑定
通过调用 QObject 对象的 connect 函数来将对象的信号与另外一个对象的槽函数相关联,当发射者发射信号时,接收者的槽函数将被调用
点击按钮,输出hello
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
import sys
# 槽函数
def click():
print('hello1')
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('信号和槽的绑定')
# 添加按钮
btn = QPushButton()
btn.setText('点我')
btn.setParent(w)
# 绑定按钮点击的信号和处理的槽函数
# 方式1:槽函数使用函数
# clicked 信号
# click定义的槽函数
btn.clicked.connect(click)
# 方式2:槽函数使用lambda表达式
# 信号和槽函数参数必须要保持一致
# 如果信号中参数有= 槽函数可以不用添加
btn.clicked.connect(lambda: print('hello2'))
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
3. 使用PyQt的槽函数
利用系统自带退出函数QApplication.quit
点击按钮,关闭窗口
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('使用系统的槽函数')
# 创建按钮
btn = QPushButton()
btn.setText('关闭窗口')
# 显示按钮
btn.setParent(w)
# 信号和槽绑定
btn.clicked.connect(QApplication.quit) # 使用QApplication的quit方法
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
七、PyQt布局layout
1. 水平布局QHBoxLayout
from PyQt5.QtWidgets import QApplication,QWidget,QPushButton,QHBoxLayout
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('水平布局')
"""------------------ 创建按钮 ------------------"""
btn1 = QPushButton('1')
btn2 = QPushButton('2')
btn3 = QPushButton('3')
btn4 = QPushButton('4')
btn5 = QPushButton('5')
# 创建布局
layout = QHBoxLayout()
# 添加布局到窗口中
w.setLayout(layout)
# 按钮控件添加到布局中
layout.addWidget(btn1)
layout.addWidget(btn2)
layout.addWidget(btn3)
layout.addWidget(btn4)
layout.addWidget(btn5)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
2. 竖直布局QVBoxLayout
from PyQt5.QtWidgets import QApplication,QWidget,QPushButton,QVBoxLayout
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('竖直布局')
w.resize(480, 240)
"""------------------ 创建并添加5个按钮 ------------------"""
# 创建布局
layout = QVBoxLayout()
# 布局添加到窗口中
w.setLayout(layout)
# 控件添加到布局中
layout.addWidget(QPushButton('1'))
layout.addWidget(QPushButton('2'))
layout.addWidget(QPushButton('3'))
layout.addWidget(QPushButton('4'))
layout.addWidget(QPushButton('5'))
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
3. 表单布局QFormLayout
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QFormLayout, QPushButton
import sys
def func():
name = nameEdit.text()
age = ageEdit.text()
phone = phoneEdit.text()
print("姓名:{} 年龄:{} 电话:{}".format(name, age, phone))
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# w.resize(480, 320)
# 修改窗口标题
w.setWindowTitle('表单布局')
"""------------------ 创建布局 ------------------"""
layout = QFormLayout()
# 添加到窗口中
w.setLayout(layout)
# 输入框
nameEdit = QLineEdit()
ageEdit = QLineEdit()
phoneEdit = QLineEdit()
btn = QPushButton('发送')
# 信号和槽绑定
btn.clicked.connect(func)
# 添加到布局中
layout.addRow('姓名', nameEdit)
layout.addRow('年纪', ageEdit)
layout.addRow('电话', phoneEdit)
layout.addRow('', btn)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
4. 布局嵌套
通过布局嵌套可以实现更加复杂的布局
from PyQt5.QtWidgets import QApplication,QWidget,QPushButton,QHBoxLayout,QVBoxLayout,QFormLayout
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('嵌套布局')
"""------------------ 实现布局 ------------------"""
# 整体水平布局
wholeLayout = QHBoxLayout()
# 添加整体布局
w.setLayout(wholeLayout)
# 每一部分布局
layout1 = QHBoxLayout()
layout2 = QVBoxLayout()
layout3 = QVBoxLayout()
# 添加到整体的布局中
wholeLayout.addLayout(layout1)
wholeLayout.addLayout(layout2)
wholeLayout.addLayout(layout3)
# 控件
# 添加第一部分控件
layout1.addWidget(QPushButton('1'))
layout1.addWidget(QPushButton('2'))
# 添加第二部分控件
layout2.addWidget(QPushButton('3'))
layout2.addWidget(QPushButton('4'))
# 添加第三部分控件
layout3.addWidget(QPushButton('5'))
layout3.addWidget(QPushButton('6'))
layout3.addWidget(QPushButton('7'))
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
八、PyQt单选框和复选框
1. 单选框
QRadioButton
是单选按钮,它提供了一组可供选择的按钮和文本标签,用户可以选择其中一个选项
单选框选中的信号是:toggled
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
def func(checked):
'''
状态变化的槽函数
:param checked: 是否被选中
:return:
'''
print('状态变化', checked)
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('单选框')
"""------------------ 创建布局 ------------------"""
layout = QHBoxLayout()
# 添加布局到窗口中
w.setLayout(layout)
# 创建两个单选框
rb1 = QRadioButton('男')
rb2 = QRadioButton('女')
rb1.setChecked(True)
# 添加到布局中
layout.addWidget(rb1)
layout.addWidget(rb2)
# 绑定信号和槽
rb1.toggled.connect(func)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
2. 复选框
QCheckBox
提供了一组带文本标签的复选框,用户可以选择多个选项
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
def func(state):
# 判断是否选中
if state == Qt.Checked: # 2
print('选中')
else: # 0
print('未选中')
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('复选框')
"""------------------ 窗口布局 ------------------"""
layout = QHBoxLayout()
# 添加到窗口中
w.setLayout(layout)
# 控件
label = QLabel()
label.setText('谦哥的爱好:')
ck1 = QCheckBox('抽烟')
ck2 = QCheckBox('喝酒')
ck3 = QCheckBox('烫头')
# 选中第一个
ck1.setChecked(True)
# 添加控件到布局中
layout.addWidget(label)
layout.addWidget(ck1)
layout.addWidget(ck2)
layout.addWidget(ck3)
# 绑定信号和槽
ck1.stateChanged.connect(func)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
九、PyQt对话框
对话框是为了更好地实现人与程序的交互
对话框主要是完成特定场景下的功能,比如删除确认等
QDialog的子类有QMessageBox
、QFileDialog
、QFontDialog
、QInputDialog
等
1. QMessageBox
QMessageBox是普通的对话框
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
def deleteUser():
# 弹出对话框,让用户确认
result = QMessageBox.question(w, '提示', '确认要删除好朋友吗?',
QMessageBox.Ok | QMessageBox.Cancel,
QMessageBox.Cancel)
if result == QMessageBox.Ok:
print('确认删除')
elif result == QMessageBox.Cancel:
print('取消删除')
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('对话框')
"""------------------ 创建按钮 ------------------"""
btn = QPushButton('删除用户')
# 显示控件
btn.setParent(w)
# 信号和槽绑定
btn.clicked.connect(deleteUser)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
2. QIputDialog
QIputDialog是输入对话框,由一个文本框和两个按钮(OK按钮和Cancel按钮)组成
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon
import sys
def func():
str,success = QInputDialog.getText(w,'提示','请输入角色名称')
if success:
edit.setText(str)
# 1.创建应用程序
app = QApplication(sys.argv)
# 2.创建窗口
w = QWidget()
# 修改窗口标题
w.setWindowTitle('输入提示框')
"""------------------ 创建界面 ------------------"""
layout = QHBoxLayout()
# 添加布局
w.setLayout(layout)
# 控件
btn = QPushButton('创建角色')
edit = QLineEdit()
# 控件添加到布局中
layout.addWidget(btn)
layout.addWidget(edit)
# 信号和槽函数绑定
btn.clicked.connect(func)
# 3.显示窗口
w.show()
# 4.等待窗口停止
sys.exit(app.exec())
十、PyQt面向对象
Qt窗口继承
写一个自定义类继承QWidget
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class MyWindow(QWidget):
def __init__(self, title):
super().__init__()
self.setWindowTitle(title)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow("窗口标题")
window.show()
sys.exit(app.exec_())
通过继承QWidget
来实现窗体
在构造中,必须调用super
函数,否则将出行错误
初始化ui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class MyWindow(QWidget):
def __init__(self, title):
super().__init__()
self.setWindowTitle(title)
self.init_ui()
def init_ui(self):
layout = QHBoxLayout()
# ---------------------------------
# 在这里初始化界面内容
# ---------------------------------
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow("窗口标题")
window.show()
sys.exit(app.exec_())
十一、PyQt自定义信号和槽
1. 为什么要使用信号和槽
使用信号和槽的好处在于,可以将代码分离成更小的、更可重用的部分,从而提高代码的可读性和可维护性。这种机制使得不同的对象之间可以进行通信,而不需要它们之间直接相互调用方法。
如果直接调用函数,会导致代码的紧密耦合,不利于代码的维护和扩展。此外,使用信号和槽也可以方便地实现多线程编程,因为它们可以在不同的线程之间进行通信。
使用信号和槽的目的:
- 用于代码之间的解耦合
- 子线程通知主线程更新界面
2. 在文件内部定义信号和槽
PyQt中自定义信号和槽的步骤如下:
- 定义信号:在类中定义一个信号,使用PyQt的信号机制可以实现自定义信号。可以通过
pyqtSignal()
方法来创建一个信号对象。pyqtSignal参数槽函数的参数类型 - 定义槽:在类中定义一个槽函数,使用
@pyqtSlot()
装饰器将该方法注册为槽函数。 - 连接信号和槽:使用
信号.connect(槽函数)
方法将信号和槽连接起来。 - 触发信号:在需要触发信号的地方,使用
信号.emit()
方法来触发该信号,参数和槽函数参数一致。
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
class MyObject(QObject):
# a. 定义一个自定义信号
my_signal = pyqtSignal(str)
# b. 定义一个槽函数
@pyqtSlot(str)
def my_slot(self, message):
print("Received message: ", message)
# 创建一个对象
obj = MyObject()
# b. 连接信号和槽
obj.my_signal.connect(obj.my_slot)
# c. 触发信号
obj.my_signal.emit("Hello, World!")
首先定义了一个名为my_signal
的自定义信号。然后,我们定义了一个名为my_slot
的槽函数,并使用@pyqtSlot()
装饰器将其注册为槽函数。最后,我们创建了一个MyObject
对象,并将my_signal
信号连接到my_slot
槽函数。最后,我们通过调用emit()
方法来触发该信号,并将消息传递给槽函数。
3. 在不同文件定义信号和槽
当在不同的类中连接信号和槽时,需要使用QObject.connect()
方法来建立连接。假设我们有两个类Sender
和Receiver
,其中Sender
类定义了一个信号my_signal
,Receiver
类定义了一个槽函数my_slot
,那么连接过程如下:
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
class Sender(QObject):
my_signal = pyqtSignal(str)
def send_data(self):
data = "Hello, World!"
self.my_signal.emit(data)
class Receiver(QObject):
@pyqtSlot(str)
def my_slot(self, data):
print("Received data: ", data)
sender = Sender()
receiver = Receiver()
# 将信号连接到槽
sender.my_signal.connect(receiver.my_slot)
# 触发信号
sender.send_data()
创建了两个类Sender
和Receiver
,并分别实例化了它们的对象sender
和receiver
。然后,我们使用connect()
方法将Sender
类中的信号my_signal
连接到了Receiver
类中的槽函数my_slot
。最后,我们通过调用send_data()
方法来触发信号,从而使得槽函数被调用,并输出接收到的数据。