信号与槽概述:
在 Qt 中,用户和控件的每次交互过程称为一个事件
- 比如 “用户点击按钮” 是一个事件, “用户关闭窗口” 也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出 “按钮被点击” 的信号,用户关闭窗口会发出 “窗口被关闭” 的信号。
Qt 中的所有控件都具有接收信号的能力,一个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作
- 例如,按钮所在的窗口接收到 “按钮被点击” 的信号后,会做出 “关闭自己” 的响应动作;再比如输入框自己接收到 “输入框被点击” 的信号后,会做出 “显示闪烁的光标,等待用户输入数据” 的响应动作。在 Qt 中,对信号做出的响应动作就称之为槽。
信号和槽是 Qt 特有的消息传输机制,它能将相互独立的控件关联起来。比如, “按钮”和 “窗口” 本身是两个独立的控件,点击 “按钮” 并不会对 “窗口” 造成任何影响。通过信号和槽机制,可以将 “按钮” 和 “窗口” 关联起来,实现 “点击按钮会使窗口关闭” 的效果。

信号和槽:
- 系统提供的信号和槽–直接使用的信号和槽
- 自定义信号和槽–提供了方式可以自己 DIY 信号、槽
系统自带的信号与槽与connect:
使用 Qt 助手查找当前控件支持的系统信号和槽。
在 Qt 中,QObject 类提供了一个静态成员函数 connect(),该函数专门用来关联指定的信号函数和槽函数。
1
2
3
4
5
6
7QMetaObject::Connection QObject::connect(
const QObject *sender, // 发送信号的对象
const char *signal, // 信号的签名
const QObject *receiver, // 接收信号的对象
const char *method, // 槽函数的签名
Qt::ConnectionType type = Qt::AutoConnection // 连接类型
);- sender 发送者 信号的发送者
- signal 信号 具体发送的信号
- receiver 接收者 事情发生之后需要做的事情的执行者
- method 槽函数 接收者得到信号之后做的事情(信号、槽)
- type 类型(可选) 信号的触发类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Widget::Widget(QWidget *parent) : QWidget(parent)
{
setWindowTitle("Qt Demo");//设置窗口名称
resize(QSize(800, 500)); //设置窗口尺寸
MyButton1 = new QPushButton(this); //在堆区实例化一个按键,并将地址给类的一个属性
MyButton1MyButton1->setText("点击关闭窗口"); //修改按键名称
MyButton1->resize(QSize(500, 300)); //修改按键尺寸
MyButton1->move(QPoint(150, 100));//把按钮放在父窗口的 (150,100) 位置
//Qt 4 写法的 connect
connect(MyButton1,SIGNAL(clicked()),this,SLOT(close()));
//Qt 5 写法的 connect
connect(MyButton1,&QPushButton::clicked,this,&Widget::close);
}
自定义信号和槽:
- 自定义信号:
- 在头文件中需要使用 signals 关键字声明
- 返回值类型必须是 void
- 可以有参数,但参数不能有默认值
- 不需要实现,只需声明即可
- 使用关键字 emit 触发信号
- 可以重载
- 自定义槽:
- 在头文件中需要使用 slots 关键字声明
- 需要声明和实现
- 可以有参数,可以有默认值
- 返回值类型可以是任意类型
- 可以重载
- 注意:信号和槽没有特定配对关系:可以一个信号连接多个槽,也可以一个槽函数被多个信号连接
信号链接信号:
信号也可以直接连接信号。
语法:使用connect函数
Qt4 语法:
1
2
3
4
5
6connect(
senderObject, // 发送信号的对象指针
SIGNAL(senderSignal()), // 发送的信号(必须用 SIGNAL() 宏包裹)
receiverObject, // 接收信号的对象指针
SIGNAL(receiverSignal()) // 触发的目标信号(必须用 SIGNAL() 宏包裹)
);Qt5 语法:不支持,想实现信号连接信号,可以通过中间槽函数转发信号
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Widget::Widget(QWidget *parent) : QWidget(parent)
{
setWindowTitle("Qt Demo"); //设置窗口名称
resize(QSize(800, 500)); //设置窗口尺寸
pButtonLog = new QPushButton(this);
pButtonLog->setText("输出 log"); //修改按键名称
pButtonLog->resize(QSize(100, 60)); //修改按键尺寸
pButtonLog->move(QPoint(150, 100));
pButtonThree = new QPushButton(this);
pButtonThree->setText("Three"); //修改按键名称
pButtonThree->resize(QSize(100, 60)); //修改按键尺寸
pButtonThree->move(QPoint(550, 100));
//信号连接信号
connect(pButtonLog,SIGNAL(clicked()),this,SIGNAL(sgSignal1()));
connect(pButtonThree,SIGNAL(clicked()),this,SIGNAL(sgSignal2()));
//信号连接槽函数
connect(this,SIGNAL(sgSignal1()),this,SLOT(vWidgetSlotSignal1()));
connect(this,SIGNAL(sgSignal2()),this,SLOT(vWidgetSlotSignal2()));
}
Widget::~Widget()
{
delete pButtonLog;
}
void Widget::vWidgetSlotSignal1(void)
{
qDebug() << "我是信号 1 触发的槽函数 1";
}
void Widget::vWidgetSlotSignal2(void)
{
qDebug() << "我是信号 2 触发的槽函数 2";
}
信号和槽的传参:
信号和槽连接时, 形参列表必须一一对应(信号发生时,会将参数给对应的槽函数)
信号和槽函数支持重载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
QPushButton *pButtonLog;
QLineEdit *Input;
signals:
void sgSignal_GetEditLineText(QString &Text);
public slots:
void vWidgetSlot_Button(void);
void vWidgetSlot_Log(QString &Text);
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Widget::Widget(QWidget *parent) : QWidget(parent)
{
setWindowTitle("Qt Demo"); //设置窗口名称
resize(QSize(800, 500)); //设置窗口尺寸
pButtonLog = new QPushButton(this);
pButtonLog->setText("clicked"); //修改按键名称
pButtonLog->resize(QSize(100, 60)); //修改按键尺寸
pButtonLog->move(QPoint(150, 100));
Input = new QLineEdit(this);
Input->setText("Input");
Input->resize(QSize(500, 30));
Input->move(QPoint(150, 35));
//信号和槽函数的形参必须一致
connect(pButtonLog,SIGNAL(clicked()),this,SLOT(vWidgetSlot_Button()));
connect(this,SIGNAL(sgSignal_GetEditLineText(QString &)),this,SLOT(vWidgetSlot_Log(QString &)));
}
Widget::~Widget()
{
delete pButtonLog;
}
void Widget::vWidgetSlot_Button(void)
{
QString temp;temp = Input->text();
emit sgSignal_GetEditLineText(temp);
}
void Widget::vWidgetSlot_Log(QString &Text)
{
qDebug() << "你输入的内容为: " << Text;
}
Lambda表达式:
Lambda 表达式是 C++11 引入的新特性,允许在代码中直接定义匿名函数。
Lambda 的组成部分包括捕获列表、参数列表、可变规格、返回类型和函数体。
1
2
3
4
5
6
7
8只支持 Qt5 写法
[capture](parameters) mutable->return-type{
statement
}
[捕获列表](参数列表) mutable(可选) 异常属性(可选) -> 返回类型(可选) {
// 函数体
}捕获列表:
[]标识一个 Lambda 的开始,这部分必须存在,不能省


[=]:以值的方式捕获所有外部变量
[&]:以引用的方式捕获所有外部变量
[this]:捕获当前类的 this 指针
[a, &b]:混合捕获方式
参数列表:
- ()操作符:重载函数参数
- 当()操作符,没有参数时,这部分可以省略。
- 有参数时,可以通过按值(如: (a,b))和按引用(如: (&a,&b))两种方式进行传递。
可变规格:(mutable)
- mutable 声明,这部分可以省略。
- 按值传递函数对象参数时,加上 mutable 修饰符后,可以修改按值传递进来的拷贝。
返回类型:
- 表示的是返回值类型,标识函数返回值的类型,当返回值是void,或者函数体中只有一处 return的地方(此时编译器可以自动推断出返回值类型)时, 这部分可以省略。
函数体:
- {},标识函数的实现,这部分不能省略,但是函数体可以为空。