前言
学习Qt之前要先背单词嗷
这里推荐背单词的软件和词汇书
一、Qt 简介
1.1 核心概念与功能
开发框架:Qt 是一个基于 C++ 的跨平台应用开发框架,最初专注于图形用户界面(GUI),但现已扩展为支持多领域开发。
功能扩展:除了 GUI,还提供对以下功能的支持:
多线程编程
数据库交互
图像处理与计算机视觉
音视频编解码与处理
网络通信(TCP/UDP、HTTP、WebSocket 等)
文件与系统操作
1.2开发语言支持
原生语言:C++(性能高,适用于工业级应用)。
Python 绑定:PyQt 或 Qt for Python(适合快速原型开发,学习成本较低)。
1.3 为什么选择 C++ 版本的 Qt?
性能优势
C++ 的底层控制能力适合高性能场景(如游戏客户端、嵌入式系统)。
行业应用广泛
工业软件、汽车 HMI、医疗设备等对稳定性和效率要求高的领域。
生态成熟
主流 IDE(如 Qt Creator)和工具链对 C++ 支持更完善。
1.4 Qt 的跨平台特性
核心理念:
“一次编码,多平台编译”。
支持平台:
桌面端:Windows、macOS、Linux
移动端:Android、iOS
嵌入式:ARM、嵌入式 Linux
典型应用案例:
微信(桌面端跨 Windows/macOS)
WPS Office(跨平台兼容性)
Blizzard 战网、QQ 音乐(跨平台 UI 一致性)
1.5 Qt 的其他核心优势
面向对象设计
基于信号与槽(Signals & Slots)的松耦合通信机制,提升代码可维护性。
提供 QObject 基类实现内存自动回收(通过父子对象树)。
丰富的 API 与文档
模块化设计(如 Qt Core、Qt GUI、Qt Widgets、Qt Quick)。
详尽的官方文档与社区资源(如 Qt Wiki、论坛)。
开源与商业双授权
LGPL 协议允许免费开发闭源项目(需动态链接库)。
商业授权提供额外支持与工具(如 Qt Design Studio)。
二、环境安装
本文章使用Qt5.4
下载链接:
Qt 5.4.0 安装包
三、新建项目
- 启动Qt Creator
双击桌面图标或从开始菜单启动。 - 创建新项目
菜单栏:文件(File) ➔ 新建文件或项目(New File or Project)
或点击欢迎页面的 新建项目(New Project) 按钮。 - 选择项目模板
选择 Application ➔ Qt Widgets Application
(确保使用Qt界面库,而非纯C++项目)
点击 选择(Choose…) 进入下一步。 - 设置项目名称与路径
名称(Name):输入英文项目名(不能含中文或特殊字符)
创建路径(Create in):选择纯英文路径(避免空格及中文)
勾选 设为默认项目路径(可选)
点击 下一步(Next)。 - 配置构建系统(默认)
选择构建工具:CMake 或 qmake(根据课程要求选择,默认qmake)
点击 下一步。 - 选择基类(关键步骤)
类信息(Class Information) 页面:
输入类名(如MainDialog)
基类(Base class) 下拉框选择 QDialog
(默认可能为QMainWindow,需手动更改)
取消勾选 生成表单(Generate form)(若无需UI设计文件)
点击 下一步(Next)。 - 项目管理
版本控制:根据需要选择(如None)
点击 完成(Finish) 生成项目。 - 项目结构
生成的文件比标准C++项目多出以下内容:
.pro:qmake项目配置文件
maindialog.h/maindialog.cpp:自定义对话框类
main.cpp:主程序入口
若启用UI设计,则包含.ui文件(XML格式界面布局)
尝试运行
配置构建套件(Kit)(首次使用需检查):
左下角确保选择了正确的 编译器(如桌面版Qt的MinGW/MSVC)
若报错提示未配置套件,需通过 工具 ➔ 选项 ➔ Kits 添加。
构建项目:
点击左下角 ▶ 运行 按钮(或按Ctrl+R),自动编译并运行。
首次构建会提示选择构建目录,建议保持默认(与项目同级的build-*文件夹)。
查看结果:
成功运行后会显示一个空白对话框窗口。
四、项目结构
4.1 目录结构
一个Qt项目包含两个核心目录:
工作目录 | 构建目录 |
---|---|
存储源代码和项目文件(.pro .cpp等) | 存放编译产物(可执行文件、中间文件) |
通过新建项目时手动选择确定 | 默认位于build-<项目名>-<编译器>路径 |
通过Qt Creator项目面板可查看构建目录位置 | 通过"项目 -> 构建目录"可修改存储位置 |
影子构建模式建议:
启用时(默认):保持源码目录清洁,但可能影响复杂项目编译稳定性
关闭方法:项目设置 → 取消勾选"影子构建" → 构建目录将与工作目录合并
故障排查:编译异常时可尝试关闭影子构建清理遗留文件
4.1 项目配置文件.pro
QT += core gui # 基础模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets # 版本适配
TARGET = MyApp # 生成的可执行文件名
TEMPLATE = app # 项目类型(应用程序/库等)
SOURCES += main.cpp \ # 源文件列表(使用反斜杠换行)
widget.cpp
HEADERS += widget.h # 头文件列表
FORMS += widget.ui # 界面设计文件
RESOURCES += resources.qrc # 资源文件(可选)
4.2 .user用户文件
4.2.1.user文件说明
文件作用
.user 文件(如 项目名.pro.user)由 Qt Creator 自动生成,保存用户本地环境的配置参数,包括:
构建目录路径
编译器和调试器的设置
运行参数、环境变量
界面布局个性化配置
为何需要删除
跨环境兼容性问题:他人电脑路径、工具链配置不同时,可能导致项目无法运行。
配置污染:残留的配置可能覆盖项目原有的通用设置(如 CMakeLists.txt 或 .pro 文件中的配置)。
文件命名示例
默认格式:项目名.pro.user
多平台或多次配置时可能生成多个文件(如 .pro.user.1234),需一并删除。
4.2.2 如何导入他人项目
解压缩
将项目文件解压至目标目录,建议使用 纯英文路径(避免中文、空格、特殊符号)。
删除.user文件
打开项目目录,检查是否存在 .pro.user 或类似文件。
手动删除:直接在资源管理器中删除,或在终端执行:
find . -name "*.user*" -delete # Linux/macOS
del /s *.user* # Windows(需在项目根目录运行)
检查项目路径
确保项目根目录及各级文件夹不包含中文。
常见问题:路径含中文可能导致编译失败或资源加载异常。
打开项目
双击 .pro 文件(Qt 项目文件),或在 Qt Creator 中选择 文件 → 打开项目。
注:Windows 系统默认关联 .pro 文件至 Qt Creator,双击后自动启动。
初始配置
- 选择构建套件(Kit):根据本地环境选择已安装的编译器(如 MSVC、MinGW、Clang)。
- 配置构建目录:建议使用默认路径或手动指定,避免与其他项目冲突。
- 点击 Configure Project 完成配置,随后可构建/运行项目。
4.3 dialog.h
此文件用于Dialog类的声明
#ifndef DIALOG_H // 头文件保护符,防止重复包含
#define DIALOG_H // 定义宏,表示该头文件已被包含
#include <QDialog> // 包含Qt对话框基类头文件
// 前向声明UI命名空间中的Dialog类(由Qt的UI编译器自动生成)
namespace Ui {
class Dialog;
}
// 自定义对话框类,继承自QDialog基类
// 该对话框用于展示和操作用户界面中的对话框窗口
class Dialog : public QDialog
{
Q_OBJECT // Qt宏,必须出现在所有使用信号/槽的类中,启用元对象特性(如动态类型转换)
public:
// explicit构造函数:显式构造对话框对象
// 参数parent:指向父窗口对象的指针,默认为空指针(0)
explicit Dialog(QWidget *parent = 0);
// 析构函数:释放资源
// virtual关键字确保子类析构时能正确调用析构链
~Dialog();
private:
// UI组件容器指针(组合设计模式)
// 指向由Qt Designer生成的界面元素集合
Ui::Dialog *ui; // 访问.ui文件中定义的界面元素(如按钮、文本框等)
};
#endif // DIALOG_H // 结束头文件保护
4.4 dialog.cpp
此文件会根据dialog.h声明的内容补充函数定义。
// 引入对话框类的头文件
// dialog.h 是当前对话框类对应的头文件,包含类声明
#include "dialog.h"
// ui_dialog.h 是Qt设计师生成的UI界面类头文件,包含界面元素定义
#include "ui_dialog.h"
// 构造函数实现
// parent: 父组件指针,用于管理内存布局,默认为nullptr
Dialog::Dialog(QWidget *parent) :
QDialog(parent), // 调用基类QDialog的构造函数,进行透传构造
ui(new Ui::Dialog) // 在初始化列表中创建UI类的实例对象(初始化顺序与声明顺序一致)
{
// 调用Ui::Dialog类的setupUi函数
// 此函数会创建界面所有控件,并自动连接信号槽
// this指针将当前对话框设为这些控件的父级,实现内存自动管理
ui->setupUi(this);
// 在此处可以添加界面初始化代码
// 例如设置控件默认值、初始化变量、连接自定义信号槽等
}
// 析构函数实现
Dialog::~Dialog()
{
// 释放UI界面对象占用的内存
// 遵循Qt的对象树机制:
// 1. 当父对象被删除时,会自动删除所有子对象
// 2. 此处ui是通过new单独创建的对象,需要手动释放
// 3. 通过Qt Designer生成的ui指针通常需要在析构函数中删除
delete ui; // 释放Ui::Dialog类实例
// 注意:如果类中有其他动态分配的资源,也需要在此处释放
}
4.6 main.cpp
项目的主文件,包含主函数,是程序运行的入口。
该文件通常无需改动
// 引入对话框类的头文件,包含自定义的Dialog类定义
#include "dialog.h"
// 引入Qt应用程序类的头文件,QApplication管理应用程序的控制流和主要设置
#include <QApplication>
// 程序的入口函数,与操作系统交互的接口
int main(int argc, char *argv[])
{
// 创建Qt应用程序对象a,管理应用程序的全局资源。
// argc和argv是命令行参数,Qt可能用它们初始化某些配置(如样式插件等)
QApplication a(argc, argv);
// 创建自定义对话框对象w(栈内存对象),作为程序的主窗口。
// 当w超出作用域时会自动释放内存,无需手动delete。
Dialog w;
// 调用show()方法显示窗口。窗口默认是隐藏的,必须显式调用显示。
// 此时窗口会出现在屏幕上,但程序尚未进入交互状态。
w.show();
// 进入Qt的主事件循环,开始处理用户输入、窗口事件等。
// a.exec()会阻塞在此处,直到收到退出事件(如关闭所有窗口)。
// 返回值是应用程序的退出状态码(通常0表示正常退出)。
return a.exec();
}
五、Qt 文档查阅指南
📚 三种文档查询方式
- 独立使用 Qt Assistant (推荐)
启动路径
Windows: 开始菜单 → Qt版本号 → Assistant
macOS/Linux: 安装路径中查找Assistant可执行文件
优势
完整离线文档、支持全文搜索、可收藏书签、多索引模式 - Qt Creator 内置帮助 (开发时快捷方式)
快速触发
定位光标到类/函数 → 快捷键 F1 (自动跳转对应帮助)
菜单操作
帮助 → Qt 文档 → 搜索框输入关键字
实时提示
编码时自动悬浮显示简单说明(需在选项 → 文本编辑器启用) - 在线文档查询
官方地址:Qt文档
特点: 最新版本文档、多语言支持(部分翻译)、方便分享链接
六、QDebug
调试优化工具
Qt 基于C++重构了一套高效开发框架,其中 QDebug 专为调试设计,相较于 cout 或 Python 的 print,具备以下优势:
前后台分离
前台信息面向用户(如界面提示),后台调试日志仅开发者可见,便于在不影响用户体验时输出诊断信息。
自动格式化
使用 << 流操作符时自动插入空格分隔内容,同一语句内连续输出无需手动处理格式。
多数据类型支持
可直接输出 Qt 对象(如 QString、QVector),并兼容标准 C++ 类型。
简单示例
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
// 防止头文件重复包含的预处理指令
// 当DIALOG_H未定义时执行后续代码,直到#endif
// 确保头文件在同一个编译单元中只被包含一次
#include <QDialog> // 包含Qt对话框基类头文件
#include <QDebug> // 包含Qt调试输出工具头文件
// 继承自QDialog的自定义对话框类
class Dialog : public QDialog
{
Q_OBJECT // 必须的Qt元对象系统宏,用于启用信号槽等Qt特性
public:
Dialog(QWidget *parent = 0); // 构造函数,parent参数指定父窗口部件
~Dialog(); // 析构函数
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
// 构造函数实现
// parent参数传递给基类QDialog的初始化列表
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 显式调用基类构造函数
{
// 使用Qt调试流输出调试信息
// 连续使用<<操作符将自动在元素间添加空格分隔
// 输出内容示例:"构造 函数"(中间有一个空格)
// 此行代码在对话框对象创建时执行,用于跟踪对象生命周期
qDebug() << "构造" << "函数";
}
// 析构函数实现
Dialog::~Dialog()
{
// 当对话框对象被销毁时输出信息
// 用于验证对象是否被正确释放
qDebug() << "析构函数"; // 输出内容示例:"析构函数"
}
常见问题与解决方法
Permission Denied 错误
主因: 程序已在运行或旧实例未完全退出。
请关闭正在运行的实例。
七、QWidget
7.1 核心属性(只读)
width / height
表示部件内容的宽度和高度(单位:像素),不包含边框和标题栏。
x / y
表示部件相对于父容器的坐标(若无父容器,则为屏幕坐标)。坐标系采用屏幕左上角为原点 (0,0),向右为 x 正方向,向下为 y 正方向。
7.2 几何调整方法
- 调整大小:resize(int w, int h)
功能:仅修改部件的宽度和高度,不影响位置。
示例:
widget->resize(500, 300); // 设置部件大小为 500x300 像素
- 调整位置:move(int x, int y)
功能:仅修改部件的坐标,不改变大小。
示例:
widget->move(100, 50); // 将部件移动到坐标 (100,50)
- 联合调整:setGeometry(int x, int y, int w, int h)
功能:一次性调整位置和大小,通常比单独调用 move 和 resize 更高效(减少重复计算和重绘)。
示例:
widget->setGeometry(100, 50, 500, 300); // 位置 (100,50),大小 500x300
八、添加子组件
以QPushButton(按钮)为例,说明如何在一个窗口中添加子组件
/**
* @brief QPushButton 构造函数,创建一个带有指定文本和父控件的按钮对象
*
* 该构造函数用于初始化一个 QPushButton 实例,并设置其显示文本及父控件。
* 父控件负责按钮的内存管理和布局归属。若未指定父控件(默认),
* 按钮将作为独立窗口存在,需手动管理其生命周期。
*
* @param text 按钮上显示的文本内容(支持 QString 编码格式,如中文)
* @param parent 指向父控件的指针,默认为 nullptr(无父控件)
*/
QPushButton::QPushButton(const QString &text, QWidget *parent = 0)
代码示例
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton> // 按钮类,Qt按钮控件头文件
// 定义Dialog类继承自QDialog
class Dialog : public QDialog
{
// Q_OBJECT宏,必须用于支持Qt的信号槽机制和元对象系统
Q_OBJECT
public:
// 构造函数,parent参数指定父窗口控件
Dialog(QWidget *parent = 0);
// 析构函数,用于清理资源
~Dialog();
private:
// 定义指向QPushButton的指针,用于管理按钮控件
QPushButton* btn;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
// 构造函数实现
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 调用基类构造函数初始化父类
{
// w移动到100,100
// 设置窗口在屏幕上的绝对坐标为(100, 100)
this->move(100,100);
// 更改w的大小
// 设置窗口客户区尺寸为300x300像素
resize(300,300);
// 创建堆内存按钮对象
// 在堆上创建按钮对象,指定显示文本为"下午好",父对象为当前窗口(自动管理生命周期)
btn = new QPushButton("下午好",this);
// 更改位置和大小,位置是在窗口里的相对位置
// 设置按钮相对于窗口的位置为(100,100),尺寸为150x150像素
btn->setGeometry(100,100,150,150);
}
// 析构函数实现
Dialog::~Dialog()
{
// 显式释放按钮控件内存(注意:当父对象存在时,通常不需要手动删除)
delete btn;
}
结果展示
九、 样式表
- 基本语法结构
QSS由选择器和声明块组成,支持类名、子控件和伪状态:
选择器 {
属性: 值;
属性: 值;
}
相关配色网站:
Color Palette Generator
在线颜色选择器 | RGB颜色查询对照表
示例:设置按钮基础样式
QPushButton* btn = new QPushButton("按钮", this);
btn->setStyleSheet("QPushButton { background-color: #4CAF50; color: white; }");
- 常用选择器
类选择器:QPushButton
ID选择器:QPushButton#okBtn(需设置objectName)
伪状态::hover、:pressed、:disabled
子控件:QComboBox::drop-down
示例:悬停和禁用状态
QPushButton:hover { background-color: #45a049; }
QPushButton:disabled { color: #888; }
- 常用属性
颜色:color(文字)、background-color(背景)
边框:border(粗细、样式、颜色)、border-radius(圆角)
布局:padding(内边距)、margin(外边距)
字体:font-size、font-family
示例:带圆角的输入框
QLineEdit {
border: 2px solid #4CAF50;
border-radius: 5px;
padding: 3px;
}
- 子控件与复杂组件
针对组合控件的子部件定制样式:
/* QComboBox的下拉箭头 */
QComboBox::down-arrow {
image: url(down_arrow.png);
}
/* QProgressBar的进度块 */
QProgressBar::chunk {
background-color: #05B8CC;
}
- 伪状态组合
多个状态联合应用:
/* 按钮悬停并按下时的样式 */
QPushButton:hover:pressed {
background-color: #3d8b40;
}
- 全局样式与继承
设置应用级默认样式,继承给所有子组件:
// 设置全局字体和按钮样式
qApp->setStyleSheet("QWidget { font-size: 12pt; } QPushButton { padding: 5px; }");
代码示例
dialog.h
/*
* 对话框控件定义头文件
* 该文件定义了一个带有自定义样式按钮的对话框类
*/
// 防止头文件重复包含
#ifndef DIALOG_H
#define DIALOG_H
// Qt 核心头文件
#include <QDialog>
// Qt 按钮控件头文件(已添加中文注释)
#include <QPushButton> // 按钮类
/*
* QPushButton 样式表宏定义
* 注意: 宏名称中的 STYTLE 应为 STYLE(拼写错误待修正)
* 使用 Qt 样式表语法定义按钮不同状态的视觉效果
*/
#define QPushButton_STYTLE (QString("\
/*---------------- 按钮普通状态 ----------------*/\
QPushButton\
{\
/* 使用微软雅黑字体(需确保系统安装该字体) */\
font-family:Microsoft Yahei;\
/* 字体尺寸使用印刷单位点(points),适合高分辨率屏幕 */\
font-size:20pt;\
/* 白色字体提高对比度 */\
color:white;\
/* 科技蓝背景色(RGB: 14, 150, 254) */\
background-color:rgb(14 , 150 , 254);\
/* 圆角边框设计,8像素圆角半径 */\
border-radius:8px;\
}\
/*---------------- 按钮悬停状态 ----------------*/\
QPushButton:hover\
{\
/* 悬停时使用浅蓝色(RGB: 100, 137, 255)加深交互反馈 */\
background-color:rgb(100 , 137 , 255);\
}\
/*---------------- 按钮按下状态 ----------------*/\
QPushButton:pressed\
{\
/* 按压态使用绿色(RGB: 14, 135, 10)增强操作反馈 */\
background-color:rgb(14 , 135 , 10);\
/* 文字向右下方微移3像素,模拟物理按钮按下效果 */\
padding-left:3px;\
padding-top:3px;\
}"))
/*
* Dialog 类定义
* 继承自 QDialog,实现自定义对话框
* 包含一个应用了自定义样式的按钮控件
*/
class Dialog : public QDialog
{
Q_OBJECT // Qt 元对象系统宏,支持信号槽机制
public:
Dialog(QWidget *parent = 0);
~Dialog(); // 析构函数
private:
QPushButton* btn; // 对话框中的主按钮控件指针
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
// 对话框类构造函数
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 初始化基类QDialog
{
// 设置窗口初始位置为屏幕坐标(100, 100)
this->move(100,100);
// 设置窗口客户端区域大小为300x300像素
resize(300,300);
/* 创建按钮控件并进行初始化设置 */
// 在堆内存中创建QPushButton对象,按钮文本为"下午好",父对象为当前对话框
btn = new QPushButton("下午好", this);
// 设置按钮的位置和尺寸:x=100, y=100, 宽度=150, 高度=150
// 坐标相对于父窗口客户区左上角
btn->setGeometry(100, 100, 150, 150);
// 设置按钮样式
// 可能存在的拼写注意:STYTLE应为STYLE,此处保持原有代码
btn->setStyleSheet(QPushButton_STYTLE);
}
// 对话框析构函数
Dialog::~Dialog()
{
// 释放按钮对象占用的堆内存
delete btn;
}
成果展示
十、信号槽
10.1 核心概念
信号与槽是Qt特有的松耦合通信机制,允许对象在无需知晓彼此细节的情况下进行交互。相较于传统回调函数,其优势在于:
类型安全:Qt5新语法支持编译时类型检查
多对多关系:一个信号可连接多个槽,多个信号可连接同一槽
线程安全:支持跨线程队列化调用
灵活参数:槽的参数可少于信号的参数,传递时自动忽略多余参数
10.2 必要条件
实现信号与槽需满足:
继承体系: 类必须直接或间接继承自QObject
元对象系统: 类声明中必须包含Q_OBJECT宏(位于头文件私有部分)
class MyClass : public QObject {
Q_OBJECT // 必须位于类声明的首个非注释内容位置
public:
// ...
};
10.3连接方式演进
Qt4旧式语法
connect(sender, SIGNAL(valueChanged(int)),
receiver, SLOT(updateValue(int)));
特点:使用字符串匹配,运行时解析,无编译时检查
缺陷:类型不一致或拼写错误只能在运行时发现
Qt5推荐语法
connect(sender, &SenderClass::valueChanged,
receiver, &ReceiverClass::updateValue);
优势:编译时类型检查,更高的安全性与执行效率
支持:普通成员函数、静态函数、lambda表达式
- 本文章作为守旧派使用旧式语法练习
十一、连接类型
11.1 内置信号→内置槽
这种连接方式最简单,因为信号函数和槽函数都在Qt内置了,只需要查询后连接即可。
【例子】 点击按钮,关闭窗口。
分析:
发射者对象——按钮;信号函数——点击;接收者对象——窗口;槽函数——关闭。
// 点击按钮发射的信号
void QAbstractButton::clicked() [signal]
// 关闭
bool QWidget::close() [slot]
代码示例
dialog.h
// 防止头文件被重复包含的宏定义
#ifndef DIALOG_H
#define DIALOG_H
// 包含Qt框架的对话框基类和按钮控件头文件
#include <QDialog>
#include <QPushButton>
// 自定义对话框类,继承自QDialog
class Dialog : public QDialog
{
// 启用Qt的元对象系统特性(如信号槽机制)
Q_OBJECT
public:
// 构造函数,parent参数指定父部件(默认为空)
explicit Dialog(QWidget *parent = 0);
// 析构函数,用于清理资源
~Dialog();
private:
// 私有成员:指向QPushButton的指针,用于对话框界面中的按钮控件
QPushButton* btn;
};
// 结束头文件保护宏
#endif // DIALOG_H
dialog.cpp
/*
* 对话框窗口类的实现文件
* 实现一个带有"关闭"按钮的简单对话框
*/
// 包含自定义对话框类的头文件,确保类声明和实现一致
#include "dialog.h"
// 对话框类构造函数
// parent参数指定父窗口,用于对象树内存管理
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 调用基类构造函数初始化
{
// 设置对话框窗口尺寸为300x300像素
resize(300,300);
// 在堆上创建QPushButton对象
// 参数1: 按钮显示文本为"关闭"
// 参数2: 指定父对象为当前对话框,父对象负责子对象内存管理
btn = new QPushButton("关闭", this);
// 移动按钮到窗口坐标(100,150)位置
// Qt坐标系原点(0,0)在窗口左上角
btn->move(100,150);
// 建立信号与槽连接(Qt4旧式语法)
// 参数1: 发送信号的对象(按钮)
// 参数2: 信号原型(按钮被点击时发射的clicked信号)
// 参数3: 接收信号的对象(当前对话框)
// 参数4: 槽函数原型(窗口关闭函数)
// 注意:新版本Qt推荐使用Qt5的类型安全连接语法:
// connect(btn, &QPushButton::clicked, this, &QDialog::close);
connect(btn, SIGNAL(clicked()), this, SLOT(close()));
}
// 对话框析构函数
Dialog::~Dialog()
{
}
点击关闭即可关闭窗口
11.2 自定义槽
槽函数的功能在实际开发中五花八门,Qt内置的功能有限,因此绝大多数情况下需要手动编写槽函数。
槽函数本质是一种特殊的成员函数。
【例子】 点击按钮,窗口向右下角移动并输出坐标。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
// 防止头文件被重复包含的预处理指令(Header Guard)
#include <QDialog> // 基础对话框类,用于创建GUI对话框
#include <QPushButton> // Qt按钮控件类
#include <QDebug> // Qt调试输出类(可能在实现中用于qDebug()输出)
// 自定义对话框类,继承自QDialog
class Dialog : public QDialog
{
Q_OBJECT // Qt宏,启用元对象特性(如信号槽、属性系统等)
public:
Dialog(QWidget *parent = 0); // 构造函数,parent指定父窗口部件
~Dialog(); // 析构函数,用于清理资源
private:
QPushButton* btn; // 按钮控件指针,用于管理界面中的按钮部件
private slots: // 声明私有槽函数区域(槽函数用于响应信号)
void mySlot(); // 自定义槽函数,通常与某个信号(如按钮点击)连接以触发特定操作
};
#endif // DIALOG_H
dialog.cpp
// 引入头文件
#include "dialog.h"
// Dialog类的构造函数,继承自QDialog
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 调用基类构造函数
{
// 设置对话框窗口的初始大小为300x300像素
resize(300,300);
// 创建一个按钮对象,显示文本为"移动",并将对话框设置为父对象
btn = new QPushButton("移动",this);
// 将按钮移动到对话框内的坐标(100,150)位置
btn->move(100,150);
// 连接信号与槽:当按钮被点击时,触发Dialog类的mySlot槽函数
// 使用Qt的老式信号槽语法:SIGNAL(clicked())和SLOT(mySlot())
connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}
// 自定义槽函数mySlot的实现
void Dialog::mySlot()
{
// 获取当前窗口在屏幕坐标系中的x,y坐标
int x = this->x();
int y = this->y();
// 每次点击将坐标增加10个像素,实现窗口向右下角移动的效果
x += 10;
y += 10;
// 将窗口移动到新坐标
move(x,y);
// 在调试终端输出新的坐标位置
qDebug() << "新窗口坐标:" << x << y;
}
// 析构函数:对象销毁时自动调用
Dialog::~Dialog()
{
// 手动释放btn按钮的内存
// 注意:由于btn的父对象是this(Dialog窗口),当父对象被销毁时,Qt会自动删除子对象
// 这里的显式delete可能多余,但在某些特殊情况下可以确保资源及时释放
delete btn;
}
11.3 自定义信号
这种方式主要用在后面一些特殊情况,因此本节“强行使用”。
信号函数是一种特殊的函数,只有声明没有定义,使用emit关键字发射。
【例子】 点击按钮,关闭窗口。
dialog.h
#include "dialog.h"
// Dialog类的构造函数
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 调用基类QDialog的构造函数,设置父组件
{
resize(300, 300); // 设置对话框窗口大小为300x300像素
// 创建按钮对象,设置按钮文本为"关闭",并将当前对话框设置为父组件
btn = new QPushButton("关闭", this);
btn->move(100, 150); // 将按钮移动到对话框内的坐标(100,150)位置
// 信号与槽连接:按钮的clicked()信号连接到当前对象的mySlot()槽函数
connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));
// 信号与槽连接:自定义的mySignal()信号连接到QDialog的close()槽函数,用于关闭窗口
connect(this, SIGNAL(mySignal()), this, SLOT(close()));
}
// 自定义槽函数实现
void Dialog::mySlot()
{
// 当按钮被点击时,触发此槽函数,发射自定义的mySignal()信号
emit mySignal();
}
// 析构函数
Dialog::~Dialog()
{
// 注意:此处手动删除btn可能存在问题,因为btn的父组件是当前对话框(this)
// 当父组件销毁时,会自动删除所有子组件,因此此处手动delete可能导致双重释放
// 建议:在Qt中,若组件已指定父对象,通常无需手动释放
delete btn;
}
/* 代码说明:
* 1. 点击按钮会触发以下流程:
* btn点击 -> mySlot()槽被调用 -> 发射mySignal()信号 -> 触发close()槽 -> 关闭窗口
* 2. 直接连接方式:实际开发中可简化为直接连接 btn的clicked()信号到close()槽,
* 此处通过自定义信号演示Qt信号/槽的灵活用法。
* 3. 内存管理警示:因为btn的父组件是this(Dialog对象),在Dialog析构时会自动销毁子组件,
* 析构函数中的delete btn会造成重复释放,可能导致程序崩溃。
*/
dialog.cpp
#include "dialog.h"
// Dialog类的构造函数
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 调用基类QDialog的构造函数,设置父组件
{
resize(300, 300); // 设置对话框窗口大小为300x300像素
// 创建按钮对象,设置按钮文本为"关闭",并将当前对话框设置为父组件
btn = new QPushButton("关闭", this);
btn->move(100, 150); // 将按钮移动到对话框内的坐标(100,150)位置
// 信号与槽连接:按钮的clicked()信号连接到当前对象的mySlot()槽函数
connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));
// 信号与槽连接:自定义的mySignal()信号连接到QDialog的close()槽函数,用于关闭窗口
connect(this, SIGNAL(mySignal()), this, SLOT(close()));
}
// 自定义槽函数实现
void Dialog::mySlot()
{
// 当按钮被点击时,触发此槽函数,发射自定义的mySignal()信号
emit mySignal();
}
// 析构函数
Dialog::~Dialog()
{
// 注意:此处手动删除btn可能存在问题,因为btn的父组件是当前对话框(this)
// 当父组件销毁时,会自动删除所有子组件,因此此处手动delete可能导致双重释放
// 建议:在Qt中,若组件已指定父对象,通常无需手动释放
delete btn;
}
/* 代码说明:
* 1. 点击按钮会触发以下流程:
* btn点击 -> mySlot()槽被调用 -> 发射mySignal()信号 -> 触发close()槽 -> 关闭窗口
* 2. 直接连接方式:实际开发中可简化为直接连接 btn的clicked()信号到close()槽,
* 此处通过自定义信号演示Qt信号/槽的灵活用法。
* 3. 内存管理警示:因为btn的父组件是this(Dialog对象),在Dialog析构时会自动销毁子组件,
* 析构函数中的delete btn会造成重复释放,可能导致程序崩溃。
*/
总结
Qt作为基于C++的跨平台应用开发框架,提供GUI开发、多线程、网络通信等核心功能,其面向对象设计与信号槽机制显著提升代码可维护性。文章从Qt的跨平台编译特性切入,详细解析C++版本在工业软件与嵌入式领域的技术优势,结合5.4版本演示环境配置、项目创建流程和文件结构特点,通过控件添加、QSS样式定制等案例展示界面开发技巧,并对比Qt4/Qt5信号槽语法差异。最后基于QWidget几何操作与内存管理机制,阐释Qt在构建高性能应用中的最佳实践,为开发者提供从入门到调试的完整技术路径。