81·模块十五:GUI编程高级

进阶 GUI:PyQt/PySide 简介

guipyqtpysideqt

第 81 课:进阶 GUI:PyQt/PySide 简介

所属模块:模块十五:GUI编程 难度:Advanced 标签:gui, pyqt, pyside, qt 上一课:Tkinter 事件处理与绑定 下一课:项目打包与分发:setuptools 入门

学习目标

完成本课学习后,你将能够:

  1. 理解 PyQt 和 PySide 框架的关系、区别及选择依据。
  2. 掌握 Qt 框架中"信号与槽"这一核心机制的基本原理和用法。
  3. 熟练运用 Qt Designer 快速设计界面并加载到 Python 代码中。
  4. 创建包含常用控件(如按钮、标签、输入框)并具有基本交互功能的桌面应用程序。
  5. 了解使用 Qt 框架进行 GUI 开发相比 Tkinter 的优势与适用场景。

核心概念

欢迎来到 GUI 编程的进阶阶段!Tkinter 是 Python 内置的、轻量级的 GUI 工具包,非常适合入门和简单应用。但当你的应用变得复杂,或者你追求更专业、更美观、功能更强大的界面时,基于 Qt 框架的解决方案就成了更好的选择。

1. PyQt 与 PySide:两条通往 Qt 的路

Qt 是一个用 C++ 编写、功能极其强大的跨平台应用程序框架。它不仅仅是一个 GUI 库,还包含了网络、数据库、多媒体等众多模块。要在 Python 中使用 Qt,主要有两个官方绑定库:

  • PyQt:由 Riverbank Computing 开发维护。它是一个商业软件,但在开发开源或 GPL 许可的应用时可以免费使用。它的 API 设计非常 Pythonic。
  • PySide:由 Qt 公司(原 Digia)官方推出的 Python 绑定。它在 LGPL 许可下发布,这意味着你可以在开发商业闭源软件时免费使用它。其 API 与 PyQt 非常相似。

如何选择? 如果你的项目是开源且愿意遵循 GPL 协议,两者皆可。如果计划开发商业软件,PySide(LGPL) 是更常见的选择,因为其许可更宽松。在语法层面,除了个别类名和模块导入方式略有不同(如 PyQt5.QtWidgets vs PySide6.QtWidgets),大部分代码可以轻松移植。本课程将以 PySide6 为例进行讲解,因为其官方背景和许可优势。

2. 核心机制:信号与槽

这是 Qt 框架的灵魂。想象一个场景:你点击了一个按钮(发送一个"被点击"的信号),你希望程序弹出一个对话框(执行一个"弹出对话框"的函数)。

  • 信号:由特定对象(如按钮、滑块)在特定事件(如点击、值改变)发生时发射。
  • :就是一个普通的 Python 函数或方法,用于响应特定的信号。

将信号与槽连接起来,就建立了对象间的通信。这比传统的回调函数更灵活、更安全。

# 伪代码概念展示
button = QPushButton("点击我")
# 当 button 发射 `clicked` 信号时,调用 my_function 槽函数
button.clicked.connect(my_function)

def my_function():
    print("按钮被点击了!")

3. 界面构建方式

Qt 提供两种方式构建界面:

  • 纯代码:像我们用 Tkinter 一样,通过 Python 代码一行行创建和布局控件。灵活,易于版本控制。
  • Qt Designer:一个所见即所得的图形化界面设计工具。你可以拖拽控件来设计界面,然后保存为 .ui 文件。在 Python 中可以通过 uic.loadUi 函数直接加载这个文件,将界面与业务逻辑代码分离,非常高效。

代码示例

下面是一个完整的 PySide6 应用示例,创建了一个带有一个标签和一个按钮的窗口。点击按钮,标签文字会改变。

# 文件:basic_pyside_example.py
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("我的第一个 PySide6 应用")
        self.setGeometry(100, 100, 400, 200) # 设置窗口位置和大小(x, y, 宽, 高)

        # 创建一个中心部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)

        # 创建一个标签
        self.label = QLabel("欢迎使用 PySide6!", self)
        self.label.setStyleSheet("font-size: 18px; color: #333;") # 设置样式
        layout.addWidget(self.label)

        # 创建一个按钮
        self.button = QPushButton("点击我")
        self.button.setStyleSheet("font-size: 16px; padding: 10px;")
        # **关键:连接信号与槽**
        self.button.clicked.connect(self.on_button_clicked)
        layout.addWidget(self.button)

        # 也可以创建一个输入框,并连接它的回车信号
        # self.input_box = QLineEdit()
        # self.input_box.returnPressed.connect(self.on_input_submitted)
        # layout.addWidget(self.input_box)

    def on_button_clicked(self):
        """这是一个槽函数,当按钮被点击时调用"""
        self.label.setText("按钮已被点击!信号与槽成功连接!")

# 应用程序的入口点
if __name__ == "__main__":
    # 1. 创建一个 QApplication 实例。每个 PySide6 应用必须且只能有一个。
    app = QApplication(sys.argv)
    
    # 2. 创建主窗口实例
    window = MainWindow()
    
    # 3. 显示窗口
    window.show()
    
    # 4. 进入应用程序的主事件循环
    sys.exit(app.exec())

代码解析

  1. 我们创建了一个继承自 QMainWindow 的自定义窗口类。
  2. __init__ 中设置了窗口标题和几何信息。
  3. 使用了 布局管理器 QVBoxLayout 来垂直排列控件(标签和按钮)。布局管理器是 Qt 强大的特性,能自动处理窗口缩放时的控件排列。
  4. 最关键的部分是 self.button.clicked.connect(self.on_button_clicked),它将按钮的 clicked 信号与我们的 on_button_clicked 方法连接起来。
  5. 最后,标准的启动流程:创建 QApplication -> 创建窗口 -> 显示窗口 -> 进入事件循环。

实践练习

练习 1:基础窗口与事件 创建一个程序,包含一个窗口和一个标签。标签初始文本为"计数器:0"。每次点击窗口(任何位置),标签的计数器数值增加1。

  • 提示:你需要为窗口部件(QWidget)的 mousePressEvent 事件重写,或者使用一个覆盖整个窗口的不可见按钮。
  • 预期输出:每点击一次窗口,标签数字加1。

练习 2:输入与响应 在练习1的基础上,增加一个 QLineEdit 输入框和一个"设置"按钮。输入框用于输入姓名,点击"设置"按钮后,将主标签的文字更新为"你好,[输入的姓名]!"。

  • 预期输出:输入"小明"并点击按钮,标签显示"你好,小明!"。

练习 3:探索 Qt Designer(可选高阶)

  1. 在终端安装 pyside6-tools (pip install pyside6-tools)。
  2. 打开 Qt Designer (通常在 Python 的 Scripts 目录下,如 pyside6-designer.exe)。
  3. 设计一个包含"用户名"、"密码"输入框和"登录"、"取消"按钮的登录界面。
  4. 将设计保存为 login.ui
  5. 编写 Python 代码,使用 uic.loadUi 加载此文件,并为"登录"按钮连接一个简单的槽函数(例如,在控制台打印"登录按钮被点击")。

常见错误

  1. 忘记调用 window.show():窗口创建后,必须显式调用 show() 方法才能将其显示在屏幕上。这是新手最常犯的错误之一。
  2. 信号连接错误
    • 写错了信号名(如 clicked 写成 click)。
    • 写错了槽函数名,或槽函数没有正确的 self 参数。
    • 尝试连接一个不存在的信号。
  3. 布局管理混乱:试图直接通过 widget.move(x, y) 来定位所有控件,而没有使用布局管理器。这会导致窗口缩放时界面错乱。优先使用布局管理器
  4. PyQt/PySide 导入混淆:PyQt5 的模块是 PyQt5.QtWidgets,PySide6 是 PySide6.QtWidgets。混用会导致导入错误。
  5. 没有创建 QApplication:在实例化任何 Qt 控件(如 QMainWindow)之前,必须先创建 QApplication 实例。

小结

本节课我们迈入了专业级 GUI 开发的大门:

  • 框架认知:了解了 PyQt 和 PySide 是 Python 访问强大 Qt 框架的两种主要途径,并知道了如何根据项目许可进行选择。
  • 核心机制:掌握了 Qt 的基石——信号与槽,理解了它是如何优雅地实现对象间通信的。
  • 实战入门:通过一个完整的例子,学习了使用 PySide6 创建窗口、添加控件、连接信号与槽,以及处理基本布局的全过程。
  • 工具链:了解了 Qt Designer 这个强大的辅助设计工具,它能极大提升复杂界面的开发效率。

掌握了 PyQt/PySide,你便拥有了开发跨平台(Windows, macOS, Linux)、外观现代化、功能强大且可扩展的桌面应用程序的能力。下一步,我们将学习如何将你的精美 GUI 程序打包并分发给用户。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「项目打包与分发:setuptools 入门」 以巩固所学知识。