三、信号与槽
  8caZn4LUURFU 2023年11月13日 22 0


1. 信号槽的定义

信号函数和槽函数是Qt在C++的基础上新增的功能,功能是实现对象之间的通信。
实现信号槽需要有两个先决条件:

  • 通信的对象必须是从QObject派生出来的
    QObject是Qt所有类的基类。
  • 类中要有Q_OBJECT

2. 信号槽的使用

2.1 函数原型

最常用且最基础的信号槽连接函数如下所示:
// 参数1:发送者,信号槽触发的来源的对象
// 参数2:信号函数,发送者的触发动作,使用SIGNAL()包裹
// 参数3:接收者,信号槽触发后执行动作的对象
// 参数4:槽函数,接收者执行的动作,使用SLOT()包裹
QObject::connect(const QObject * sender, 
				    const char * signal, 
				    const QObject * receiver, 
				    const char * method) [static]

按照不同的情况,分为三种情况进行学习:

  • 方式一:自带信号→自带槽
  • 方式二:自带信号→自定义槽
  • 方式三:自定义信号

可以使用disconnect函数断开已经连接的信号槽,参数与connect连接时保持一致。返回值为是否断开成功,如果已经不连接了,则会断开失败,此时不会有任何影响。

2.2 自带信号→自带槽

这种情况下信号函数和槽函数都是Qt内置的,程序员只需要找到对应关系后连接即可。

【例子】点击按钮,关闭窗口。
分析:
发射者:按钮
信号函数:点击
接收者:窗口
槽函数:关闭

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;
};

#endif // DIALOG_H
#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(300,300);
    btn = new QPushButton("关闭",this);
    btn->move(100,150);

//  发射者:按钮
//	信号函数:点击
//	接收者:窗口
//	槽函数:关闭
    connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}

Dialog::~Dialog()
{
    delete btn;
}

2.3 自带信号→自定义槽

【例子】点击按钮,窗口向右侧移动10个像素,向下移动10个像素,同时输出当前的窗口坐标。
分析:
发射者:按钮
信号函数:点击
接收者:窗口
槽函数:自定义

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;

private slots: // 槽函数
    void mySlot(); // 头文件声明
};

#endif // DIALOG_H
#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(300,300);
    btn = new QPushButton("关闭",this);
    btn->move(100,150);
    // 发射者:按钮
//    信号函数:点击
//	接收者:窗口
//	槽函数:自定义
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}

void Dialog::mySlot() // 源文件定义
{
    // 先获得当前的窗口坐标
    int x = this->x();
    int y = this->y();
    // 窗口向右侧移动10个像素,向下移动10个像素
    move(x+10,y+10);
    // 同时输出当前的窗口坐标。
    qDebug() << x+10 << y+10;
}

Dialog::~Dialog()
{
    delete btn;
}

2.4 自定义信号

这种方式主要用于解决复杂问题,所以在本节强行使用。

信号函数具有以下特点:👇

  • 信号函数只有声明,没有定义
  • 信号函数没有权限
  • 声明后只用emit关键字发射
  • 可携带参数

【例子】点击按钮,关闭窗口。

三、信号与槽_#include


三、信号与槽_qt开发_02

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;

private slots:
    void mySlot();

    // 声明信号函数
signals:
    void mySignal(); // 自定义信号
};

#endif // DIALOG_H
#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn = new QPushButton("关闭",this);
    btn->move(100,150);

    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}

void Dialog::mySlot()
{
    // 发射自定义信号
    emit mySignal();
}

Dialog::~Dialog()
{
    delete btn;
}

3. 信号槽传参

信号槽支持参数传递,信号函数可携带参数发送给槽函数。

【例子】点击按钮,按钮上显示点击的次数。

正常的做法不使用信号槽传参:

三、信号与槽_信号槽_03


dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;
    int count; // 点击的次数

private slots:
    void btnClickedSlot(); // 点击按钮的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0) // 构造初始化列表
{
    resize(400,400);
    btn = new QPushButton("0",this);
    btn->move(100,200);

    connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
}

void Dialog::btnClickedSlot()
{
    // 显示点击的次数
    count++; // count是成员变量
    // int → 字符串
    QString text =  QString::number(count);
    // 给按钮设置显示内容
    btn->setText(text);
}

Dialog::~Dialog()
{
    delete btn;
}

上面的例子强行增加信号槽传参的语法。

三、信号与槽_c++_04


dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;
    int count; // 点击的次数

private slots:
    void btnClickedSlot(); // 点击按钮的槽函数
    void countSlot(int); // 自定义槽函数2

signals:
    // 能发参数的自定义信号
    void countSignal(int);
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0) // 构造初始化列表
{
    resize(400,400);
    btn = new QPushButton("0",this);
    btn->move(100,200);

    connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
    connect(this,SIGNAL(countSignal(int)),
            this,SLOT(countSlot(int)));
}

void Dialog::btnClickedSlot()
{
   count++;
   // 发射带参数的自定义信号
   emit countSignal(count);
}

/**
 * @brief Dialog::countSlot
 * @param count此数值并非成员变量,而是信号函数发射来的
 */
void Dialog::countSlot(int count)
{
    // int → 字符串
    QString text = QString::number(count);
    // 设置显示
    btn->setText(text);
}

Dialog::~Dialog()
{
    delete btn;
}

4. 总结

  • 槽函数是一种特殊的成员函数
  • 信号函数只有声明,没有定义,因此不能调用
  • 理论上可以传递任意多个信号槽参数
  • 信号的参数个数必须大于等于槽函数的参数个数
  • 信号槽传参的参数类型必须匹配
  • 一个信号函数可以连接多个槽函数,多个信号函数也可以连接看一个槽函数(一对多,多对一)

下面是一个一对多和多对一的例子:
dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn1; // 一对多
    QPushButton* btn2;

private slots:
    void btnClickedSlot1();
    void btnClickedSlot2();
    void btnClickedSlot3();
    void btnClickedSlot4();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn1 = new QPushButton("1",this);
    btn1->move(100,100);
    btn2 = new QPushButton("2",this);
    btn2->move(200,200);
    // 一对多
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot1()));
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot2()));
    // 一对一
    connect(btn2,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot3()));

    // 多对一
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot4()));
    connect(btn2,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot4()));
}

void Dialog::btnClickedSlot1()
{
    qDebug() << "a";
}

void Dialog::btnClickedSlot2()
{
    qDebug() << "b";
}

void Dialog::btnClickedSlot3()
{
    // 槽函数也是成员函数
    this->btnClickedSlot1();
    btnClickedSlot2();
}

void Dialog::btnClickedSlot4()
{
    qDebug() << "发射者是谁?";
    // 多对一的情况下如何区分发射者:
    if(btn1 == sender())
    {
        qDebug() << "发射者是btn1";
    }else if(btn2 == sender())
    {
        qDebug() << "发射者是btn2";
    }
}

Dialog::~Dialog()
{
    delete btn1;
    delete btn2;
}

📢上面要注意的点使用了sender()函数,该函数用来返回信号发送者对象的首地址,当有多个发送者对应同一个槽函数时,可以用来判断是谁发的消息。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
8caZn4LUURFU