PyQt5 基础详尽教程
一、PyQt5 简介
PyQt5 是 Python 对 Qt5 应用程序框架的绑定,用于创建图形用户界面(GUI)。它由 Riverbank Computing 开发,包含 620 多个类和 6000 多个函数。
主要特点:
- 跨平台支持 (Windows, Linux, macOS)
- 丰富的控件集合
- 强大的布局管理
- 信号与槽机制
- 样式表支持 (类似CSS)
- 多媒体支持
- 数据库连接
- 网络功能
二、安装 PyQt5
pip install PyQt5
# 如果需要设计工具
pip install PyQt5-tools
三、第一个 PyQt5 程序
import sys
from PyQt5.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv) # 创建应用对象
label = QLabel("Hello PyQt5!") # 创建标签控件
label.show() # 显示控件
sys.exit(app.exec_()) # 进入主循环
四、核心概念
1. 主窗口结构
from PyQt5.QtWidgets import QMainWindow, QTextEdit
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 设置窗口标题和大小
self.setWindowTitle("主窗口示例")
self.setGeometry(100, 100, 800, 600)
# 添加中央控件
text_edit = QTextEdit()
self.setCentralWidget(text_edit)
# 添加菜单栏
menubar = self.menuBar()
file_menu = menubar.addMenu("文件")
# 添加工具栏
toolbar = self.addToolBar("工具")
# 添加状态栏
self.statusBar().showMessage("就绪")
2. 常用控件
按钮 (QPushButton)
from PyQt5.QtWidgets import QPushButton
button = QPushButton("点击我", self)
button.setToolTip("这是一个按钮")
button.clicked.connect(self.on_button_click)
def on_button_click(self):
print("按钮被点击了!")
文本框 (QLineEdit, QTextEdit)
from PyQt5.QtWidgets import QLineEdit, QTextEdit
line_edit = QLineEdit(self)
line_edit.setPlaceholderText("请输入文本")
text_edit = QTextEdit(self)
text_edit.setPlainText("多行文本编辑器")
标签 (QLabel)
from PyQt5.QtWidgets import QLabel
label = QLabel("这是一个标签", self)
label.setAlignment(Qt.AlignCenter) # 文本居中
复选框 (QCheckBox) 和单选按钮 (QRadioButton)
from PyQt5.QtWidgets import QCheckBox, QRadioButton
checkbox = QCheckBox("启用选项", self)
checkbox.stateChanged.connect(self.on_checkbox_changed)
radio1 = QRadioButton("选项1", self)
radio2 = QRadioButton("选项2", self)
def on_checkbox_changed(self, state):
print("复选框状态:", state)
3. 布局管理
垂直布局 (QVBoxLayout)
from PyQt5.QtWidgets import QVBoxLayout, QWidget
layout = QVBoxLayout()
layout.addWidget(QLabel("顶部"))
layout.addWidget(QPushButton("中间"))
layout.addWidget(QLineEdit("底部"))
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
水平布局 (QHBoxLayout)
from PyQt5.QtWidgets import QHBoxLayout
h_layout = QHBoxLayout()
h_layout.addWidget(QPushButton("左"))
h_layout.addWidget(QPushButton("中"))
h_layout.addWidget(QPushButton("右"))
网格布局 (QGridLayout)
from PyQt5.QtWidgets import QGridLayout
grid = QGridLayout()
grid.addWidget(QLabel("用户名:"), 0, 0)
grid.addWidget(QLineEdit(), 0, 1)
grid.addWidget(QLabel("密码:"), 1, 0)
grid.addWidget(QLineEdit(), 1, 1)
grid.addWidget(QPushButton("登录"), 2, 0, 1, 2) # 跨2列
4. 信号与槽机制
from PyQt5.QtCore import pyqtSignal, QObject
class Communicate(QObject):
signal = pyqtSignal(str) # 定义一个信号
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.c = Communicate()
self.c.signal.connect(self.signal_handler) # 连接信号到槽
button = QPushButton("发射信号", self)
button.clicked.connect(self.emit_signal)
def emit_signal(self):
self.c.signal.emit("Hello from signal!") # 发射信号
def signal_handler(self, message):
print("收到信号:", message)
五、对话框
1. 消息对话框
from PyQt5.QtWidgets import QMessageBox
# 信息对话框
QMessageBox.information(self, "标题", "这是一条信息")
# 问题对话框
reply = QMessageBox.question(self, "确认", "确定要退出吗?",
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
print("用户选择了是")
2. 文件对话框
from PyQt5.QtWidgets import QFileDialog
# 打开文件
filename, _ = QFileDialog.getOpenFileName(self, "打开文件", "", "文本文件 (*.txt);;所有文件 (*)")
# 保存文件
filename, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "文本文件 (*.txt)")
# 选择目录
directory = QFileDialog.getExistingDirectory(self, "选择目录")
六、样式表 (QSS)
# 设置全局样式
app.setStyleSheet("""
QMainWindow {
background-color: #f0f0f0;
}
QPushButton {
background-color: #4CAF50;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
text-decoration: none;
font-size: 14px;
margin: 4px 2px;
border-radius: 4px;
}
QPushButton:hover {
background-color: #45a049;
}
QLineEdit {
padding: 5px;
border: 1px solid #ccc;
border-radius: 3px;
}
""")
七、事件处理
from PyQt5.QtCore import Qt
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setMouseTracking(True) # 启用鼠标跟踪
# 键盘事件
def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape:
self.close()
# 鼠标事件
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
print("左键点击位置:", event.pos())
# 窗口事件
def closeEvent(self, event):
reply = QMessageBox.question(self, '确认退出',
"确定要退出吗?", QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
八、多线程
from PyQt5.QtCore import QThread, pyqtSignal
class WorkerThread(QThread):
finished = pyqtSignal(str) # 定义一个完成信号
def run(self):
# 模拟耗时操作
import time
time.sleep(3)
self.finished.emit("任务完成!")
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.thread = WorkerThread()
self.thread.finished.connect(self.on_thread_finished)
button = QPushButton("开始任务", self)
button.clicked.connect(self.start_task)
def start_task(self):
self.thread.start()
def on_thread_finished(self, message):
QMessageBox.information(self, "完成", message)
九、综合示例 - 简易文本编辑器
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTextEdit,
QAction, QFileDialog, QMessageBox)
class TextEditor(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 创建文本编辑区
self.textEdit = QTextEdit()
self.setCentralWidget(self.textEdit)
# 创建菜单栏
self.createMenus()
# 设置窗口属性
self.setGeometry(300, 300, 800, 600)
self.setWindowTitle('简易文本编辑器')
self.show()
def createMenus(self):
# 文件菜单
menubar = self.menuBar()
fileMenu = menubar.addMenu('文件')
# 新建动作
newAction = QAction('新建', self)
newAction.setShortcut('Ctrl+N')
newAction.triggered.connect(self.newFile)
# 打开动作
openAction = QAction('打开', self)
openAction.setShortcut('Ctrl+O')
openAction.triggered.connect(self.openFile)
# 保存动作
saveAction = QAction('保存', self)
saveAction.setShortcut('Ctrl+S')
saveAction.triggered.connect(self.saveFile)
# 退出动作
exitAction = QAction('退出', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(self.close)
# 添加到菜单
fileMenu.addAction(newAction)
fileMenu.addAction(openAction)
fileMenu.addAction(saveAction)
fileMenu.addSeparator()
fileMenu.addAction(exitAction)
def newFile(self):
self.textEdit.clear()
def openFile(self):
filename, _ = QFileDialog.getOpenFileName(self, "打开文件")
if filename:
with open(filename, 'r') as f:
self.textEdit.setText(f.read())
def saveFile(self):
filename, _ = QFileDialog.getSaveFileName(self, "保存文件")
if filename:
with open(filename, 'w') as f:
f.write(self.textEdit.toPlainText())
QMessageBox.information(self, "成功", "文件保存成功!")
if __name__ == '__main__':
app = QApplication(sys.argv)
editor = TextEditor()
sys.exit(app.exec_())
十、进阶主题
1. 使用 Qt Designer
- 可视化设计界面
- 保存为 .ui 文件
- 使用 pyuic5 转换为 Python 代码:
pyuic5 input.ui -o output.py
2. 自定义控件
from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QPainter, QColor, QPen
class CircleWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.color = QColor(255, 0, 0)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
pen = QPen()
pen.setWidth(3)
pen.setColor(self.color)
painter.setPen(pen)
painter.drawEllipse(10, 10, self.width()-20, self.height()-20)
def setColor(self, color):
self.color = color
self.update() # 触发重绘
3. 国际化
from PyQt5.QtCore import QTranslator
app = QApplication(sys.argv)
translator = QTranslator()
translator.load("myapp_zh.qm") # 加载翻译文件
app.installTranslator(translator)
4. 数据库连接
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
# 连接SQLite数据库
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("mydatabase.db")
if db.open():
query = QSqlQuery()
query.exec_("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
query.exec_("INSERT INTO users (name) VALUES ('Alice')")
db.close()
十一、资源与扩展
官方文档:
推荐书籍:
- "Rapid GUI Programming with Python and Qt"
- "PyQt5 快速开发与实战"
学习资源:
- Qt 官方示例
- GitHub 上的开源项目
- PyQt5 视频教程
扩展库:
- PyQtGraph (科学绘图)
- QScintilla (代码编辑器组件)
- PyQtWebEngine (网页浏览器组件)
通过本教程,你应该已经掌握了 PyQt5 的基础知识。要成为 PyQt5 专家,建议多实践、阅读源码和参考官方文档。