Qt-02:信号与槽

文章目录

信号与槽

什么是信号与槽函数

信号与槽(Signals and Slots)是一种用于对象间通信的机制,广泛应用于图形用户界面(GUI)编程,尤其在Qt框架中。其核心思想是通过松耦合的方式实现对象间的交互,无需显式调用对方的方法。

信号(Signal)是对象在特定事件发生时发出的通知。例如,按钮被点击时发出clicked信号,窗口关闭时发出closed信号。信号本身不包含具体的实现逻辑,仅作为事件触发的标志。

  • 信号由Qt的moc(元对象编译器)自动生成。
  • 信号可以携带参数,用于传递事件相关的数据。

槽(Slot)是普通的成员函数,用于响应信号。当信号被触发时,与之连接的槽函数会被自动调用。槽函数可以执行任何逻辑,例如更新界面、处理数据等。

  • 槽可以是任何类的成员函数,只需声明为public slots或使用Q_SLOTS宏。
  • 槽可以接受信号传递的参数,并与之匹配。

信号与槽的连接

通过QObject::connect函数建立信号与槽的关联。语法如下:

cpp 复制代码
QObject::connect(发送者, 信号, 接收者, 槽);

特性与优势

  1. 松耦合:发送者和接收者无需知道对方的具体实现,仅需通过信号与槽连接。
  2. 类型安全:Qt在编译时检查信号与槽的参数类型是否匹配。
  3. 多对多支持:一个信号可以连接多个槽,一个槽也可以响应多个信号。
  4. 跨线程通信 :通过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
相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript