基础篇
第一章 QT 基础认知
1.1 什么是 QT(What)
- 定义:跨平台 C++ 应用开发框架,不仅用于 UI 设计,还包含核心功能(如事件、网络、数据库)。
- 核心特性:
- 跨平台:一套代码支持 Windows/macOS/Linux/ 嵌入式(如 ARM)/ 移动(iOS/Android);
- 面向对象:基于 QObject 对象模型;
- 丰富组件:内置数百个 UI 与功能组件;
- 高效开发:Qt Creator IDE 可视化设计 + 代码联动。
1.2 为什么用 QT(Why)
|----------|----------------------|
| 优势 | 嵌入式开发场景价值 |
| 跨平台 | 避免为不同嵌入式设备重复开发 |
| 低内存占用 | 适配嵌入式设备有限资源 |
| 支持硬件交互 | 可直接操作串口、GPIO 等嵌入式硬件 |
| 成熟社区与文档 | 问题易检索,降低学习成本 |
1.3 谁用 QT(Who)
嵌入式开发工程师(工业屏 / 智能设备 UI)、桌面应用开发者、移动应用开发者。
1.4 什么时候用 QT(When)
- 需跨平台开发时;
- 需快速实现复杂 UI(如菜单栏、表格、对话框)时;
- 嵌入式设备需可视化交互界面时。
1.5 在哪用 QT(Where)
- 嵌入式领域:工业控制屏(如 PLC 人机界面)、智能家电(如冰箱触控屏);
- 桌面领域:Windows/macOS 工具软件(如串口助手);
- 其他:医疗设备界面、车载系统 UI。
1.6 怎么用 QT(How)
核心流程:搭建环境→设计UI→编写逻辑(信号与槽)→编译调试→部署到目标设备。
1.7 学习成本(How Much)
- 技术前提:需掌握 C++ 基础(类、指针、继承);
- 工具成本:Qt Creator+Qt SDK 免费(开源版本),商业授权需付费(嵌入式项目常用开源版);
- 学习周期:2-4 周可掌握基础开发。
习题 1:QT 基础认知判断
- 下列关于 QT 的描述正确的是( )
A. QT 仅用于开发 Windows 桌面应用
B. QT 基于 C++,支持跨平台开发
C. 嵌入式设备无法使用 QT
D. QT 的核心功能仅包含 UI 设计
解析 1
- 答案:B
- 分析:A 错(QT 跨平台,支持嵌入式 / 移动);C 错(QT 是嵌入式 UI 开发常用框架);D 错(QT 还包含网络、数据库等核心功能)。
第二章 QT 开发环境搭建
建议观看B站迅为电子的视频教程。
第三章 QT 核心概念(层级结构:概念→子知识点)
3.1 核心模块(QT 功能分类)
|-------------|------------------------|----------------|
| 模块名 | 功能描述 | 嵌入式常用场景 |
| Qt Core | 核心功能(对象树、事件、定时器) | 内存管理、硬件定时器控制 |
| Qt Widgets | 桌面 / 嵌入式 UI 组件(窗口、按钮) | 开发工业屏交互界面 |
| Qt GUI | 图形渲染(绘图、字体、颜色) | 绘制自定义控件(如仪表盘) |
| Qt Network | 网络通信(TCP/UDP/HTTP) | 嵌入式设备联网传输数据 |
| Qt Sql | 数据库操作(SQLite/MySQL) | 存储设备运行日志 |
3.2 QObject 对象模型(QT 所有对象的基类)
核心作用:
- 支持信号与槽(对象间通信);
- 对象树管理(自动回收内存);
- 事件处理(如鼠标点击、键盘输入)。
对象树机制:
- 创建 QObject 子类对象时,可指定 "父对象"(通过构造函数参数);
- 父对象销毁时,会自动销毁所有子对象(避免内存泄漏);
- 示例:QPushButton *btn = new QPushButton(this);(this为父对象,窗口销毁时 btn 自动销毁)。
3.3 元对象系统(MOC)
作用:处理 QT 特有的语法(如 Q_OBJECT 宏、信号与槽),将其转换为标准 C++ 代码;
关键组件:
- Q_OBJECT 宏:需在 QObject 子类中声明,否则 MOC 无法生成信号与槽代码;
- 元对象编译器(MOC):Qt Creator 自动调用,生成moc_xxx.cpp文件。
习题 3:QObject 对象树实操
编写代码创建 3 个 QObject 子类对象(A、B、C),指定 A 为 B 的父对象,B 为 C 的父对象,在析构函数中打印 "对象 X 销毁",观察 delete A 后的输出顺序,说明原因。
解析 3
cpp
#include <QObject>
#include <QDebug>
#include <QCoreApplication>
class MyObject : public QObject {
Q_OBJECT
public:
~MyObject() {
qDebug() << "对象" << objectName() << "销毁";
}
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
MyObject *A = new MyObject;
A->setObjectName("A");
MyObject *B = new MyObject(A); // A为B的父对象
B->setObjectName("B");
MyObject *C = new MyObject(B); // B为C的父对象
C->setObjectName("C");
delete A; // 销毁父对象A
return a.exec();
}
- 输出顺序:对象A销毁 → 对象B销毁 → 对象C销毁(或 C→B→A,取决于对象树遍历顺序);
- 原因:QObject 对象树机制,父对象销毁时会遍历所有子对象并销毁,避免内存泄漏。
第四章 QT 基础 UI 组件(模块结构:按组件类型拆解)
4.1 窗口组件(UI 容器)
|--------------|-----------------|------------------|
| 组件名 | 特点 | 用途 |
| QMainWindow | 含菜单栏、工具栏、状态栏 | 主应用窗口(如文本编辑器) |
| QWidget | 基础空白窗口 | 自定义控件容器 |
| QDialog | 弹窗窗口(模态 / 非模态) | 弹出 "确认""设置" 对话框 |
示例:创建 QMainWindow 窗口(附字符模拟界面)
cpp
#include <QApplication>
#include <QMainWindow>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QMainWindow w;
w.setWindowTitle("嵌入式UI示例");
w.resize(800, 600);
w.show();
return a.exec();
}
字符模拟界面:
cpp
+--------------------------------------------------------------+
| 文件 编辑 视图 帮助 | 菜单栏(高25像素,默认灰色背景)
+--------------------------------------------------------------+
| 嵌入式UI示例 [最小化] [最大化] [关闭] | 标题栏(高30像素)
+--------------------------------------------------------------+
| |
| |
| | 中心空白区域(800×545像素)
| |
| |
+--------------------------------------------------------------+
| 状态栏(默认隐藏,需手动启用) | 状态栏(高20像素)
+--------------------------------------------------------------+
界面说明:
- QMainWindow 默认包含菜单栏和标题栏,状态栏需通过statusBar()->show()手动启用;
- 中心区域为空白,需通过setCentralWidget设置组件容器后才能添加 UI 元素。
4.2 交互组件(用户操作)
|--------------|-------------|---------------------------------------------------|
| 组件名 | 功能 | 示例代码 |
| QPushButton | 按钮(点击触发事件) | QPushButton *btn = new QPushButton("点击我", &w); |
| QLineEdit | 单行输入框 | QLineEdit *edit = new QLineEdit("请输入内容", &w); |
| QLabel | 显示文本 / 图片 | QLabel *label = new QLabel("欢迎使用QT", &w); |
4.3 布局管理(组件排版)
问题:直接用setGeometry(x,y,w,h)固定组件位置,窗口缩放时组件会错位;
解决方案:使用布局管理器自动排版,常用布局:
- QVBoxLayout:垂直布局(组件上下排列);
- QHBoxLayout:水平布局(组件左右排列);
- QGridLayout:网格布局(组件按行列排列)。
示例:垂直布局(QVBoxLayout)(附字符模拟界面)
cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QWidget w;
w.setWindowTitle("布局示例");
// 创建组件
QPushButton *btn1 = new QPushButton("按钮1");
QPushButton *btn2 = new QPushButton("按钮2");
QLineEdit *edit = new QLineEdit("请输入内容");
// 创建垂直布局
QVBoxLayout *layout = new QVBoxLayout(&w);
layout->addWidget(edit); // 添加输入框
layout->addWidget(btn1); // 添加按钮1
layout->addWidget(btn2); // 添加按钮2
w.show();
return a.exec();
}
字符模拟界面:
cpp
+----------------------------------------+
| 布局示例 [_] [□] [×] | 标题栏(宽300像素,高30像素)
+----------------------------------------+
| |
| [请输入内容] | QLineEdit(高30像素,左右距10像素,灰色提示文本)
| |
| [ 按钮1 ] | QPushButton(高35像素,宽280像素,文本居中)
| |
| [ 按钮2 ] | QPushButton(与按钮1同尺寸,间距15像素)
| |
+----------------------------------------+
界面说明:
- 窗口总尺寸约 300×200 像素,组件垂直居中排列,上下组件间距 15 像素;
- 拖动窗口边缘缩放时,输入框和按钮会同步拉伸 / 收缩(宽度随窗口变化,高度不变),保持布局整齐。
习题 4:UI 组件与布局实操
- 创建一个 QMainWindow 窗口,要求:
- 菜单栏添加 "控制" 菜单,包含 "开灯""关灯" 两个动作;
- 中心部件用 QVBoxLayout,包含 1 个 QLabel(显示 "灯状态:关闭")和 1 个 QPushButton(文本 "切换灯状态");
- 窗口大小固定为 400x300。
解析 4
代码示例:
cpp
#include <QApplication>
#include <QMainWindow>
#include <QMenu>
#include <QAction>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QMainWindow w;
w.setWindowTitle("灯控UI");
w.setFixedSize(400, 300); // 固定窗口大小
// 1. 菜单栏
QMenu *controlMenu = w.menuBar()->addMenu("控制");
QAction *lightOn = controlMenu->addAction("开灯");
QAction *lightOff = controlMenu->addAction("关灯");
// 2. 中心部件(QWidget+QVBoxLayout)
QWidget *centralWidget = new QWidget(&w);
w.setCentralWidget(centralWidget);
QVBoxLayout *layout = new QVBoxLayout(centralWidget);
// 3. 添加组件
QLabel *statusLabel = new QLabel("灯状态:关闭");
QPushButton *toggleBtn = new QPushButton("切换灯状态");
layout->addWidget(statusLabel);
layout->addWidget(toggleBtn);
w.show();
return a.exec();
}
字符模拟界面:
cpp
+----------------------------------------+
| 文件 编辑 控制 帮助 | 菜单栏(高25像素,"控制"菜单可点击下拉)
+----------------------------------------+
| 灯控UI [_] [□] [×] | 标题栏(高30像素,窗口固定大小不可缩放)
+----------------------------------------+
| |
| 灯状态:关闭 | QLabel(文本黑色,14号字体,居中)
| |
| | 垂直间距30像素
| [ 切换灯状态 ] | QPushButton(宽120像素,高35像素,文本居中)
| |
| |
+----------------------------------------+
界面说明:
- 点击菜单栏 "控制",下拉显示 "开灯""关灯" 选项(黑色文本,hover 时背景变为浅灰色);
- 中心区域标签和按钮垂直居中,窗口背景为白色,组件无额外样式(默认系统风格)。
第五章 QT 信号与槽
5.1 核心原理(对象间通信机制)
- 信号(Signal):对象状态变化时发出的 "通知"(如按钮点击clicked()、文本变化textChanged());
- 槽(Slot):接收信号并执行的函数(如窗口关闭close()、更新文本setText());
- 连接(Connect):通过connect函数将 "信号" 与 "槽" 绑定,信号触发时自动执行槽函数。
5.2 语法规则(推荐 Qt 5 + 新语法)
cpp
connect(发送者对象, &发送者类::信号名, 接收者对象, &接收者类::槽函数名);
参数说明:
- 发送者:发出信号的对象(如 QPushButton);
- 信号:发送者的信号(如&QPushButton::clicked);
- 接收者:执行槽函数的对象(如 QLabel);
- 槽函数:接收者的函数(如&QLabel::setText)。
5.3 常用信号与槽示例
|--------------|-----------------------|--------------|-------------------|---------------|
| 发送者组件 | 信号名 | 接收者组件 | 槽函数名 | 功能描述 |
| QPushButton | clicked() | QMainWindow | close() | 点击按钮关闭窗口 |
| QLineEdit | textChanged(QString) | QLabel | setText(QString) | 输入框文本变化时更新标签 |
| QAction | triggered() | QWidget | show() | 点击菜单动作显示窗口 |
5.4 自定义信号与槽
步骤:
- 新建 QObject 子类,添加Q_OBJECT宏;
- 用signals:关键字声明信号(仅声明,无实现);
- 用public slots:声明槽函数(需实现);
- 用emit关键字发送信号。
习题 5:信号与槽实操
基于习题 4 的灯控 UI,补充信号与槽逻辑:
- 点击 "切换灯状态" 按钮,触发toggleLight槽函数,更新 QLabel 显示状态;
- 点击菜单栏 "开灯",直接设置灯为开启状态;点击 "关灯",直接设置为关闭状态。
解析 5
完整代码:
cpp
#include <QApplication>
#include <QMainWindow>
#include <QMenu>
#include <QAction>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QObject>
class LightControl : public QObject {
Q_OBJECT
public:
LightControl(QLabel *label) : m_label(label) {}
signals:
void lightStatusChanged(QString status);
public slots:
void toggleLight() {
m_isOn = !m_isOn;
emit lightStatusChanged("灯状态:" + (m_isOn ? "开启" : "关闭"));
}
void turnOnLight() { // 开灯槽函数
m_isOn = true;
emit lightStatusChanged("灯状态:开启");
}
void turnOffLight() { // 关灯槽函数
m_isOn = false;
emit lightStatusChanged("灯状态:关闭");
}
private:
bool m_isOn = false;
QLabel *m_label;
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QMainWindow w;
w.setWindowTitle("灯控UI");
w.setFixedSize(400, 300);
// 1. 菜单栏
QMenu *controlMenu = w.menuBar()->addMenu("控制");
QAction *lightOn = controlMenu->addAction("开灯");
QAction *lightOff = controlMenu->addAction("关灯");
// 2. 中心部件
QWidget *centralWidget = new QWidget(&w);
w.setCentralWidget(centralWidget);
QVBoxLayout *layout = new QVBoxLayout(centralWidget);
QLabel *statusLabel = new QLabel("灯状态:关闭");
QPushButton *toggleBtn = new QPushButton("切换灯状态");
layout->addWidget(statusLabel);
layout->addWidget(toggleBtn);
// 3. 信号与槽连接
LightControl *lightCtrl = new LightControl(statusLabel);
QObject::connect(toggleBtn, &QPushButton::clicked, lightCtrl, &LightControl::toggleLight);
QObject::connect(lightOn, &QAction::triggered, lightCtrl, &LightControl::turnOnLight);
QObject::connect(lightOff, &QAction::triggered, lightCtrl, &LightControl::turnOffLight);
QObject::connect(lightCtrl, &LightControl::lightStatusChanged, statusLabel, &QLabel::setText);
w.show();
return a.exec();
}
#include "main.moc"
字符模拟交互界面:
- 初始状态
cpp
+----------------------------------------+
| 文件 编辑 控制 帮助 |
+----------------------------------------+
| 灯控UI [_] [□] [×] |
+----------------------------------------+
| |
| 灯状态:关闭 | 初始标签文本
| |
| [ 切换灯状态 ] | 按钮默认样式
| |
+----------------------------------------+
- 点击 "切换灯状态" 按钮后
cpp
+----------------------------------------+
| 文件 编辑 控制 帮助 |
+----------------------------------------+
| 灯控UI [_] [□] [×] |
+----------------------------------------+
| |
| 灯状态:开启 | 标签文本实时更新
| |
| [ 切换灯状态 ] | 按钮样式不变
| |
+----------------------------------------+
- 点击 "控制→开灯" 后
cpp
+----------------------------------------+
| 文件 编辑 控制▼ 帮助 | "控制"菜单下拉
| 开灯 | 选中"开灯"选项(背景浅灰)
| 关灯 |
+----------------------------------------+
| 灯控UI [_] [□] [×] |
+----------------------------------------+
| |
| 灯状态:开启 | 标签直接更新为"开启"
| |
| [ 切换灯状态 ] |
| |
+----------------------------------------+
交互说明:
- 所有操作无延迟,标签文本实时更新;
- 点击 "控制→关灯" 时,标签会立即变为 "灯状态:关闭",逻辑与 "开灯" 相反。
第六章 QT 事件处理(层级结构:事件类型→处理方式)
6.1 什么是 QT 事件
定义:系统或用户触发的行为(如鼠标点击、键盘输入、窗口缩放),QT 通过 "事件队列" 管理事件。
常用事件类型:
- QMouseEvent:鼠标事件(点击、移动、滚轮);
- QKeyEvent:键盘事件(按键按下、松开);
- QResizeEvent:窗口大小变化事件。
6.2 事件处理方式(重点:重写事件函数)
- 核心方法:重写 QWidget 的虚函数(如mousePressEvent、keyPressEvent),实现自定义逻辑。
- 规则:重写后需调用父类事件函数(如QWidget::mousePressEvent(event)),否则会屏蔽默认行为(如窗口无法拖动)。
示例:鼠标点击显示坐标(附字符模拟界面)
cpp
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QMouseEvent>
class MouseWidget : public QWidget {
Q_OBJECT
public:
MouseWidget(QWidget *parent = nullptr) : QWidget(parent) {
QVBoxLayout *layout = new QVBoxLayout(this);
m_label = new QLabel("点击窗口查看鼠标坐标");
layout->addWidget(m_label);
}
protected:
// 重写鼠标按下事件
void mousePressEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) { // 仅处理左键点击
QString coord = QString("鼠标左键坐标:(%1, %2)").arg(event->x()).arg(event->y());
m_label->setText(coord);
}
QWidget::mousePressEvent(event); // 保留父类默认行为
}
private:
QLabel *m_label;
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MouseWidget w;
w.setWindowTitle("鼠标事件示例");
w.resize(400, 300);
w.show();
return a.exec();
}
#include "main.moc"
字符模拟界面:
- 初始状态
cpp
+----------------------------------------+
| 鼠标事件示例 [_] [□] [×] | 标题栏(宽400像素)
+----------------------------------------+
| |
| 点击窗口查看鼠标坐标 | QLabel(文本居中,14号字体)
| |
| |
| |
+----------------------------------------+
- 鼠标左键点击窗口中心后
cpp
+----------------------------------------+
| 鼠标事件示例 [_] [□] [×] |
+----------------------------------------+
| |
| 鼠标左键坐标:(200, 150) | 标签文本更新为坐标(中心位置X=200,Y=150)
| |
| |
| |
+----------------------------------------+
界面说明:
- 点击窗口左上角(靠近边缘),标签显示 "鼠标左键坐标:(5, 5)";
- 右键点击窗口无任何变化,拖动标题栏移动窗口时,坐标文本保持不变。
习题 6:事件处理实操
基于上述示例,补充键盘事件处理:
- 按下 "Ctrl+S" 键,在 QLabel 上显示 "快捷键 Ctrl+S 按下";
- 按下 "ESC" 键,关闭窗口。
解析 6
- 补充代码(MouseWidget 类中):
cpp
protected:
// 新增:重写键盘按下事件
void keyPressEvent(QKeyEvent *event) override {
// 判断Ctrl+S(event->modifiers()获取组合键)
if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_S) {
m_label->setText("快捷键Ctrl+S按下");
}
// 判断ESC键
else if (event->key() == Qt::Key_Escape) {
close(); // 关闭窗口
}
QWidget::keyPressEvent(event); // 调用父类
}
字符模拟交互效果:
- 按下 "Ctrl+S" 后
cpp
+----------------------------------------+
| 鼠标事件示例 [_] [□] [×] |
+----------------------------------------+
| |
| 快捷键Ctrl+S按下 | 标签文本替换为快捷键提示
| |
| |
| |
+----------------------------------------+
- 按下 "ESC" 后
- 窗口直接关闭,程序退出,无任何弹窗提示;
- 若当前标签显示坐标或快捷键文本,按下 "ESC" 后直接退出,不保留状态。
交互说明:
- 仅当窗口处于激活状态(标题栏为蓝色,Windows 系统)时,键盘事件才会被触发;
- 按下其他键(如 "A""1""空格"),标签无变化,保持当前文本。
QT开发知识点梳理
后续更新