PyQt6 教程:基础入门篇 – wiki基地


PyQt6 教程:基础入门篇

导语:踏入桌面应用开发的奇妙世界

欢迎来到 PyQt6 的世界!如果你是 Python 开发者,并且渴望创建拥有图形用户界面 (GUI) 的桌面应用程序,那么你找对地方了。PyQt6 是一个功能强大、灵活且成熟的 GUI 工具包,它将 Qt 框架的强大功能与 Python 语言的简洁优雅完美结合。

在当今世界,虽然 Web 应用和移动应用占据了很大一部分市场,但桌面应用依然在特定领域(如专业工具、开发环境、离线应用等)扮演着不可替代的角色。学习 PyQt6 不仅能让你开发出专业的桌面软件,还能加深你对事件驱动编程、面向对象设计以及跨平台开发的理解。

本教程是 PyQt6 的基础入门篇,我们将从零开始,一步步带你了解 PyQt6 的核心概念,构建你的第一个 GUI 应用程序,并学习如何使用基本的控件(Widgets)、布局(Layouts)和信号与槽(Signals and Slots)机制。无论你是完全的 GUI 开发新手,还是有其他 GUI 框架经验,本教程都将为你打下坚实的基础。

准备好了吗?让我们开始这段令人兴奋的旅程吧!

第一章:PyQt6 是什么?为什么选择它?

1.1 什么是 PyQt6?

PyQt6 是一个 Python 绑定库,用于创建图形用户界面 (GUI) 应用程序。它基于著名的 Qt 框架,由 Riverbank Computing 开发和维护。Qt 是一个跨平台的 C++ 应用程序开发框架,广泛用于开发 GUI 程序,但也用于创建非 GUI 程序,如控制台工具和服务器。PyQt6 则将 Qt 的强大功能通过 Python 接口暴露出来。

简单来说,PyQt6 让你能够使用你熟悉的 Python 语言来访问 Qt 库提供的所有类、方法和属性,从而轻松创建复杂的 GUI 应用程序。

1.2 为什么选择 PyQt6?

市面上有许多 Python GUI 库,比如 Tkinter(Python 内建)、Kivy、wxPython 等。那么,为什么选择 PyQt6 呢?

  • 强大且功能丰富: Qt 框架本身是一个非常成熟和全面的库,提供了大量的控件、图形渲染能力、多媒体支持、网络模块、数据库集成等等。PyQt6 继承了这一切,几乎可以用来开发任何类型的桌面应用程序。
  • 跨平台性: 使用 PyQt6 开发的应用可以在 Windows、macOS、Linux 等主流操作系统上运行,而无需修改代码。这极大地提高了开发效率和应用的可移植性。
  • 成熟和稳定: Qt 框架已经有超过 20 年的历史,经过了大量实际应用的检验。PyQt6 作为其成熟的绑定,也具有很高的稳定性和可靠性。
  • 良好的文档和社区支持: Qt 拥有详尽的官方文档,PyQt6 的文档也相当不错。同时,Qt 和 PyQt 都有庞大的用户社区,遇到问题时很容易找到帮助。
  • Pythonic 风格: PyQt6 的设计尽可能地遵循 Python 的语法和习惯,使得 Python 开发者感觉更加亲切和易用。
  • 集成的工具: PyQt6 通常与 Qt Designer 等可视化界面设计工具配合使用,可以大大加快 UI 界面的开发速度。

虽然 PyQt6 是商业许可和 GPLv3 双重许可的,对于大多数个人开发者或开源项目来说,使用 GPLv3 许可是可行的(意味着你的应用程序也必须是 GPL 兼容的开源项目)。如果需要开发闭源商业软件,则需要购买商业许可。但对于学习和个人项目,GPLv3 通常足够了。

第二章:环境准备与安装

在开始编写代码之前,我们需要确保 Python 环境已准备好,并正确安装 PyQt6 库。

2.1 Python 环境

你需要安装 Python 解释器。建议使用 Python 3.6 或更高版本。你可以从 Python 官方网站 下载并安装。

强烈建议使用虚拟环境(Virtual Environment) 来管理项目依赖。虚拟环境可以隔离不同项目的库,避免版本冲突。

创建并激活虚拟环境的步骤(以 venv 为例):

  1. 创建虚拟环境:
    bash
    python -m venv myenv

    myenv 是你虚拟环境的名称,可以随意命名)

  2. 激活虚拟环境:

    • Windows:
      bash
      myenv\Scripts\activate
    • macOS/Linux:
      bash
      source myenv/bin/activate

激活虚拟环境后,你的终端提示符前会显示虚拟环境的名称,表示你现在处于该环境中。

2.2 安装 PyQt6

确保你的虚拟环境已激活,然后使用 pip 安装 PyQt6:

bash
pip install PyQt6

这将自动下载并安装 PyQt6 及其所需的依赖项。安装过程可能需要一些时间,取决于你的网络速度。

如果你还想使用 Qt Designer 等工具,可以额外安装 pyqt6-tools

bash
pip install pyqt6-tools

安装 pyqt6-tools 后,可以在虚拟环境的 Scripts (Windows) 或 bin (macOS/Linux) 目录下找到 designer 可执行文件,这就是 Qt Designer。

安装完成后,你可以通过简单的 Python 代码来验证 PyQt6 是否安装成功:

python
import PyQt6
print("PyQt6 安装成功!")

如果运行这段代码没有报错并输出了信息,那么恭喜你,PyQt6 环境已经准备就绪!

第三章:你的第一个 PyQt6 应用程序 – “Hello World”

每个编程学习旅程都始于 “Hello World”。PyQt6 的 “Hello World” 是一个最简单的窗口应用程序。让我们来创建它。

创建一个新的 Python 文件,比如 hello_world.py,然后输入以下代码:

“`python
import sys
from PyQt6.QtWidgets import QApplication, QWidget

1. 创建一个应用程序实例

QApplication 类负责处理事件循环、窗口管理等

sys.argv 参数允许我们从命令行传递参数到应用程序

app = QApplication(sys.argv)

2. 创建一个顶级窗口 (顶层窗口通常是主窗口)

QWidget 是所有用户界面对象的基类

window = QWidget()

3. 设置窗口的标题

window.setWindowTitle(“Hello PyQt6”)

4. 设置窗口的初始大小和位置 (x, y, width, height)

window.setGeometry(100, 100, 280, 80) # 窗口出现在屏幕坐标(100, 100)处,大小为280×80像素

5. 显示窗口

window.show()

6. 启动应用程序的事件循环

app.exec() 方法启动应用程序的事件循环,让程序进入待机状态

直到用户关闭窗口或其他事件发生,事件循环才会停止,程序才会退出

sys.exit(app.exec())
“`

保存文件,然后在激活的虚拟环境终端中运行它:

bash
python hello_world.py

你将看到一个简单的小窗口弹出,标题栏显示着 “Hello PyQt6″。这个窗口现在还不能做任何事情,但它标志着你成功运行了第一个 PyQt6 应用程序!

代码解析:理解每一行

让我们仔细分析上面代码中的每一行:

  • import sys: 导入 Python 的 sys 模块,它提供了与 Python 解释器及其环境交互的功能。我们在这里需要 sys.argv
  • from PyQt6.QtWidgets import QApplication, QWidget: 从 PyQt6 的 QtWidgets 模块中导入 QApplicationQWidget 类。
    • QApplication: 应用程序类。每个 PyQt6 应用程序都必须创建一个 QApplication 实例。它负责初始化 GUI 环境,处理事件循环,以及管理应用程序的全局设置。
    • QWidget: 窗口组件的基类。它可以作为一个独立的窗口使用,也可以作为其他控件的容器。
  • app = QApplication(sys.argv): 创建 QApplication 类的实例。sys.argv 包含了命令行参数列表,这对于允许应用程序接收命令行参数是很重要的(尽管在这个简单的例子中它们可能没有被使用)。
  • window = QWidget(): 创建一个 QWidget 类的实例,这将是我们的主窗口。QWidget 默认就是一个空白窗口。
  • window.setWindowTitle("Hello PyQt6"): 设置窗口的标题栏文本。
  • window.setGeometry(100, 100, 280, 80): 设置窗口的几何形状,即位置和大小。参数分别是:窗口左上角的 x 坐标,左上角的 y 坐标,窗口的宽度,窗口的高度。这些坐标是相对于屏幕的左上角 (0, 0)。
  • window.show(): 使窗口可见。默认情况下,创建的控件是不可见的。
  • sys.exit(app.exec()):
    • app.exec(): 这是应用程序的主循环入口。它启动 Qt 事件循环,程序进入等待状态,响应用户的交互(如点击按钮、输入文本、关闭窗口等)或系统事件。当事件循环退出时(通常是主窗口被关闭),app.exec() 返回一个退出状态码。
    • sys.exit(...): Python 的标准函数,用于退出程序。它接收一个退出状态码,并将其传递给操作系统。使用 sys.exit() 确保程序干净地退出。

这个简单的例子展示了任何 PyQt6 应用程序的基本骨架:导入必要的模块,创建 QApplication 实例,创建并配置一个或多个窗口/控件,显示它们,然后启动应用程序的事件循环。

第四章:核心概念 – 窗口、控件与布局

GUI 应用程序的核心是各种可视化的元素,它们用于显示信息和与用户交互。在 PyQt6 中,这些元素被称为 控件 (Widgets)。窗口本身也是一种特殊的控件。

4.1 控件 (Widgets)

QWidget 是所有控件的基类。PyQt6 提供了大量内置的控件,常用的包括:

  • QLabel: 用于显示文本或图片。
  • QPushButton: 一个可点击的按钮。
  • QLineEdit: 单行文本输入框。
  • QTextEdit: 多行文本输入框。
  • QCheckBox: 复选框。
  • QRadioButton: 单选按钮。
  • QSlider: 滑动条。
  • QComboBox: 下拉列表。
  • QListWidget: 列表框。
  • QTableWidget: 表格。
  • QMenuBar, QToolBar, QStatusBar: 用于构建主窗口的应用菜单、工具栏和状态栏。
  • QMainWindow: 提供一个框架,用于构建应用程序的主窗口,包含菜单栏、工具栏、状态栏和中心区域。

让我们修改一下 “Hello World” 程序,在窗口中添加一个标签 (QLabel) 和一个按钮 (QPushButton)。

“`python
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout

class MyWidget(QWidget):
def init(self):
super().init()

    self.setWindowTitle("窗口与控件示例")
    # self.setGeometry(100, 100, 300, 200) # 暂时不固定大小,让布局管理器决定

    # 创建一个标签
    self.label = QLabel("你好,PyQt6!")
    # 可以设置标签的对齐方式
    # self.label.setAlignment(PyQt6.QtCore.Qt.AlignmentFlag.AlignCenter)

    # 创建一个按钮
    self.button = QPushButton("点我一下")

    # 创建一个垂直布局管理器
    layout = QVBoxLayout()
    # 将标签和按钮添加到布局中
    layout.addWidget(self.label)
    layout.addWidget(self.button)

    # 将布局设置到窗口上
    # QWidget 需要一个容器来应用布局,自身就可以作为容器
    self.setLayout(layout)

if name == “main“:
app = QApplication(sys.argv)

# 创建我们的自定义窗口实例
my_window = MyWidget()
my_window.show()

sys.exit(app.exec())

“`

在这个例子中,我们做了一些重要改变:

  1. 我们创建了一个名为 MyWidget 的类,它继承自 QWidget。这是一种更好的组织代码的方式,特别是对于更复杂的应用程序。在类的 __init__ 方法中设置窗口属性和创建控件。
  2. 导入了 QLabel, QPushButton, QVBoxLayout 类。
  3. 创建了 QLabelQPushButton 的实例。
  4. 引入了布局管理器 QVBoxLayout

4.2 布局管理器 (Layouts)

手动设置每个控件的位置 (move()setGeometry()) 在简单的例子中可行,但在更复杂的界面中会变得非常麻烦。而且,当用户调整窗口大小时,控件的位置和大小不会自动调整,导致界面混乱。

布局管理器就是用来解决这个问题的!它们负责自动安排和管理窗口中控件的位置和大小,确保界面在窗口大小变化时仍能保持良好组织。

PyQt6 提供了多种常用的布局管理器:

  • QVBoxLayout: 垂直布局,控件从上到下排列。
  • QHBoxLayout: 水平布局,控件从左到右排列。
  • QGridLayout: 网格布局,控件放置在由行和列组成的网格中。
  • QFormLayout: 表单布局,常用于创建标签-输入框对的表单。

在上面的例子中,我们使用了 QVBoxLayout

  1. layout = QVBoxLayout(): 创建一个垂直布局管理器实例。
  2. layout.addWidget(self.label): 将 label 控件添加到布局中。它会放在布局的顶部。
  3. layout.addWidget(self.button): 将 button 控件添加到布局中。它会放在 label 的下方。
  4. self.setLayout(layout): 将创建好的布局管理器设置到 MyWidget 实例上。一旦布局被设置,它就会负责管理添加到其中的控件。

运行修改后的代码,你会看到一个窗口,其中标签在上方,按钮在下方。尝试调整窗口大小,你会发现标签和按钮会随着窗口的大小变化而自动调整位置和可能的大小(取决于控件和布局的策略)。

4.3 更复杂的布局

布局管理器可以嵌套使用,以创建更复杂的界面结构。例如,你可以将一个 QHBoxLayout 放入一个 QVBoxLayout 中,或者将多个布局组合在一个 QGridLayout 中。

示例:水平布局中的多个按钮

“`python
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout, QVBoxLayout

class LayoutExample(QWidget):
def init(self):
super().init()

    self.setWindowTitle("布局嵌套示例")
    # self.setGeometry(100, 100, 400, 150)

    # 创建主垂直布局
    main_layout = QVBoxLayout()

    # 创建一个水平布局,用于放置按钮
    button_layout = QHBoxLayout()

    # 创建几个按钮
    button1 = QPushButton("按钮 A")
    button2 = QPushButton("按钮 B")
    button3 = QPushButton("按钮 C")

    # 将按钮添加到水平布局中
    button_layout.addWidget(button1)
    button_layout.addWidget(button2)
    button_layout.addWidget(button3)

    # 将水平布局添加到主垂直布局中
    # 可以在水平布局上方或下方添加其他控件或布局
    # main_layout.addWidget(QLabel("上方标签")) # 可以在这里添加其他控件
    main_layout.addLayout(button_layout)
    # main_layout.addWidget(QLabel("下方标签")) # 可以在这里添加其他控件

    # 将主布局设置到窗口上
    self.setLayout(main_layout)

if name == “main“:
app = QApplication(sys.argv)
window = LayoutExample()
window.show()
sys.exit(app.exec())
“`

在这个例子中,我们创建了一个 QHBoxLayout 来水平排列三个按钮,然后将这个 QHBoxLayout 添加到了主 QVBoxLayout 中。这样,按钮会在窗口下方水平排列,而上方区域可以用来放置其他内容。注意,将布局添加到另一个布局使用的是 addLayout() 方法,而不是 addWidget()

QGridLayout 示例

QGridLayout 允许你将控件放置在指定的行和列中。

“`python
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QGridLayout

class GridLayoutExample(QWidget):
def init(self):
super().init()

    self.setWindowTitle("网格布局示例")

    grid_layout = QGridLayout()

    # 添加控件到网格布局 (控件, 行, 列, [行跨度, 列跨度])
    grid_layout.addWidget(QLabel("姓名:"), 0, 0) # 行0, 列0
    grid_layout.addWidget(QLineEdit(), 0, 1)    # 行0, 列1

    grid_layout.addWidget(QLabel("年龄:"), 1, 0) # 行1, 列0
    grid_layout.addWidget(QLineEdit(), 1, 1)    # 行1, 列1

    grid_layout.addWidget(QLabel("地址:"), 2, 0) # 行2, 列0
    grid_layout.addWidget(QLineEdit(), 2, 1, 1, 2) # 行2, 列1, 跨1行, 跨2列 (占据列1和列2)

    submit_button = QPushButton("提交")
    grid_layout.addWidget(submit_button, 3, 0, 1, 2) # 行3, 列0, 跨1行, 跨2列 (占据列0和列1)

    self.setLayout(grid_layout)

if name == “main“:
app = QApplication(sys.argv)
window = GridLayoutExample()
window.show()
sys.exit(app.exec())
``
这个例子展示了如何使用
QGridLayout` 创建一个简单的表单布局,并使用行/列跨度来合并单元格。

理解并熟练使用布局管理器是 PyQt6 GUI 开发的关键一步。它们让你的界面更加灵活、适应性更强。

第五章:核心概念 – 信号与槽 (Signals and Slots)

创建了好看的界面是第一步,但应用程序需要能够响应用户的操作。在 PyQt6 中,这主要通过信号与槽 (Signals and Slots) 机制来实现。

5.1 什么是信号与槽?

信号与槽是 Qt 框架的核心特性之一,用于对象之间的通信。它们提供了一种类型安全的方式来处理事件。

  • 信号 (Signal): 当某个特定事件发生时,一个控件会发射(emit)一个信号。例如,当用户点击一个按钮时,按钮会发射一个 clicked 信号;当文本输入框的内容改变时,它会发射 textChanged 信号。信号本身并不知道或关心哪个对象接收它。
  • 槽 (Slot): 槽是普通的 Python 函数或类方法。当与信号连接时,槽会在该信号被发射时自动被调用。槽就是用来响应特定事件的代码块。

信号与槽的关系类似于发布/订阅模式:一个对象(信号的发射者)发布一个事件(信号),而另一个或多个对象(槽的接收者)订阅这个事件(通过连接信号与槽),并在事件发生时执行相应的操作(调用槽)。

5.2 连接信号与槽

连接信号与槽的基本语法是:

“`python
sender.signal.connect(receiver.slot)

或连接到普通函数

sender.signal.connect(function)
“`

  • sender: 发射信号的控件对象。
  • signal: 控件发射的信号(通常是一个可调用的属性,如 clicked, textChanged)。
  • receiver: 接收信号的对象(通常是另一个控件或窗口实例)。
  • slot: 接收对象中用于处理信号的方法,或者是一个普通的函数。

示例:按钮点击事件

让我们修改之前的 MyWidget 示例,让按钮被点击时改变标签的文本。

“`python
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout
from PyQt6.QtCore import Qt # 导入Qt模块,用于对齐方式

class MyWidgetWithSignal(QWidget):
def init(self):
super().init()

    self.setWindowTitle("信号与槽示例")

    self.label = QLabel("点击下面的按钮")
    self.label.setAlignment(Qt.AlignmentFlag.AlignCenter) # 文本居中

    self.button = QPushButton("点我改变文本")

    # 创建布局
    layout = QVBoxLayout()
    layout.addWidget(self.label)
    layout.addWidget(self.button)
    self.setLayout(layout)

    # 连接信号与槽!
    # 当 self.button 发射 clicked 信号时,调用 self.change_label_text 方法
    self.button.clicked.connect(self.change_label_text)

# 这是一个槽方法
def change_label_text(self):
    """槽函数:改变标签文本"""
    print("按钮被点击了!") # 可以在终端看到输出
    self.label.setText("按钮已经被点击了!")
    self.button.setText("已点击") # 也可以改变按钮本身的文本
    self.button.setEnabled(False) # 按钮变灰,不可再点击

if name == “main“:
app = QApplication(sys.argv)
my_window = MyWidgetWithSignal()
my_window.show()
sys.exit(app.exec())
“`

运行这个例子,当你点击按钮时,标签的文本会改变,按钮的文本也会改变并变为不可用。同时,终端会输出 “按钮被点击了!”。

代码解析:

  1. 我们在 MyWidgetWithSignal 类中定义了一个新的方法 change_label_text()。这个方法就是我们的槽。它包含了我们希望在按钮被点击时执行的代码。
  2. __init__ 方法的末尾,我们写了 self.button.clicked.connect(self.change_label_text)
    • self.button: 发射信号的对象。
    • .clicked: QPushButton 类内置的一个信号,当按钮被点击时发射。
    • .connect(): 用于连接信号与槽的方法。
    • self.change_label_text: 槽函数(类的方法)。注意,这里传递的是方法的引用(不带括号 ()),而不是调用它。

当用户点击 self.button 时,clicked 信号被发射,PyQt6 的事件循环检测到这个连接,并自动调用 self.change_label_text() 方法。

5.3 信号可以传递数据

有些信号会携带数据。例如,QLineEdittextChanged 信号会发射一个字符串参数,表示新的文本内容。你的槽函数需要能够接收这些参数。

示例:文本输入框内容变化事件

“`python
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QVBoxLayout
from PyQt6.QtCore import Qt

class SignalWithDataExample(QWidget):
def init(self):
super().init()

    self.setWindowTitle("信号带数据示例")

    self.input_label = QLabel("请输入文本:")
    self.input_lineedit = QLineEdit()
    self.display_label = QLabel("你输入的内容将显示在这里")
    self.display_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

    layout = QVBoxLayout()
    layout.addWidget(self.input_label)
    layout.addWidget(self.input_lineedit)
    layout.addWidget(self.display_label)

    self.setLayout(layout)

    # 连接信号与槽
    # textChanged 信号发射时会带上当前文本作为参数
    self.input_lineedit.textChanged.connect(self.update_display_label)

# 槽函数,接收一个字符串参数 (lineEdit 发射的文本)
def update_display_label(self, text):
    """槽函数:更新显示标签的文本"""
    if text: # 如果文本不为空
        self.display_label.setText(f"你输入了: {text}")
    else:
         self.display_label.setText("你输入的内容将显示在这里")

if name == “main“:
app = QApplication(sys.argv)
window = SignalWithDataExample()
window.show()
sys.exit(app.exec())
“`

运行此代码,在文本输入框中输入内容,你会看到下方标签的文本会实时更新,显示你输入的内容。

代码解析:

  1. QLineEdittextChanged 信号在文本框内容每次变化时发射,并携带一个表示当前文本的字符串参数。
  2. 我们的槽函数 update_display_label 定义了一个参数 text 来接收这个字符串。
  3. 通过 self.input_lineedit.textChanged.connect(self.update_display_label),我们将信号连接到槽,确保每次文本变化时,update_display_label 方法都会被调用,并将新的文本作为参数传递进去。

信号与槽机制是 PyQt6 中实现交互性的基石。理解它对于开发任何非 trivial 的 PyQt6 应用程序至关重要。

第六章:构建一个简单的应用示例 – 文本转换器

让我们综合运用前面学到的知识:控件、布局、信号与槽,来构建一个简单的应用:一个可以将输入文本转换为大写或小写的工具。

“`python
import sys
from PyQt6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QPushButton)
from PyQt6.QtCore import Qt

class TextConverterApp(QWidget):
def init(self):
super().init()

    self.setWindowTitle("文本转换器")
    self.setGeometry(200, 200, 400, 150) # 设置一个初始大小和位置

    # 创建主布局 (垂直)
    main_layout = QVBoxLayout()

    # 1. 输入区域
    input_layout = QHBoxLayout()
    self.input_label = QLabel("输入文本:")
    self.input_lineedit = QLineEdit()
    input_layout.addWidget(self.input_label)
    input_layout.addWidget(self.input_lineedit)

    # 2. 按钮区域
    button_layout = QHBoxLayout()
    self.upper_button = QPushButton("转大写")
    self.lower_button = QPushButton("转小写")
    button_layout.addWidget(self.upper_button)
    button_layout.addWidget(self.lower_button)

    # 3. 输出区域
    output_layout = QHBoxLayout()
    self.output_label = QLabel("输出结果:")
    # 使用 QLabel 作为输出区域,设置文本可选中以便复制
    self.output_display = QLabel("") # 初始为空
    self.output_display.setWordWrap(True) # 文本自动换行
    self.output_display.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse | Qt.TextInteractionFlag.TextSelectableByKeyboard) # 使文本可选择

    output_layout.addWidget(self.output_label)
    output_layout.addWidget(self.output_display)
    output_layout.setStretch(0, 0) # 设置输入标签不伸缩
    output_layout.setStretch(1, 1) # 设置输出显示区域伸缩,占据剩余空间

    # 将子布局添加到主布局
    main_layout.addLayout(input_layout)
    main_layout.addLayout(button_layout)
    main_layout.addLayout(output_layout)

    # 设置主布局到窗口
    self.setLayout(main_layout)

    # 连接信号与槽
    # 按钮点击信号连接到各自的处理方法
    self.upper_button.clicked.connect(self.convert_to_uppercase)
    self.lower_button.clicked.connect(self.convert_to_lowercase)

    # 也可以连接输入框文本变化信号,实时更新输出 (可选)
    # self.input_lineedit.textChanged.connect(self.update_output_realtime)


# 槽方法:转换为大写
def convert_to_uppercase(self):
    """获取输入文本,转换为大写,并显示在输出标签"""
    input_text = self.input_lineedit.text() # 获取 QLineEdit 的文本
    output_text = input_text.upper()      # 转换为大写
    self.output_display.setText(output_text) # 设置 QLabe 的文本

# 槽方法:转换为小写
def convert_to_lowercase(self):
    """获取输入文本,转换为小写,并显示在输出标签"""
    input_text = self.input_lineedit.text() # 获取 QLineEdit 的文本
    output_text = input_text.lower()      # 转换为小写
    self.output_display.setText(output_text) # 设置 QLabe 的文本

# 可选槽方法:实时更新输出
# def update_output_realtime(self, text):
#     """实时将输入文本显示在输出标签 (无需转换)"""
#     self.output_display.setText(text)

if name == “main“:
app = QApplication(sys.argv)
window = TextConverterApp()
window.show()
sys.exit(app.exec())
“`

应用程序结构解析:

  1. 类继承: 我们创建了一个继承自 QWidgetTextConverterApp 类,将整个应用程序封装在一个对象中。这使得代码更加模块化和易于管理。
  2. 控件创建:__init__ 方法中,我们创建了所有需要的控件:两个 QLabel (用于标签提示和显示结果),一个 QLineEdit (用于输入),以及两个 QPushButton (用于转换操作)。
  3. 布局构建:
    • 使用 QVBoxLayout 作为主布局。
    • 使用两个 QHBoxLayout 分别组织输入框和按钮。
    • 使用第三个 QHBoxLayout 组织输出标签和显示区域 (output_display 这个 QLabel)。
    • 通过 main_layout.addLayout() 将子布局添加到主布局中。
    • output_layout.setStretch(index, stretch_factor) 用于控制布局中元素的伸缩比例。setStretch(1, 1)self.output_display 占据尽可能多的剩余水平空间。
  4. 信号与槽连接:
    • self.upper_button.clicked.connect(self.convert_to_uppercase): 当“转大写”按钮点击时,调用 convert_to_uppercase 方法。
    • self.lower_button.clicked.connect(self.convert_to_lowercase): 当“转小写”按钮点击时,调用 convert_to_lowercase 方法。
  5. 槽方法实现: convert_to_uppercaseconvert_to_lowercase 方法是槽。它们获取 QLineEdit 的当前文本 (self.input_lineedit.text()),执行相应的字符串转换 (.upper().lower()),然后使用 setText() 方法更新 self.output_display 标签的内容。

这个例子展示了如何将不同的控件、布局和信号与槽结合起来,创建一个简单的、具有实际功能的 GUI 应用程序。

第七章:使用 QMainWindow 作为主窗口 (可选但推荐)

在前面的例子中,我们直接使用了 QWidget 作为主窗口。对于更复杂的应用程序,通常建议使用 QMainWindow 作为顶级窗口。QMainWindow 提供了一个标准的应用程序窗口框架,包含了内置支持的菜单栏(QMenuBar)、工具栏(QToolBar)、状态栏(QStatusBar),以及一个中心区域(central widget),你可以在中心区域放置其他控件或布局。

虽然这不是绝对的基础,但了解 QMainWindow 对构建更专业的应用程序很有帮助。

“`python
import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QLabel, QPushButton, QLineEdit, QStatusBar, QMenuBar)
from PyQt6.QtCore import Qt

class MainWindowExample(QMainWindow): # 继承自 QMainWindow
def init(self):
super().init()

    self.setWindowTitle("QMainWindow 示例")
    self.setGeometry(300, 300, 500, 200)

    # 1. 创建中心区域 (Central Widget)
    # QMainWindow 需要一个 QWidget 作为其中心控件,所有主要的界面元素都放在这里
    central_widget = QWidget()
    self.setCentralWidget(central_widget)

    # 2. 创建布局 (用于中心区域)
    layout = QVBoxLayout(central_widget) # 将布局直接设置到 central_widget 上

    # 添加一些控件到布局
    self.label = QLabel("这是一个中心区域的标签")
    self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
    self.button = QPushButton("点击这里")

    layout.addWidget(self.label)
    layout.addWidget(self.button)

    # 3. 创建菜单栏 (可选)
    # menu_bar = self.menuBar()
    # file_menu = menu_bar.addMenu("&文件") # &符号表示Alt+F快捷键
    # file_menu.addAction("新建")
    # file_menu.addAction("打开")
    # file_menu.addSeparator() # 分隔线
    # file_menu.addAction("退出").triggered.connect(self.close) # 连接退出动作到窗口关闭槽

    # 4. 创建状态栏 (可选)
    self.statusBar().showMessage("应用程序已启动")

    # 5. 创建工具栏 (可选)
    # toolbar = self.addToolBar("主要工具")
    # toolbar.addAction("打开").triggered.connect(lambda: self.statusBar().showMessage("点击了打开工具"))

    # 连接信号与槽
    self.button.clicked.connect(self.on_button_click)


def on_button_click(self):
    """按钮点击槽"""
    self.label.setText("按钮被点击了!")
    self.statusBar().showMessage("按钮被点击了!") # 更新状态栏信息

if name == “main“:
app = QApplication(sys.argv)
window = MainWindowExample()
window.show()
sys.exit(app.exec())
“`

QMainWindow 解析:

  • 我们继承自 QMainWindow 而不是 QWidget
  • QMainWindow 不能直接使用 setLayout() 设置布局。你需要创建一个 QWidget 实例作为中心控件 (central_widget),然后将这个控件设置到 QMainWindow 上 (self.setCentralWidget(central_widget))。所有的主要 UI 元素和布局都应该放在这个 central_widget 中。
  • QMainWindow 提供了 menuBar(), statusBar(), addToolBar() 方法来创建和访问菜单栏、状态栏和工具栏。这些是 QMainWindow 特有的区域,不需要手动添加到布局中。
  • 在上面的例子中,我们创建了一个简单的中心区域布局,并添加了标签和按钮。同时,我们也创建了一个状态栏并在启动时显示信息,以及在按钮点击时更新状态栏信息。菜单栏和工具栏的代码被注释掉了,你可以取消注释并运行代码查看效果。

对于大多数桌面应用程序,使用 QMainWindow 作为主窗口是一种更规范和灵活的方式。

第八章:下一步去哪里?

恭喜你!你已经完成了 PyQt6 的基础入门学习。你现在应该对如何创建一个基本的 PyQt6 窗口、使用常见的控件、组织界面布局以及通过信号与槽响应用户操作有了基本的理解。

这仅仅是 PyQt6 强大功能的冰山一角。接下来,你可以继续深入学习:

  1. 更多的控件: 探索 PyQt6/Qt 提供的其他丰富控件,如图形视图、日历控件、进度条、文件对话框等。
  2. 对话框 (Dialogs): 学习如何创建和使用各种标准对话框(文件选择、颜色选择、字体选择等)和自定义对话框。
  3. 事件处理: 深入理解 Qt 的事件系统,除了信号与槽,还有事件过滤器等高级机制。
  4. 自定义信号与槽: 学习如何在自己的类中定义和使用自定义信号。
  5. 模型/视图编程 (Model/View Programming): 学习如何使用 Model/View 架构处理大量数据(如列表、表格、树状结构),这是构建高效数据密集型应用的关键。
  6. 绘图与图形: 学习如何使用 QPainter 进行自定义绘图,或使用图形视图框架处理复杂的图形场景。
  7. 多线程: 在 GUI 应用中执行耗时操作时,学习如何使用线程避免界面冻结。
  8. 样式表 (Style Sheets): 学习如何使用 QSS (Qt Style Sheets) 为你的应用程序美化界面,类似于 Web 开发中的 CSS。
  9. 国际化 (i18n): 学习如何让你的应用支持多种语言。
  10. 使用 Qt Designer: 学习如何使用可视化工具设计 .ui 文件,然后用 pyuic6 将其转换为 Python 代码,或者在运行时加载 .ui 文件。这可以大大提高 UI 开发效率。
  11. 应用程序打包: 学习如何使用 PyInstaller 等工具将你的 Python PyQt6 应用程序打包成可执行文件,方便分发给没有安装 Python 环境的用户。

PyQt6 社区资源丰富,Qt 官方文档(尽管是 C++ 版,但类名和概念是通用的)和 PyQt6 文档是最好的参考资料。大量的在线教程、博客和开源项目也是学习的宝库。

结语

学习 GUI 编程是一个实践出真知过程。不要害怕尝试,多写代码,多实践小项目。从简单的计算器、待办事项列表开始,逐步挑战更复杂的应用。

PyQt6 提供了一个坚实而强大的基础,让你能够使用 Python 的力量创造出专业级的桌面应用程序。希望本入门教程为你打开了这扇门,激发了你进一步探索的兴趣。

祝你在 PyQt6 的学习和开发之旅中一切顺利!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部