文章目录
- 信号与槽
-
- 什么是信号与槽函数
- 信号与槽的连接
- [创建 ui 项目](#创建 ui 项目)
- 连接重载的信号与槽
- 连接多个信号与槽函数
信号与槽
什么是信号与槽函数
信号与槽(Signals and Slots)是一种用于对象间通信的机制,广泛应用于图形用户界面(GUI)编程,尤其在Qt框架中。其核心思想是通过松耦合的方式实现对象间的交互,无需显式调用对方的方法。
信号(Signal)是对象在特定事件发生时发出的通知。例如,按钮被点击时发出clicked信号,窗口关闭时发出closed信号。信号本身不包含具体的实现逻辑,仅作为事件触发的标志。
- 信号由Qt的
moc(元对象编译器)自动生成。 - 信号可以携带参数,用于传递事件相关的数据。
槽(Slot)是普通的成员函数,用于响应信号。当信号被触发时,与之连接的槽函数会被自动调用。槽函数可以执行任何逻辑,例如更新界面、处理数据等。
- 槽可以是任何类的成员函数,只需声明为
public slots或使用Q_SLOTS宏。 - 槽可以接受信号传递的参数,并与之匹配。
信号与槽的连接
通过QObject::connect函数建立信号与槽的关联。语法如下:
cpp
QObject::connect(发送者, 信号, 接收者, 槽);
特性与优势
- 松耦合:发送者和接收者无需知道对方的具体实现,仅需通过信号与槽连接。
- 类型安全:Qt在编译时检查信号与槽的参数类型是否匹配。
- 多对多支持:一个信号可以连接多个槽,一个槽也可以响应多个信号。
- 跨线程通信 :通过
Qt::QueuedConnection方式实现线程安全的异步调用。
注意事项
- 信号与槽的参数数量和类型必须兼容,但允许槽的参数比信号少(忽略多余的参数)。
- 使用
disconnect可断开已建立的连接。 - 在Qt5中推荐使用新式语法(函数指针),而非旧式的
SIGNAL()和SLOT()宏。
1. 字符串方式 SIGNAL / SLOT(Qt4):
cpp
connect(sender, SIGNAL(signalName(parameters)), receiver, SLOT(slotName(parameters)));
2. 函数地址方式(Qt5):
cpp
connect(sender, &SenderClass::signalName, receiver, &ReceiverClass::slotName);
3. Lambda表达式 :
可直接在connect中编写逻辑:
cpp
connect(button, &QPushButton::clicked, this, []() {
qDebug() << "Lambda slot called";
});
4. UI设计师界面-转到槽

5. UI设计师界面-信号槽编辑器

创建 ui 项目
勾选:Generate form

双击 widget.ui,进入编辑模式


进行信号与槽的连接


- widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget)
{
ui->setupUi(this);
// 1. 使用 SIGNAL/SLOT 方式连接信号与槽
connect(ui->pushButton_1, SIGNAL(clicked(bool)), this, SLOT(showMaximized()));
// 2. 使用函数地址 方式连接信号与槽
connect(ui->pushButton_2, &QPushButton::clicked, this, &Widget::showNormal);
// 5. 使用 Lambda表达式做槽函数
connect(ui->pushButton_5, &QPushButton::clicked, this, [&](){
this->setWindowTitle("连接信号槽的5种方式");
});
}
Widget::~Widget(){ delete ui; }
void Widget::on_pushButton_3_clicked(){
// 3. 使用设计师界面-转到槽 方式连接信号与槽
this->showMinimized();
}
连接重载的信号与槽

cpp
#if 0
// 1. 创建发送者、接收者对象
Sender sender;
Receiver receiver;
// 2. 建立信号与槽的链接 Qt4
QObject::connect(&sender, SIGNAL(click()), &receiver, SLOT(execute()));
QObject::connect(&sender, SIGNAL(click(QString)), &receiver, SLOT(execute(QString)));
// 3. 发送信号 emit 可省略
emit sender.click();
emit sender.click("overload");
return a.exec(); // 让应用程序对象进入消息循环,应用程序就阻塞在这里
#endif
#if 1
// 1. 创建发送者、接收者对象
Sender sender;
Receiver receiver;
// 2. 建立信号与槽的链接 Qt5
void (Sender::*pClick)() = &Sender::click;
void (Receiver::*pExecute)() = &Receiver::execute;
QObject::connect(&sender, pClick, &receiver, pExecute);
void (Sender::*pClick2)(QString) = &Sender::click;
void (Receiver::*pExecute2)(QString) = &Receiver::execute;
QObject::connect(&sender, pClick2, &receiver, pExecute2);
// 3. 发送信号 emit 可省略
emit sender.click();
emit sender.click("overload");
#endif
连接多个信号与槽函数
一个信号连接多个槽函数
多个信号连接一个槽函数

cpp
#if 1
// 一个信号连接多个槽函数
Sender sender1,sender2;
Receiver receiver1, receiver2;
void (Sender::*click1)() = &Sender::click;
void (Receiver::*execute1)() = &Receiver::execute;
void (Receiver::*execute1_2)() = &Receiver::execute;
QObject::connect(&sender1, click1, &receiver1, execute1);
QObject::connect(&sender1, click1, &receiver1, execute1_2);
emit sender1.click();
// -------------------------------------------------------
// 多个信号连接一个槽函数
void (Sender::*click2)(QString) = &Sender::click;
void (Sender::*click2_2)(QString) = &Sender::click;
void (Receiver::*execute2)(QString) = &Receiver::execute;
QObject::connect(&sender1, click2, &receiver2, execute2);
QObject::connect(&sender2, click2_2, &receiver2, execute2);
emit sender1.click("AAA");
emit sender2.click("BBB");
#endif