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()

十一、资源与扩展

  1. 官方文档:

  2. 推荐书籍:

    • "Rapid GUI Programming with Python and Qt"
    • "PyQt5 快速开发与实战"
  3. 学习资源:

    • Qt 官方示例
    • GitHub 上的开源项目
    • PyQt5 视频教程
  4. 扩展库:

    • PyQtGraph (科学绘图)
    • QScintilla (代码编辑器组件)
    • PyQtWebEngine (网页浏览器组件)

通过本教程,你应该已经掌握了 PyQt5 的基础知识。要成为 PyQt5 专家,建议多实践、阅读源码和参考官方文档。









results matching ""

    No results matching ""