learnxinyminutes-docs 实战指南:用 PyQt4 快速上手 Qt 跨平台 GUI 编程

原创2026-10-07 21:02:561,759 阅读
文章标签:文档教程

learnxinyminutes-docs 实战指南:用 PyQt4 快速上手 Qt 跨平台 GUI 编程

导读

本文基于 learnxinyminutes-docs 仓库中的 id/pyqt.md(印度尼西亚语译本)及其英文原版 pyqt.md,系统讲解如何使用 PyQt4 在 Python 中构建 Qt 跨平台桌面应用。Qt 是业界著名的 C++ 跨平台 GUI 框架,而 PyQt 是其在 Python 世界的官方绑定;读完本文,你将掌握 Qt 应用的最小骨架(QApplication + QWidget 事件循环模型)、控件的创建与父子关系组织、信号与槽(signals & slots)事件驱动机制,以及模态对话框的实现方式,并直接获得两个可复制运行、逐行注释的完整示例程序。

Qt 与 PyQt:跨平台 GUI 的原生体验

Qt 是一个广为人知的跨平台软件开发框架,能够在各种软件与硬件平台上以很少甚至零代码改动运行,同时保持原生应用程序的速度与能力。Qt 最初由 C++ 编写,而 PyQt 则是 Qt 面向 Python 的绑定库,让开发者可以用 Python 语法享受 Qt 全部控件与事件体系——这正是本文所依托的核心技术栈。

id/pyqt.md 明确说明,该文改编自 Aleksey Kholovchuk 撰写的 C++ 版 Qt 入门,代码示例在功能上与 C++ 原版等价,只是全部改用 PyQt 实现。这从侧面说明:PyQt 与 Qt 的编程模型一一对应,理解本文示例后,你也能顺畅阅读 Qt/C++ 生态的资料。

环境准备:基于 PyQt4 的代码前提

仓库内的 pyqt 系列文档(如 pyqt.md、zh-cn/pyqt.md、id/pyqt.md)均基于 PyQt4 编写,其模块结构为:

  • PyQt4.QtGui:GUI 控件库(窗口、按钮、标签、对话框等)
  • PyQt4.QtCore:核心非 GUI 功能(信号、槽、事件循环辅助、枚举常量如 Qt.ApplicationModal 等)

需要说明的是,PyQt4 属于较早的 Qt 4 时代绑定版本,其模块划分(QtGui 同时容纳控件与窗口系统 API)与后续的 PyQt5/PyQt6(控件类迁移至 QtWidgets 模块)有所不同。若要在新环境运行文中代码,请先安装对应的 PyQt4 运行环境;若使用 PyQt5/PyQt6,只需将导入语句对应调整(如 from PyQt5.QtWidgets import QApplication, QWidget, QLabel),核心的编程模型与 API 命名基本保持延续。仓库中 qt.md、de/qt.md、zh-cn/qt.md 等文档还提供了 C++ 原生 Qt 的对照视角,可交叉阅读。

第一个 PyQt 程序:从零搭建"Hello World"窗口

以下代码是 id/pyqt.md 的核心示例之一,它完整展示了任何 PyQt 应用都必备的五步骨架:创建应用对象 → 创建控件 → 设置内容与几何属性 → 显示 → 进入事件循环。我们将逐行拆解。

import sys
from PyQt4 import QtGui

def window():
    # Buat objek aplikasi(创建应用对象)
    app = QtGui.QApplication(sys.argv)
    # Buat sebuah widget, sebagai tempat di mana label kita akan ditempatkan
    # (创建一个 widget,作为放置 label 的容器)
    w = QtGui.QWidget()
    # Tambahkan label untuk widget(为 widget 添加一个 label 子控件)
    b = QtGui.QLabel(w)
    # Set teks untuk label(设置 label 的文本)
    b.setText("Halo, Dunia!")
    # Set parameter penempatan dan ukuran(设置位置与尺寸参数)
    w.setGeometry(100, 100, 200, 50)
    b.move(50, 20)
    # Set judul pada jendela(设置窗口标题)
    w.setWindowTitle("PyQt")
    # Tampilkan segalanya(显示所有内容)
    w.show()
    # Jalankan apa yang telah kita atur(运行已配置好的应用)
    sys.exit(app.exec_())

if __name__ == '__main__':
    window()

逐层拆解:应用对象与事件循环

  • QtGui.QApplication(sys.argv):每个 PyQt 程序都必须且只能创建一个 QApplication 实例,它是整个 GUI 程序的"心脏",负责管理事件循环、窗口系统资源与全局设置。sys.argv 让应用能接收命令行参数。
  • QtGui.QWidget():QWidget 是所有控件的基类与通用容器。这里它作为顶级窗口使用,也是后续所有子控件的"父容器"。
  • QtGui.QLabel(w):创建标签控件,并把 w 作为其父控件传入。父子关系是 Qt 对象生命周期管理的关键——父控件析构时会自动清理子控件,且子控件会随父控件一起显示、移动。
  • b.setText("Halo, Dunia!"):设置标签文本。原文使用印尼语问候语"Halo, Dunia!"(即 Hello World),在 pyqt.md 英文原版中对应文本为 "Hello World!",多语言译本均保留了各自的本地化示例。
  • w.setGeometry(100, 100, 200, 50):以 (x, y, 宽, 高) 四个参数一次性设定窗口在屏幕上的位置(左上角距屏幕原点 100×100 像素)与尺寸(200×50 像素)。
  • b.move(50, 20):将 label 相对父控件 w 移动到 (50, 20) 偏移处——坐标是相对父控件的局部坐标,这是理解 Qt 布局的基础。
  • w.setWindowTitle("PyQt"):设置窗口标题栏文本。
  • w.show():默认情况下控件是隐藏的,必须显式调用 show() 才会渲染。它会同时显示该控件及其所有子控件。
  • sys.exit(app.exec_()):exec_() 启动事件循环并阻塞当前线程,直到最后一个窗口关闭或应用退出;事件循环期间 Qt 持续分发鼠标、键盘、重绘等事件。sys.exit 将应用退出码传递给操作系统。注意 PyQt4 中该方法名为 exec_()(带下划线),这是为了避免与 Python 2 的内置 exec 关键字冲突——这正是仓库文档选择 PyQt4 时代的遗留命名。

代码组织:if __name__ == '__main__'

末尾的 if __name__ == '__main__': 是 Python 的标准入口约定:当该文件作为脚本直接运行时执行 window(),而作为模块被导入时不执行,从而保证代码可复用、可测试。

信号与槽:让界面响应交互

Qt 最具特色的机制是信号与槽(signals & slots):控件在特定事件发生时发射信号(如按钮被点击时的 clicked),你可以把信号连接到任意函数(即"槽"),实现事件驱动的解耦设计。第二个示例展示了这一机制在对话框场景下的完整运用。

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *


def window():
    app = QApplication(sys.argv)
    w = QWidget()
    # Buat tombol b dan tempelkan pada widget w(创建按钮并挂到 widget w 上)
    b = QPushButton(w)
    b.setText("Tekan aku!")   # 按钮文本:"Press me!"(按我!)
    b.move(50, 50)
    # Perintahkan tombol b untuk memanggil fungsi ini ketika diklik
    # (命令按钮 b 在被点击时调用此函数)
    # Perhatikan bahwa kita tidak menggunakan simbol "()" pada pemanggilan fungsi kali ini
    # (注意:这次调用函数时没有使用 "()" 符号)
    b.clicked.connect(ShowDialog)
    w.setWindowTitle("Dialog PyQt")
    w.show()
    sys.exit(app.exec_())

# Fungsi ini akan membuat jendela dialog dengan tombol
# yang menunggu untuk diklik untuk keluar dari program
# (此函数将创建一个带按钮的对话框窗口,按钮等待被点击后退出程序)
def ShowDialog():
    d = QDialog()
    b1 = QPushButton("ok", d)
    b1.move(50, 50)
    d.setWindowTitle("Dialog")
    # Modalitas ini memberitahu popup untuk memblokir induk saat ini aktif
    # (此模态设置告诉弹出窗口:在其激活期间阻塞父窗口)
    d.setWindowModality(Qt.ApplicationModal)
    # Pada klik, kita ingin seluruh proses untuk berhenti(点击时终止整个进程)
    b1.clicked.connect(sys.exit)
    d.exec_()

if __name__ == '__main__':
    window()

连接信号的关键写法

  • b.clicked.connect(ShowDialog):这是信号与槽的核心调用。clicked 是 QPushButton 在用户点击时发射的信号,connect 把它与函数 ShowDialog 绑定。注意这里传入的是函数对象本身,而不是 ShowDialog()——加上括号就变成立即执行并传入返回值,而非"等到点击时再触发"。这正是 Qt 事件驱动模型与普通命令式编程的本质区别,zh-cn/pyqt.md 译本特别补充:此写法下函数以对象方式传入,更多信号传递、带参绑定的细节属于 PyQt 信号机制的进阶话题。
  • b1.clicked.connect(sys.exit):信号不仅可以连接自定义函数,也能直接连接内置可调用对象。点击"ok"按钮即触发 sys.exit,终止整个进程——这也是文档注释"On click I'd like the entire process to end"的意图。

模态对话框:阻塞父窗口的交互

  • QDialog():QDialog 是专门用于对话框的窗口类,常用于请求用户确认决策或展示信息,正对应文档所述"useful for asking the user to confirm a decision or to provide information"。
  • d.setWindowModality(Qt.ApplicationModal):设置应用级模态(Qt.ApplicationModal 枚举来自 QtCore)。模态对话框激活期间会阻塞其父窗口(乃至整个应用)的输入,强制用户先处理对话框——这是"确认关键操作"类交互的标准做法。Qt 枚举常量正是因此需要 from PyQt4.QtCore import * 的原因。
  • d.exec_():与 app.exec_() 类似,为对话框启动一个嵌套的事件循环,阻塞直到对话框关闭,并返回用户操作结果(如 OK/Cancel 的按钮角色)。

从示例到实战:可运行的完整流程

将两个示例分别保存为独立脚本(如 hello.py 与 dialog.py),在安装好 PyQt4 的 Python 环境中直接运行:

python hello.py
python dialog.py
  • hello.py 会弹出一个标题为 "PyQt"、尺寸 200×50 的窗口,中央偏右显示 "Halo, Dunia!" 文本。
  • dialog.py 会先显示带 "Tekan aku!" 按钮的主窗口;点击后弹出模态对话框 "Dialog",在对话框关闭(点击 "ok")之前,主窗口无法交互,点击 "ok" 则整个程序退出。

若你的环境使用 PyQt5/PyQt6,可将导入语句按如下方式迁移(PyQt5 起 GUI 控件统一移入 QtWidgets 模块,信号连接与模态 API 保持一致):

# PyQt5/PyQt6 等价写法示例
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QDialog
from PyQt5.QtCore import Qt

继续深入:仓库内的配套学习路径

learnxinyminutes-docs 为 PyQt 提供了多语言对照资料,便于你横向验证代码行为并深入不同侧面:

这套文档体系本身就是"同一逻辑、多语言实现"的绝佳教材:把 C++ 版与 PyQt 版并排阅读,即可快速建立"Qt 概念 → Python 表达"的映射能力,为后续学习布局管理器(Layout)、模型/视图、绘图等 PyQt 高级主题打下坚实基础。

登录后查看全文
learnxinyminutes-docs