目录
- 前言
- 一、信号槽
- 1.1 传参
- 1.2 Qt信号与槽的对应关系
- 1.2.1一对多关系
- 1.2.2 多对一关系
- 二、Designer
- 三、Layout 布局
- 3.1 基础用法
- 3.2 打破布局
- 3.3 贴合窗口
- 3.4 伸展器(Spacer)
- 3.5 嵌套布局
- 四、ui指针
- 五、QWidget
- 六、QLabel 标签使用指南
- 总结
前言
本篇文章,我们将继续探讨Qt的学习,解锁现代应用开发的无限可能。上一篇文章,我们已经对信号槽进行了初步的探讨,本篇文章我们将会书接上文,继续来探讨信号槽的使用。
一、信号槽
首先补充上篇文章的两个小知识点
需要注意的是,调用connect函数之前,发射者与接收者对象必须均创建完成。
把connect的函数名称改为disconnect,参数不变可以断开信号槽连接。另外,发射者或接收者对象销毁后之前连接的信号槽也会自动断开。
disconnect(sender, SIGNAL(...), receiver, SLOT(...));
1.1 传参
为了理解传参,我们先来做一个例子
【例子】 点击按钮,按钮显示点击的次数。
●text : QString
按钮显示的文字
// int → QString
QString QString::number(int n) [static]
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
// 包含必要的头文件
#include <QDialog> // Qt对话框基类
#include <QPushButton> // Qt按钮控件
// 自定义对话框类,继承自QDialog
class Dialog : public QDialog
{
Q_OBJECT // Qt宏,启用信号槽机制
public:
// 构造函数
// @param parent 父窗口指针,默认为nullptr
Dialog(QWidget *parent = 0);
// 析构函数
~Dialog();
private:
QPushButton* btn; // 按钮控件指针
int count; // 记录按钮被点击的次数
private slots:
// 按钮点击的槽函数
void btnClickedSlot();
};
#endif // DIALOG_H
dialog.cpp
// 包含对话框类的头文件
#include "dialog.h"
// 对话框类的构造函数
Dialog::Dialog(QWidget *parent)
: QDialog(parent), count(0) // 使用构造初始化列表初始化父类和计数器count
{
// 设置对话框窗口大小为300x300像素
resize(300, 300);
// 创建一个显示"0"的按钮,并指定父对象为当前对话框
btn = new QPushButton("0", this);
// 将按钮移动到窗口中央位置
// 计算方式:窗口宽度/2 - 按钮宽度/2,窗口高度/2 - 按钮高度/2
btn->move(300/2 - btn->width()/2, 300/2 - btn->height()/2);
// 连接按钮的clicked信号到本类的btnClickedSlot槽函数
connect(btn, SIGNAL(clicked()),
this, SLOT(btnClickedSlot()));
}
// 按钮点击的槽函数实现
void Dialog::btnClickedSlot()
{
// 计数器自增1
count++;
// 将整型计数器转换为QString类型
QString text = QString::number(count);
// 更新按钮上显示的文本为当前计数值
btn->setText(text);
}
// 对话框类的析构函数
Dialog::~Dialog()
{
// 释放按钮对象的内存
delete btn;
}
下面为了讲解信号槽传参,强行多增加一个信号槽的理解,本质上信号槽传参是为了解决后期不同对象之间的传参问题。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
// 自定义对话框类,继承自QDialog
class Dialog : public QDialog
{
Q_OBJECT // 启用Qt的元对象系统(信号槽机制等)
public:
Dialog(QWidget *parent = 0); // 构造函数,parent参数指定父窗口
~Dialog(); // 析构函数
private:
QPushButton* btn; // 按钮指针
int count; // 记录按钮被点击的次数
private slots:
// 槽函数声明
void btnClickedSlot(); // 处理按钮点击事件的槽函数
void countSlot(int); // 接收int类型参数的槽函数
signals:
// 信号声明
void countSignal(int); // 自定义信号,携带一个int类型参数
};
#endif // DIALOG_H
dialog.cpp
// 包含对话框类的头文件
#include "dialog.h"
/**
* @brief Dialog类的构造函数
* @param parent 父窗口指针,默认为nullptr
*/
Dialog::Dialog(QWidget *parent)
: QDialog(parent), count(0) // 使用构造初始化列表初始化父类和计数器count
{
// 设置对话框窗口大小为300x300像素
resize(300, 300);
// 创建一个显示"0"的按钮,并指定父对象为当前对话框
btn = new QPushButton("0", this);
// 将按钮移动到窗口中央位置
// 计算方式:窗口宽度/2 - 按钮宽度/2,窗口高度/2 - 按钮高度/2
btn->move(300/2 - btn->width()/2, 300/2 - btn->height()/2);
// 连接按钮的clicked信号到btnClickedSlot槽函数
// 当按钮被点击时,会触发btnClickedSlot函数
connect(btn, SIGNAL(clicked()),
this, SLOT(btnClickedSlot()));
// 连接自定义信号countSignal到countSlot槽函数
// 这是一个自连接,当countSignal信号发射时,会触发countSlot函数
connect(this, SIGNAL(countSignal(int)),
this, SLOT(countSlot(int)));
}
/**
* @brief 按钮点击的槽函数
* 当按钮被点击时,发射带参数的自定义信号
*/
void Dialog::btnClickedSlot()
{
// 先递增count,然后发射countSignal信号,携带count值作为参数
emit countSignal(++count);
}
/**
* @brief 处理计数信号的槽函数
* @param count 接收到的计数值
* 将计数值显示在按钮上
*/
void Dialog::countSlot(int count)
{
// 将整型count转换为QString类型
QString text = QString::number(count);
// 设置按钮文本为当前计数值
btn->setText(text);
}
/**
* @brief Dialog类的析构函数
* 释放动态分配的按钮对象
*/
Dialog::~Dialog()
{
// 删除按钮对象,释放内存
delete btn;
}
1.2 Qt信号与槽的对应关系
1.2.1一对多关系
概念
同一个信号可以同时连接到多个槽
槽函数也是成员函数,可以直接调用
优化技巧: 可以把多个槽函数放在一个槽函数中调用,将一对多优化为一对一结构
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog> // 包含QDialog头文件,用于创建对话框窗口
#include <QPushButton> // 包含QPushButton头文件,用于创建按钮控件
#include <QDebug> // 包含QDebug头文件,用于调试输出
// Dialog类继承自QDialog,表示一个对话框窗口
class Dialog : public QDialog
{
Q_OBJECT // 宏定义,启用Qt的元对象系统(信号槽机制等)
public:
Dialog(QWidget *parent = 0); // 构造函数,parent参数指定父窗口
~Dialog(); // 析构函数
private:
QPushButton* btn; // 私有成员变量:按钮1
QPushButton* btn2; // 私有成员变量:按钮2
private slots:
void mySlot1(); // 私有槽函数1(用于响应信号)
void mySlot2(); // 私有槽函数2
void mySlot3(); // 私有槽函数3
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
// 对话框类的构造函数
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 调用父类QDialog的构造函数
{
resize(300,300); // 设置对话框大小为300x300像素
// 创建"一对多"按钮并设置位置
btn = new QPushButton("一对多",this);
btn->move(100,100);
// 创建"一对一"按钮并设置位置
btn2 = new QPushButton("一对一",this);
btn2->move(100,150);
// 信号与槽连接:一对多示例
// 将btn的clicked()信号同时连接到mySlot1()和mySlot2()两个槽函数
connect(btn,SIGNAL(clicked()),
this,SLOT(mySlot1()));
connect(btn,SIGNAL(clicked()),
this,SLOT(mySlot2()));
// 信号与槽连接:一对一示例
// 将btn2的clicked()信号连接到mySlot3()槽函数
connect(btn2,SIGNAL(clicked()),
this,SLOT(mySlot3()));
}
// 槽函数1:输出"A"
void Dialog::mySlot1()
{
qDebug() << "A";
}
// 槽函数2:输出"B"
void Dialog::mySlot2()
{
qDebug() << "B";
}
// 槽函数3:调用mySlot1和mySlot2
void Dialog::mySlot3()
{
// 直接调用mySlot1和mySlot2
mySlot1();
mySlot2();
}
// 析构函数:释放按钮对象
Dialog::~Dialog()
{
delete btn; // 释放"一对多"按钮
delete btn2; // 释放"一对一"按钮
}
1.2.2 多对一关系
概念
多个信号可以同时连接到一个槽
可以使用QObject::sender()函数判断当前是哪个发射者触发的槽函数
该函数返回发射者对象的地址(protected成员函数)
// 可以返回发射者对象的地址
QObject * QObject::sender() const [protected]
示例代码
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog> // 包含QDialog头文件,用于创建对话框窗口
#include <QPushButton> // 包含QPushButton头文件,用于创建按钮控件
#include <QDebug> // 包含QDebug头文件,用于调试输出
// Dialog类继承自QDialog,表示一个对话框窗口
class Dialog : public QDialog
{
Q_OBJECT // 必须的宏,用于支持Qt的信号和槽机制
public:
Dialog(QWidget *parent = 0); // 构造函数,parent参数指定父窗口
~Dialog(); // 析构函数
private:
QPushButton* btn; // 私有成员变量:按钮1
QPushButton* btn2; // 私有成员变量:按钮2
private slots:
void mySlot(); // 私有槽函数,用于处理按钮点击等信号
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
// 对话框类的构造函数
Dialog::Dialog(QWidget *parent)
: QDialog(parent) // 调用父类QDialog的构造函数
{
resize(300,300); // 设置对话框窗口大小为300x300像素
// 创建第一个按钮,显示文本为"多对一",父对象为当前对话框
btn = new QPushButton("多对一",this);
btn->move(100,100); // 将按钮移动到(100,100)位置
// 创建第二个按钮,显示文本为"多对一",父对象为当前对话框
btn2 = new QPushButton("多对一",this);
btn2->move(100,150); // 将按钮移动到(100,150)位置
// 多对一信号槽连接
// 将btn的clicked()信号连接到当前对象的mySlot()槽
connect(btn,SIGNAL(clicked()),
this,SLOT(mySlot()));
// 将btn2的clicked()信号连接到当前对象的mySlot()槽
connect(btn2,SIGNAL(clicked()),
this,SLOT(mySlot()));
}
// 自定义槽函数
void Dialog::mySlot()
{
// 通过sender()判断是哪个按钮触发的信号
if(sender() == btn) // 如果是btn按钮
{
qDebug() << "随便输出个什么A"; // 输出调试信息A
}
else if(sender() == btn2) // 如果是btn2按钮
{
qDebug() << "随便输出个什么B"; // 输出调试信息B
}
}
// 对话框类的析构函数
Dialog::~Dialog()
{
delete btn; // 释放btn按钮的内存
delete btn2; // 释放btn2按钮的内存
}
二、Designer
定义
Qt Designer 是 Qt 框架自带的可视化界面设计工具,用于快速创建 GUI 界面。
核心功能
通过拖拽组件设计界面,自动生成 ui 文件(XML 格式)。
与 Qt Creator 深度集成,双击 .ui 文件即可启动 Designer。
与代码的关系
Designer 的所有操作均可通过 C++ 代码实现,二者功能等价,但C++效率更高。
生成的 ui 文件会被编译为对应的 C++ 头文件(如 ui_xxx.h),供程序调用。
Designer 界面功能分布
组件工具箱:包含按钮、文本框等可拖拽控件。
属性编辑器:调整选中组件的属性(如尺寸、文本)。
信号/槽编辑器:可视化配置组件的事件响应。
布局工具:快速对齐和排列组件。
使用流程示例
- 在 Qt Creator 中创建项目,添加 .ui 文件。
- 双击 .ui 文件启动 Designer,拖拽组件设计界面。
- 保存后,Qt 自动生成 XML 代码,编译时转换为 C++ 代码。
- 在业务逻辑中通过 ui->组件名 访问界面元素。
-
三、Layout 布局
3.1 基础用法
定义: 布局是一个透明的容器,内部组件按预设规则自动排列。
主要类型:
垂直布局:组件垂直排列(纵向)。
水平布局:组件水平排列(横向)。
两者除方向外,其他属性基本一致。
常用属性:
间距(Spacing)、对齐方式(Alignment)、边距(Padding)等。
3.2 打破布局
作用: 移除外层布局但保留内部组件。
操作步骤:
选中目标布局。
点击工具栏的 “打破布局” 按钮。
注意: 直接删除布局会连带删除内部组件,需谨慎操作。
3.3 贴合窗口
作用:使最外层布局自适应窗口大小变化。
操作步骤:
选中窗口(或顶层布局)。
点击工具栏的 “贴合窗口” 按钮。
原理:在窗口内嵌套一个自动伸缩的布局。
取消方式:与打破布局相同(选中后点击“打破布局”)。
3.4 伸展器(Spacer)
功能: 在布局中填充空白区域,调整组件间距。
应用场景:
实现组件靠左/右/顶部/底部对齐。
动态分配剩余空间。
3.5 嵌套布局
用途:通过多层布局嵌套实现复杂界面设计。
关键点:
内层布局整体被视为外层布局的一个子组件。
可混合使用垂直、水平布局及伸展器。
四、ui指针
五、QWidget
QWidget 是 Qt 框架中所有用户界面组件的基类,提供了基础的属性和功能,其派生类(如按钮、窗口、标签等)会继承这些特性。以下是其常用属性和功能的整理:
六、QLabel 标签使用指南
基本特性
用途:仅用于文字和图片信息展示,不可交互操作。
图片资源管理规范
开发步骤:
准备图片
选择分辨率/大小适中的图片
命名要求:纯英文,不含中文字符
存放位置:项目工作目录
创建资源文件
右键项目 → “Add New File”
选择文件类型 → 命名资源文件 → 完成创建
管理资源文件
右键资源文件 → “Open in Editor”
首次使用需设置虚拟路径前缀
添加图片到资源文件中
使用资源
Designer中需先点击资源按钮
支持C++代码和Designer两种使用方式
代码操作图片
核心函数:
静态图片处理
// 构造函数(虚拟路径参数)
QPixmap::QPixmap(const QString &fileName)
// 图片缩放
// width: 目标宽度 | height: 目标高度
// aspectRatioMode: 缩放模式(默认忽略比例)
// transformMode: 插值方法(默认快速变换)
QPixmap QPixmap::scaled(int width, int height,
Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio,
Qt::TransformationMode transformMode = Qt::FastTransformation) const
动态图片处理
// 动图构造函数(必须堆内存分配,参数为虚拟路径)
QMovie::QMovie(const QString &fileName)
// 开始播放
void QMovie::start() [slot]
代码示例
QLabel 代码压缩包
总结
本文全面解析了Qt框架中的信号槽机制与UI设计核心知识,首先详细讲解了信号槽的连接与断开、参数传递以及一对多/多对一的对应关系实现,通过计数器案例演示了信号传参的实际应用;接着系统介绍了Qt Designer可视化设计工具的功能布局、使用流程以及与代码的对应关系;然后深入剖析了布局管理的各类技巧,包括基础布局、打破布局、贴合窗口、伸展器使用和嵌套布局等实用方法;最后讲解了ui指针的访问方式和QWidget/QLabel组件的核心功能,特别提供了图片资源管理规范和动静态图片处理的代码示例,为开发者提供了从原理到实践的完整Qt开发指南。