前言
很多新手学习 Qt 习惯直接复制一长串完整代码,运行成功却看不懂每一行作用。 本文换一种学习方式:迭代式开发
- 版本 1:最简程序,先把窗口跑起来,弄懂 Qt 程序生命周期。
- 版本迭代:逐个增加交互、封装类、搭建界面、优化排版、美化样式。
- 每一次迭代都会引出新知识点,同时对比旧方案的缺陷,理解为什么需要新方案。
一、前置基础认知
1. Qt Creator 初次启动弹窗处理
首次打开软件会弹出两个提示框:
- Crash Reporting(崩溃报告) :收集软件崩溃日志,直接点击
Do Not Show Again(不再显示)。 - Take a UI Tour?(界面导览) :软件操作引导,新手可选择跳过,点击
Do Not Show Again。
2. Qt 核心应用类区分
| 类 | 适用场景 | 核心限制 |
|---|---|---|
QCoreApplication |
控制台后台程序 | 不能使用任何 GUI 窗口、按钮控件 |
QApplication |
图形界面 GUI 程序 | 支持窗口、控件、鼠标键盘交互,本文使用 |
3. qmake 工程构建流程
我们编写.pro工程文件 → 通过qmake工具自动生成Makefile → make 工具编译生成可执行程序。
日常开发不需要手动修改 Makefile,交由工具自动生成。
//基础.pro模板
QT += core gui widgets
TARGET = QtLoginDemo
TEMPLATE = app
SOURCES += main.cpp
二、从空白窗口到精致交互
版本1:最小可用 Qt GUI 程序
目标:写出最简代码,弹出窗口,弄懂 Qt 程序运行基础框架。
cpp
#include <QPushButton>
#include <QApplication>
int main(int argc, char *argv[])
{
// 1. 创建唯一GUI应用实例
QApplication a(argc, argv);
// 2. 创建按钮控件,控件独立创建时可以直接作为顶层窗口
QPushButton btn("测试窗口");
// 3. 设置窗口基础属性
btn.setWindowTitle("第一个Qt程序");
btn.setFixedSize(400, 300);
// 4. 显示窗口
btn.show();
// 5. 启动事件循环,监听界面操作
return a.exec();
}
核心知识点
QApplication a(argc, argv):一个 GUI 程序有且只能有一个实例。show():控件创建后默认隐藏,必须调用才能渲染显示。a.exec():开启事件循环。程序运行到此不会立刻退出,持续监听鼠标、窗口操作;
✅ 实验验证:删除
show()看不到窗口;删除a.exec()窗口一闪而过。
运行效果:一个带文字按钮的独立窗口。

版本2:新增交互,信号槽与消息对话框
需求升级:点击按钮,弹出确认框,选择确认后关闭窗口。 新增知识点:信号与槽、connect 连接、Lambda 表达式、QMessageBox 弹窗
cpp
#include <QPushButton>
#include <QApplication>
#include <QObject>
#include <QMessageBox>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton btn("点我退出");
btn.setWindowTitle("第一个Qt程序");
btn.setFixedSize(400, 300);
// 信号槽绑定:发送者 -> 信号 -> 执行逻辑
QObject::connect(&btn, &QPushButton::clicked, [&]{
// 问答弹窗
auto ret = QMessageBox::question(nullptr, "确认操作", "是否真的退出程序?");
if(ret == QMessageBox::Yes)
{
btn.close();
}
});
btn.show();
return a.exec();
}
知识点梳理
- 信号:
&QPushButton::clicked,按钮被点击时自动发出的事件。 QObject::connect(发送者, 信号, 处理函数),搭建事件桥梁。[&]Lambda 引用捕获:可以直接访问外部局部变量 btn。QMessageBox::question()弹出确认对话框,通过返回值判断用户操作。
运行测试:点击按钮弹出弹窗,选择【是】关闭窗口,选择【否】窗口保持打开。

版本3:代码封装,自定义窗口类
当前代码存在问题
所有界面代码全部写在 main.cpp 中,界面复杂时代码臃肿、难以维护。 解决方案:封装自定义窗口类 LoginWidget。

新建 loginwidget.h
cpp
#ifndef LOGINWIDGET_H
#define LOGINWIDGET_H
#include <QWidget>
class LoginWidget : public QWidget
{
Q_OBJECT // 重要宏:启用元对象系统,支持信号槽
public:
explicit LoginWidget(QWidget *parent = nullptr);
};
#endif // LOGINWIDGET_H
新建 loginwidget.cpp
cpp
#include "loginwidget.h"
LoginWidget::LoginWidget(QWidget *parent)
: QWidget(parent)
{
setWindowTitle("登录窗口");
setFixedSize(400, 320);
}
改造 main.cpp,main 只负责启动程序
cpp
#include <QApplication>
#include "loginwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LoginWidget w;
w.show();
return a.exec();
}
核心知识点
Q_OBJECT:只要类需要使用信号槽,必须添加。QWidget *parent:父对象参数,Qt 对象树机制,自动管理内存。- 职责分离:main 负责程序启动,所有界面搭建逻辑放在自定义窗口构造函数。
运行效果:空白登录窗口,为后续搭建表单控件做准备。

版本4:搭建登录控件 + 绝对定位布局
需求:在窗口上放置标签、输入框、登录按钮,实现登录页面雏形。 新增知识点:基础控件、setGeometry() 绝对定位
cpp
#include "loginwidget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
LoginWidget::LoginWidget(QWidget *parent)
: QWidget(parent)
{
setWindowTitle("登录窗口");
setFixedSize(400, 320);
// 账户标签
QLabel *labUser = new QLabel("账户:", this);
labUser->setGeometry(40, 40, 60, 30);
// 账户输入框
QLineEdit *editUser = new QLineEdit(this);
editUser->setGeometry(110, 40, 220, 30);
// 密码标签
QLabel *labPwd = new QLabel("口令:", this);
labPwd->setGeometry(40, 90, 60, 30);
// 密码输入框
QLineEdit *editPwd = new QLineEdit(this);
editPwd->setGeometry(110, 90, 220, 30);
// 登录按钮
QPushButton *btnLogin = new QPushButton("登录", this);
btnLogin->setGeometry(240, 140, 90, 35);
}
知识点梳理
控件->setGeometry(x, y, width, height) x:距离窗口左上角横向坐标,y:纵向坐标;width/height:控件宽高。
致命缺陷: 坐标全部写死!如果取消setFixedSize允许窗口缩放,拉大窗口后,控件位置不会跟随自适应,界面直接错乱。

结论:正式项目禁止大量使用绝对定位,引出布局管理器。
版本5:布局管理器重构界面
新增知识点:Qt 四大布局、布局嵌套、QSpacerItem 弹簧 四大布局回顾:
QVBoxLayout:垂直布局,自上而下排列QHBoxLayout:水平布局,自左向右排列QFormLayout:表单布局,适合【标签 + 输入框】表单QGridLayout:网格布局,行列表格形式
使用布局嵌套重构登录界面代码:
cpp
#include "loginwidget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QSpacerItem>
LoginWidget::LoginWidget(QWidget *parent)
: QWidget(parent)
{
setWindowTitle("登录窗口");
setFixedSize(400, 320);
// 顶层垂直布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QFormLayout *formLayout = new QFormLayout();
// 第一行:账户
QHBoxLayout *line1 = new QHBoxLayout();
line1->addWidget(new QLabel("账 户"));
line1->addWidget(new QLineEdit());
formLayout->addRow(line1);
// 第二行:口令
QHBoxLayout *line2 = new QHBoxLayout();
line2->addWidget(new QLabel("口 令"));
QLineEdit *pwdEdit = new QLineEdit();
// 输入时明文,失去焦点隐藏密码
pwdEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
line2->addWidget(pwdEdit);
formLayout->addRow(line2);
// 第三行:弹簧 + 登录按钮
QHBoxLayout *line3 = new QHBoxLayout();
QSpacerItem *space = new QSpacerItem(200, 50);
line3->addItem(space);
line3->addWidget(new QPushButton("登录"));
formLayout->addRow(line3);
mainLayout->addLayout(formLayout);
mainLayout->setAlignment(Qt::AlignCenter);
}
核心知识点
- 布局可以互相嵌套,实现复杂界面。
QSpacerItem空白弹簧:填充空白区域,挤压控件实现对齐。- 所有控件交给布局管理后,窗口缩放时控件自动适配位置。
setEchoMode控制输入框密码显示模式。

版本6:引入 QSS 样式美化界面
当前界面控件样式默认原生,观感简陋,引入 QSS 美化。 新增知识点:Qt 样式表、原始字符串 R""、伪状态、样式优先级
最终完整代码:
cpp
#include "loginwidget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QSpacerItem>
LoginWidget::LoginWidget(QWidget *parent)
: QWidget(parent)
{
setWindowTitle("登录窗口");
setFixedSize(400, 320);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QFormLayout *formLayout = new QFormLayout();
QHBoxLayout *line1 = new QHBoxLayout();
line1->addWidget(new QLabel("账 户"));
line1->addWidget(new QLineEdit());
formLayout->addRow(line1);
QHBoxLayout *line2 = new QHBoxLayout();
line2->addWidget(new QLabel("口 令"));
QLineEdit *pwdEdit = new QLineEdit();
pwdEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
// 单个控件局部样式
pwdEdit->setStyleSheet("color: blue;");
line2->addWidget(pwdEdit);
formLayout->addRow(line2);
QHBoxLayout *line3 = new QHBoxLayout();
QSpacerItem *space = new QSpacerItem(200, 50);
line3->addItem(space);
line3->addWidget(new QPushButton("登录"));
formLayout->addRow(line3);
mainLayout->addLayout(formLayout);
mainLayout->setAlignment(Qt::AlignCenter);
// 全局QSS样式
QString qss=R"(
*{
font-size: 14px;
}
QLineEdit{
font-size: 14px;
padding: 5px;
margin: 5px;
border: 1px solid lightgray;
border-radius: 10px;
}
QLineEdit:focus{
border: 1px solid red;
}
QPushButton{
padding: 20px 30px;
background-color: lightblue;
color: white;
}
QPushButton:hover{
background-color: rgb(0,0,200);
}
QPushButton:pressed{
background-color: green;
}
QLabel{
color: green;
}
)";
this->setStyleSheet(qss);
}
QSS 核心知识点
R"(文本)":C++ 原始字符串,书写多行样式无需转义。- 伪状态:
:focus:输入框获取光标焦点
:hover:鼠标悬浮控件上方
:pressed:鼠标按下控件
- 样式优先级:控件单独 setStyleSheet > 父窗口全局样式。
- 常用属性:
border边框、border-radius圆角、padding内边距、background-color背景色。

三、全文知识点汇总
1. Qt GUI 程序生命周期
创建QApplication → 创建窗口控件 → show()显示 → a.exec()启动事件循环监听交互。
2. 信号与槽基础
QObject::connect实现事件绑定,Lambda 表达式可以充当槽函数。
3. 界面两种排版方案
- 绝对定位
setGeometry:简单、无法自适应,仅用于临时原型。 - 四大布局管理器:支持自适应,支持嵌套,项目标准方案。
4. 内存管理
Qt 父子对象机制:父对象销毁时,自动释放所有子控件,一般无需手动 delete。
5. QSS 样式表
借鉴 CSS 语法美化控件,支持交互伪状态,区分全局样式与局部控件样式。
四、拓展练习任务
- 在登录界面增加【记住密码】复选框
QCheckBox。 - 使用
QGridLayout网格布局重新改造登录页面。 - 给下拉框
QComboBox编写 QSS 圆角样式。