Qt Widgets 速通:事件循环、信号槽、对象树与布局
Qt Widgets 速通:事件循环、信号槽、对象树与布局
Disboundary背景:先从能写小 GUI 开始
学习 Qt 时不一定要一开始就系统啃完整文档。更实用的路线是:先写出一个可运行的小 GUI 程序,再逐步理解常见代码为什么这么写。
这篇文章采用 Qt Widgets + C++ 作为入口。原因很简单:Qt Widgets 更适合快速理解传统桌面程序结构,也能直接暴露 Qt 的几个核心概念:事件循环、信号槽、QObject 对象模型和布局管理器。
一个最小 Qt 程序由什么组成
最小 Qt Widgets 程序大致如下:
1 |
|
这段代码里有三个关键对象或动作。
QApplication 表示整个 GUI 应用程序对象。它负责初始化 Qt GUI 环境、处理命令行参数、管理事件循环,并把鼠标、键盘、窗口等事件分发给对应对象。
QWidget 是 Qt Widgets 体系中最基础的界面类。它既可以表示普通控件,也可以作为一个窗口。
show() 负责真正显示窗口。只创建对象不会自动显示界面。
GUI 程序的核心是事件循环
普通控制台程序通常是:
1 | 进入 main |
GUI 程序不一样。窗口显示出来之后,程序不能立刻结束。它要持续等待用户和系统事件:
1 | 鼠标点击 |
所以 Qt 程序最后通常写:
1 | return app.exec(); |
app.exec() 会启动事件循环。程序会停在这里不断等待事件、分发事件、处理事件,直到应用退出。这样看,Qt 程序不是“一口气执行完”,而是“创建界面后进入等待和响应状态”。
信号与槽:把用户动作连接到代码
GUI 程序不能一直主动问用户“你点按钮了吗”。更自然的模式是:
1 | 先告诉 Qt:如果按钮被点击,就执行某段代码。 |
这就是信号与槽。
1 |
|
这句最关键:
1 | QObject::connect(&button, &QPushButton::clicked, []() { |
它的意思是:当 button 发出 clicked 信号时,执行后面的 lambda。
信号表示某个对象发生了一件事或状态变化,例如按钮点击、输入框文字变化、定时器超时。槽表示信号发生后要执行的函数或代码。现代 Qt 中,lambda 经常可以直接作为槽使用。
如果槽里要使用外部变量,需要捕获:
1 | QObject::connect(&button, &QPushButton::clicked, [&button]() { |
这里 [&button] 表示按引用捕获外部变量 button。按引用捕获时要确认对象在槽执行时仍然存在。
成员函数作为槽:真实项目更常见
实际项目里,界面通常会封装成自己的窗口类:
1 |
|
这里的 connect 表示:按钮点击时,调用当前窗口对象 this 的 onButtonClicked() 成员函数。
QObject 父子对象:为什么 new 了不用 delete
Qt 代码里经常看到:
1 | button = new QPushButton("Click me", this); |
如果只从普通 C++ 的 new/delete 角度看,会自然追问:为什么没有 delete button?
Qt 的答案是 QObject 父子对象机制。很多 Qt 类都继承自 QObject,可以形成父子对象树。当父对象销毁时,Qt 会自动销毁它的子对象。
例如:
1 | MainWindow |
MainWindow 销毁时,button 和 layout 会被一起释放。所以对于已经指定父对象的 Qt 对象,通常不要再手动 delete,否则可能破坏对象树管理,甚至带来重复释放风险。
需要注意的是,Qt 的父子机制只适用于 QObject 体系。普通 C++ 类不会因为写了类似关系就被 Qt 自动管理。
父对象也影响界面层级
对 QWidget 控件来说,父对象不仅影响生命周期,也常常影响界面归属。
1 | QWidget window; |
这里按钮属于窗口。如果按钮没有父窗口,它可能成为一个独立顶层窗口:
1 | QPushButton* button = new QPushButton("Click"); |
速通阶段可以先记住:在窗口类里写 new QPushButton("OK", this),通常表示“创建按钮,并交给当前窗口管理”。
布局管理器:不要手动摆坐标
Qt 中不推荐大量使用:
1 | button->move(20, 20); |
手动坐标的问题很多:窗口缩放后不自然,不同系统字体大小可能挤压控件,翻译后文字变长也容易溢出。更常规的做法是把控件交给 layout。
常见布局有:
1 | QVBoxLayout:垂直排列控件。 |
垂直布局例子:
1 |
|
复杂界面可以嵌套布局。例如外层垂直布局,上面放输入框,下面放一排按钮:
1 | QLineEdit* edit = new QLineEdit; |
布局的核心价值是把“控件如何摆放、如何随窗口变化调整”交给 Qt 处理,而不是自己手算坐标。
阶段性结论
Qt Widgets 入门可以先抓住五句话:
- Qt GUI 程序需要
QApplication和事件循环。 QWidget是最基础的窗口/控件类,创建后要show()才显示。- 信号表示对象发生事件,槽表示事件发生后要执行的代码。
QObject父子对象机制负责管理很多 Qt 对象的生命周期。- 真实界面优先使用布局管理器,不要依赖手动坐标。
理解这五件事后,再继续学习菜单、对话框、文件读写、资源文件和多窗口结构,会顺很多。


