Qt 5.14.2 学习记录 —— 오 信号与槽机制(2)

文章目录


1、信号与槽的参数

信号和槽可以带参数,当信号带有参数时,槽的参数必须和信号的一致,此时发送信号就可以给信号函数传递实参,那么对应的参数就会传到对应的槽函数中,这样就是信号给槽传参了。

cpp 复制代码
// widget.h

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

signals:
    void mySignal(const QString& text);

private slots:
	void handleMySignal(const QString& text);
    
    void on_pushButton_clicked();

// widget.cpp

void Widget::handleMySignal(const QString& text)
{
    this->setWindowTitle(text);
}

void Widget::on_pushButton_clicked()
{
    connect(this, &Widget::mySignal, this, &Widget::handleMySignal);

    // 连接好后用emit来发送信号
    emit mySignal("带参数的信号");
}

按照代码逻辑来看,传的参数被复用了。可以再拖过去一个按钮,也改它的槽函数。顺便把连接代码放在类中。widget.cpp中:

cpp 复制代码
#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(this, &Widget::mySignal, this, &Widget::handleMySignal);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handleMySignal(const QString& text)
{
    this->setWindowTitle(text);
}

void Widget::on_pushButton_clicked()
{
    emit mySignal("这是信号1");
}

void Widget::on_pushButton_2_clicked()
{
    emit mySignal("这是信号2");
}

运行后点击不同按钮标题就有不同变化,也就起到了复用的效果。

假如信号函数比槽函数的参数量更多,依然是可以正常运行的,反之则不行。

一个槽函数会和多个信号绑定,所以如果严格一致,那么就无法绑定很多信号。如果参数量之间不一致,槽函数的参数有多少个,就会按照信号的参数顺序来拿到信号的前几个参数。这样至少确保槽函数的每个参数都是有值的。

信号函数和槽函数的参数类型得匹配,类型要一样。

如果要让某个类能够使用信号和槽,就必须在类最开始写上Q_OBJECT宏。

2、为什么要有信号槽机制?

实际上,这个机制有点复杂,而GUI开发框架对此做得更简洁。网页中响应用户操作也是用回调函数,但是它可以很简单地写出来,比如:

cpp 复制代码
button.onclick = handle;

function handle(){

}

并不需要一个connect来做连接。

Qt这样做的原因主要是信号与槽可以做到多对多,所以就有上面的槽函数可以对应多个信号,并且记录下来各个对应关系。这样的思路和数据库类似,数据库也是有多对多,一对多,一对一的关系。

不过实际开发中,多对多也不是必需的。

3、断开并重新连接

通常断开是为了把信号和别的槽函数连接。断开用disconnec。

拖过去两个按钮,一个按钮我们自定义槽函数,另一个切换按钮修改给定的槽函数。

cpp 复制代码
// widget.h

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void handleClick();
    void handleClick2();

private slots:
    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
};

// widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handleClick()
{
    this->setWindowTitle("标题被修改");
    qDebug() << "handleClick";
}

void Widget::handleClick2()
{
    this->setWindowTitle("已切换");
    qDebug() << "handleClick2";
}

void Widget::on_pushButton_2_clicked()
{
    // 1. 断开连接
    disconnect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick);

    // 2. 重新绑定
    connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handleClick2);
}

如果不写disconnect,那么这个信号就会绑定两个槽函数,点击切换按钮后再去点击第一个按钮,那么handleClick和handleClick2都会打印出来,标题改为已切换,也就是说两个槽函数都会被执行。

4、槽函数lambda写法

lambda本质是一个匿名函数,用来作回调函数很方便。

cpp 复制代码
#include <QPushButton>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPushButton* button = new QPushButton(this);
    button->setText("按钮");
    button->move(330, 250);

    connect(button, &QPushButton::clicked, this, []() {
        qDebug() << "lambda函数被执行";
    });
}

如果要在lambda函数里使用button这个对象,就写在捕获里

cpp 复制代码
    connect(button, &QPushButton::clicked, this, [button, this]() {
        qDebug() << "lambda函数被执行";
        button->move(330, 300);
        this->move(100, 200);
    });

this的move就是把整个框都移动。要捕获所有变量就写成[=]。lambda的写法和C++的一样,=传值,&引用传递。当然得在.pro文件中写上CONFIG += c++11才行。

结束。

相关推荐
Heris9912 分钟前
2.22 c++练习【operator运算符重载、封装消息队列、封装信号灯集】
开发语言·c++
----云烟----14 分钟前
C/C++ 中 volatile 关键字详解
c语言·开发语言·c++
yuanpan33 分钟前
23种设计模式之《组合模式(Composite)》在c#中的应用及理解
开发语言·设计模式·c#·组合模式
BanLul43 分钟前
进程与线程 (三)——线程间通信
c语言·开发语言·算法
十八朵郁金香1 小时前
【JavaScript】深入理解模块化
开发语言·javascript·ecmascript
Hello.Reader1 小时前
深入理解 Rust 的 `Rc<T>`:实现多所有权的智能指针
开发语言·后端·rust
程序员阿鹏1 小时前
jdbc批量插入数据到MySQL
java·开发语言·数据库·mysql·intellij-idea
yoona10201 小时前
Rust编程语言入门教程(八)所有权 Stack vs Heap
开发语言·后端·rust·区块链·学习方法
莲动渔舟1 小时前
国产编辑器EverEdit - 在编辑器中对文本进行排序
java·开发语言·编辑器
陈无左耳、1 小时前
HarmonyOS学习第4天: DevEco Studio初体验
学习·华为·harmonyos