信号槽 是 Qt 框架中一种用于对象间通信的机制。它通过让一个对象发出信号,另一个对象连接到这个信号的槽上来实现通信。信号槽机制是 Qt 的核心特性之一,提供了一种灵活且类型安全的方式来处理事件和数据传递。
QT中,信号由三部分组成:
槽 本身就是一个成员函数,负责对QT中产生的信号进行处理。
在编写代码时,槽函数的编写等同于类的成员函数。
举例
connect(pushButton, &QPushButton::clicked, this, &MainWindow::close)
即 Qt框架 中内置的信号槽:
Qt框架中,存在一些标准信号(Standard Signals)和标准槽(Standard Slots)的已定义信号和槽函数。这些标准信号和槽提供了一些常见的功能,可以在不同的Qt对象之间进行连接。
我们尝试写一个关闭窗口按钮:
举例
我们将使用的标准信号 以及 槽函数:
// 单击按钮后发出的信号
[signal] void QAbstractButton::clicked(bool checked = false)
// 关闭窗口的槽函数
[slot] bool QWidget::close();
我们需要在mainWindow.ui中插入一个QPushButton类(不要忘记更改objectName)
随后通过 connect函数 将该功能实现出来:
// 单击按钮关闭窗口
connect(ui->closeBtn, &QPushButton::clicked, this, &MainWindow::close);
在上面的例子中:
信号(Signal):&QPushButton::clicked
。这里的信号是QPushButton类的clicked信号。当用户点击按钮时,QPushButton对象会发出(emit)一个clicked信号。
槽(Slot):&MainWindow::close
。这里的槽是MainWindow类的close成员函数。槽可以是任何普通的成员函数,它被设计为响应特定信号的函数。
当QT提供的标准信号槽无法满足需求时,我们可以设计所需的信号与槽的功能,最后通过connect连接以实现功能。
当进行自定义信号槽时,需要遵循以下规则:
// 在头文件派生类的时候,首先如下面的写法引入Q_OBJECT宏:
class MyMainWindow : public QWidget
{
Q_OBJECT
// ... ...
}
自定义槽函数有两种写法:
法一
一种是当我们使用代码创建控件时,自定义槽函数后手动连接以及实现。
随后我们在widget.cpp中手动进行创建按钮以及连接信号的操作。
法二
我们通过图形化界面创建控件,并利用Qt Creator的功能自动连接。
且此时,我们只需要实现 on_pushButton_clicked() 函数,不需要进行connect就可以实现按钮的功能。
原因如下:
以下是一些自定义信号时的要求 和 注意事项:
void
类型(直接不写返回值就行)signals 关键字
进行声明, 使用方法类似于public等emit
,表示发射
举例
我们首先在头文件中定义信号
再用connect将自定义信号与槽连接起来、可以直接在构造函数中发送信号,也可以通过其他函数发送信号,我们这里通过按钮按下的槽函数发送信号。
信号和槽都可以带有参数、自然也有函数重载,两者之间满足规则:
信号和槽的参数类型需一致,且信号的参数个数不能少于槽(可以多于)。
解耦合
在传统的编程模式中,一个对象A直接调用另一个对象B的函数,形成强耦合关系。如果对象B的函数接口发生变化,那么对象A也需要相应地修改。这种直接依赖关系使得代码难以维护和扩展。信号槽机制通过信号和槽的连接,实现了对象间的间接通信,降低了对象之间的耦合度。
易于扩展和维护
由于信号和槽减少了对象间的直接依赖,当系统需要新增功能或者修改现有功能时,往往只需要添加或修改相关的信号和槽,而不需要对其他组件进行大幅度修改。这大大提高了代码的可维护性和可扩展性。
支持异步通信
在传统的同步调用中,调用方必须等待被调用方处理完成后才能继续执行,这在某些情况下会导致程序的响应性不佳。信号槽机制支持异步通信,即发送信号后,发送方可以继续其它操作,而不需要等待接收方处理完毕。这对于提高程序的响应性和性能尤为重要。
Qt中可以使用connect连接信号与槽、同时也可以使用disconnect 断开某个信号与槽的连接
disconnect()函数有几种重载形式,可以根据需要选择使用。
由于一般不用disconnect 断开连接,下面进行简单举例:
示例1:断开特定信号和槽
假设有一个按钮(QPushButton)和一个标签(QLabel),当按钮被点击时,标签的文本会改变。如果在某个时刻想要停止这种行为,可以使用disconnect()断开它们之间的连接:
QPushButton *button = new QPushButton("Click me");
QLabel *label = new QLabel("Hello");
// 连接信号和槽
QObject::connect(button, &QPushButton::clicked, [label]() {
label->setText("Button Clicked!");
});
// 假设在某个条件下,我们需要断开上面建立的连接
QObject::disconnect(button, &QPushButton::clicked, nullptr, nullptr);
这里,disconnect()的调用断开了button的clicked信号与所有槽之间的连接。
示例2:断开所有与对象相关的连接
如果你想断开一个对象的所有信号与槽的连接,可以简单地传递该对象作为参数给disconnect():
// 断开与button相关的所有信号和槽的连接
QObject::disconnect(button);
这将断开button发出的所有信号与任何槽之间的连接,同时也断开任何信号到button槽的连接。
示例3:断开特定的信号和特定的槽
如果你只想断开一个特定信号与一个特定槽之间的连接,可以这样做:
// 假设有一个自定义槽函数
void customSlot();
// 连接信号和槽
QObject::connect(button, &QPushButton::clicked, this, &MyClass::customSlot);
// 在某个条件下,只断开这个特定的信号和槽的连接
QObject::disconnect(button, &QPushButton::clicked, this, &MyClass::customSlot);
这里,只有button的clicked信号与MyClass的customSlot槽之间的连接被断开。
示例4:使用返回值断开连接
connect()函数返回一个QMetaObject::Connection对象,可以用来在稍后断开连接:
QMetaObject::Connection conn = QObject::connect(button, &QPushButton::clicked, []() {
qDebug() << "Button clicked!";
});
// 断开连接
QObject::disconnect(conn);
这种方式允许对特定的连接进行更精确的控制。
使用disconnect()可以灵活地管理信号和槽之间的连接状态,根据应用程序的需要动态调整其行为。
这里是关于lamda表达式的一篇文章:
【C++11】lambda表达式 的定义、性质和用法
在Qt 5及以上版本中,connect()
函数支持使用lambda表达式作为槽函数。这使得在连接信号和槽时可以直接在参数中编写逻辑处理代码,而不需要定义额外的槽函数。这种方式可以让代码更加紧凑和灵活,特别是当槽函数只在一个地方使用且逻辑简单时。
下面是一个使用lambda表达式作为槽函数的基本示例:
QPushButton *button = new QPushButton("Click me");
QObject::connect(button, &QPushButton::clicked, []() {
qDebug() << "Button was clicked!";
});
在该例中,当按钮被点击时,会执行lambda表达式内的代码,即打印一条消息到调试控制台。
Lambda表达式可以捕获上下文中的变量,以便在表达式内部使用。例如,假设我们想在按钮点击时改变一个标签(QLabel)的文本:
QPushButton *button = new QPushButton("Change Label");
QLabel *label = new QLabel("Original Text");
QObject::connect(button, &QPushButton::clicked, [label]() {
label->setText("Text after click");
});
这里,lambda表达式通过捕获
label
指针,可以在按钮被点击时修改标签的文本。
我们知道:Lambda表达式的捕获列表允许以不同的方式捕获变量,例如按值捕获(拷贝)或按引用捕获。使用=
捕获所有局部变量的副本,使用&
按引用捕获所有局部变量。
int count = 0;
QPushButton *button = new QPushButton("Increase Count");
QObject::connect(button, &QPushButton::clicked, [=]() mutable {
qDebug() << "Count:" << ++count;
});
mutable
关键字。但是,这里的count
变量实际上是按值捕获的副本,外部的count
变量不会被修改。为了确保外部变量也被修改,应该按引用捕获:int count = 0;
QPushButton *button = new QPushButton("Increase Count");
QObject::connect(button, &QPushButton::clicked, [&]() {
qDebug() << "Count:" << ++count;
});