第三章 信号槽(重点)

目录

一、信号槽的概念

二、函数原型

三、连接方式

3.1 自带信号 → 自带槽

3.2 自带信号 → 自定义槽

3.3 自定义信号 → 槽

四、参数传递

4.1 全局参数

4.2 信号槽传参

五、信号槽的对应关系


一、信号槽的概念

类似于一些其它的编程语言或框架中的回调机制,信号槽是Qt基于C++语法新增的特性,使用起来非常方便,可以完成不同对象之间的通信。

信号槽的使用需要有以下两个条件:

1. 通信的对象必须继承自QObject类QObject是Qt所有内置类型的基类

2. 类中要有Q_OBJECT宏

二、函数原型

信号槽需要连接后才能触发,因此信号槽的核心是连接函数,连接函数是一个静态成员函数。

参数1:发射者发射者是一个对象,此对象发射信号函数,作为信号槽的触发条件。

参数2:信号函数参数1中的发射者发射出的信号函数,作为信号槽的触发条件需要使用 SIGNAL()包裹函数名称

参数3:接收者接收者是一个对象,此对象执行槽函数,作为信号槽的执行结果

参数4:槽函数参数3中接收者要执行的槽函数,作为信号槽的执行结果。需要使用SLOT() 包裹函数名称。

接收者绑定了发射者的信号函数,一旦发射者发射信号函数,接收者就执行槽函数。

三、连接方式

为了方便讲解,依次使用三种方式进行信号槽的连接。

  • 自带信号 → 自带槽
  • 自带信号 → 自定义槽
  • 自定义信号 → 槽

3.1 自带信号 → 自带槽

这种方式是最简单的一种连接方式,因为信号函数和槽函数Qt都内置了,只需要程序员从文档中找到对应函数连接即可。

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

分析:先找因果关系的四个参数。

参数1:发射者,按钮对象

参数2:信号函数,点击

参数3:接收者,窗口对象

参数4:槽函数,关闭

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;//窗口中的子组件必须放在堆内存里面(就是必须用指针),
                        而且必须在.h里面定义成全局的 因为还要析构不然调不了
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

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

    // 连接信号槽
    //  参数1:发射者,按钮对象
    //	参数2:信号函数,点击
    //	参数3:接收者,窗口对象
    //	参数4:槽函数,关闭
    connect(btn,SIGNAL(clicked()),this,SLOT(close()));
    //点击按钮 发射信号 由于窗口绑定了信号函数 所以窗口接收信号并触发了槽函数
}

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

3.2 自带信号 → 自定义槽

在实际的开发中,Qt不可能内置所有的函数,特别是槽函数,更多的情况是需要用户自定义一个槽函数来实现特定的功能,这种方式也是最常见的一种信号槽连接方式。

要注意的是,槽函数是一种特殊的成员函数,实现槽函数的方式与普通成员函数类似。

注意:一定要先链接再触发信号 不然你虽然触发了信号但是接收者没有进行链接就触发不了槽函数

【例子】点击按钮,向右下方移动窗口并输出当前的窗口坐标。分析:

参数1:按钮对象

参数2:clicked

参数3:窗口对象

参数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 *btn;

private slots: // 私有槽函数
    // 声明自定义槽函数
    void mySlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn = new QPushButton("向右下方移动",this);
    btn->setGeometry(100,100,100,100);

    // 连接信号槽
    //    参数1:按钮对象 btn
    //    参数2:clicked
    //    参数3:窗口对象 this
    //    参数4:自定义槽函数 mySlot
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));//类内通过this指针找到w,
          第三个参数为什么是this因为自定义信号槽函数属于Dialog类而这个类只有一个对象就是w,
          类内想要调w就必须用this
}
//法一:手写 法二:再定义中鼠标中点击重构
void Dialog::mySlot()//类内声明类外定义必须加作用域限定符 
{
    // 先获得当前窗口的坐标
    int x = this->x();
    int y = this->y();
    // 增加后移动
    move(x+10,y+10);
    // 输出当前坐标
    qDebug() << x+10 << "," << y+10;
}

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

3.3 自定义信号 → 槽

这种做法主要用于后期一些稍微复杂的场景,现在讲解无法使用合适案例演示,因此讲解的过程中并不是最优解,属于强行使用。

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

之前的思路:

现在的思路:

现在的思路需要有两个信号槽的连接,在自定义槽函数中要手动发射一个自定义信号函数,信号函数是一种非常特殊的函数,信号函数只有声明,没有定义;信号函数没有权限。

首先按钮与窗口进行链接connect 再点击按钮 按钮发射一个信号 由于两者绑定所以窗口会收到这个信号并触发槽函数,然后再去链接connect窗口与窗口本身就是自己链接自己 上一个触发的槽函数里面是一个自定义信号 然后发射这个自定义信号 窗口接受 并执行相应的槽函数 

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;

private slots:
    // 自定义槽函数
    void mySlot();

signals: // 信号函数没有权限
    // 自定义信号函数只需要声明就能使用
    void mySignal();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

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

    // 第一个信号槽的连接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    // 第二个信号槽的连接
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
    //点击按钮发射点击信号给窗口 窗口收到信号并触发槽函数 ,
      槽函数里面 又触发信号,由窗口发送给窗口 窗口收到信号触发槽函数 执行函数操作关闭窗口
}

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

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

四、参数传递

4.1 全局参数

在一个类中进行参数传递,可以通过成员变量等方式。

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

QPushButton的text : QString属性表示显示的文字,对应的getter和setter为

QString text() const 读取内容

void setText(const QString & text) 设置内容

setter函数不是槽函数,因此需要自定义槽函数,在自定义槽函数中调用text属性的setter函数改变其数值。

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:
    int count; // 点击按钮的次数

    QPushButton* btn;

private slots:
    void setTextSlot(); // 自定义槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0)
{
    btn = new QPushButton("0",this);
    btn->move(100,100);

    // 点击按钮,设置当前点击的次数
    // 连接信号槽
    connect(btn,SIGNAL(clicked()),this,SLOT(setTextSlot()));
}

void Dialog::setTextSlot()
{
    // 点击次数+1
    count++;
    // int → QString
    QString text = QString::number(count);//类型转换函数
    // 设置当前点次数的字符串 设置到按钮上显示
    btn->setText(text);
}

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

4.2 信号槽传参

这种做法主要用于后期一些稍微复杂的场景,现在讲解无法使用合适案例演示,因此讲解的过程中并不是最优解,属于强行使用。

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

4.1节中的思路

本节思路

首先链接按钮与窗口 当按钮被点击时发送点击信号 然后窗口收到此信号去出发无参自定义的槽函数,槽函数里面执行数据的自增 然后保存并进行信号传参 再然后窗口绑定自身,发送带参信号,窗口收到带参信号 并触发带参构造函数

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:
    int count; // 点击按钮的次数

    QPushButton* btn;

private slots:
    void mySlot1(); // 自定义槽函数1
    void mySlot2(QString); // 自定义槽函数2

signals:
    // 带参数的自定义信号,参数使用哑元
    void mySignal(QString);
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0)
{
    btn = new QPushButton("0",this);
    btn->move(100,100);

    // 点击按钮,设置当前点击的次数
    // 连接信号槽1
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot1()));
    // 连接信号槽2
    connect(this,SIGNAL(mySignal(QString)),this,SLOT(mySlot2(QString)));
}

void Dialog::mySlot1()
{
    // 点击次数+1
    count++;
    // int → QString
    QString text = QString::number(count);
    // 发射带参数的自定义信号
    emit mySignal(text);
}

/**
 * @brief Dialog::mySlot2
 * @param text 信号发来的参数
 */
void Dialog::mySlot2(QString text)
{
    // 更新按钮显示
    btn->setText(text);
}

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

信号槽传参需要注意以下几点:

  • 理论上可以传递任意个数的参数,但是实际开发建议1-2个参数
  • 信号的参数个数必须大于等于槽的参数个数
  • 参数类型必须一一匹配

五、信号槽的对应关系

同一个信号可以连接到多个槽(一对多),多个信号也可以连接到同一个槽(多对一)。一对多的情况可以优化为一对一。

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 mySlot1();
    void mySlot2();

    void mySlot3();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    btn1 = new QPushButton("1",this);
    btn2 = new QPushButton("2",this);
    btn1->move(50,50);
    btn2->move(100,100);

    // 点击btn1,一对多
    connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot1()));
    connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));

    // 可以优化为btn2的一对一
    connect(btn2,SIGNAL(clicked()),this,SLOT(mySlot3()));
}

void Dialog::mySlot1()
{
    qDebug() << "槽函数1";
}

void Dialog::mySlot2()
{
    qDebug() << "槽函数2";
}

void Dialog::mySlot3()
{
    // 槽函数也是成员函数,可以直接调用
    mySlot1();
    mySlot2();
}

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

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Qt开发及实例 第三版》是一本针对Qt开发的教材,在课后的答案中,会对书中的练习题和问题进行解答和分析,帮助读者更好地理解和掌握Qt开发的知识和技能。 这本书的课后答案涵盖了各个章节的内容,包括Qt基础知识、窗口和控件、布局管理、信号机制、文件和网络操作、数据库编程等方面的问题。通过阅读和分析这些答案,读者可以深入了解每个章节的重点和难点,并通过实例和案例来巩固所学的知识。 通过《Qt开发及实例 第三版》这本书的课后答案的学习,读者可以提高自己的Qt开发能力,加深对Qt框架的理解和应用。同时,这本书的课后答案也可以作为学习过程中的参考和辅助资料,帮助读者解决一些自己遇到的问题和困惑。 总之,《Qt开发及实例 第三版》课后答案是这本书的重要补充,它提供了对书中内容的深入解析和全面回答,让读者更好地掌握Qt开发的知识和技能。这本书及其课后答案对于想要学习和掌握Qt开发的读者来说,是一本非常有价值和实用的教材。 ### 回答2: 《Qt开发及实例 第三版》是一本介绍Qt软件开发的参考书籍。本书分为多个章节,涵盖了Qt的基础知识和实际应用。下面是一些课后答案的简要说明: 1. 第一章:介绍了Qt开发环境的安装和配置,重点介绍了Qt的基本功能和特性。 2. 第二章:讲解了Qt的基本界面设计和窗口布局,包括使用布局管理器和创建自定义的窗口类。 3. 第三章:介绍了Qt信号机制,以及如何在应用程序中使用它们来实现事件处理。 4. 第四章:详细介绍了Qt的图形编程,包括绘图、图像处理和图形效果等方面的内容。 5. 第五章:讲解了Qt的网络编程,包括使用Qt网络模块进行数据通信和远程访问。 6. 第六章:介绍了Qt的数据库编程,包括使用Qt的Sql模块进行数据库的连接和操作。 7. 第七章:讲解了Qt的多线程编程,包括使用Qt的多线程类进行并发操作和任务处理。 8. 第八章:介绍了Qt的动画编程,包括使用Qt的动画框架进行动画效果的实现。 9. 第九章:讲解了Qt的国际化和本地化,包括如何为应用程序添加多语言支持。 10. 第十章:介绍了Qt的测试框架和调试工具,以及如何对Qt应用程序进行测试和调试。 通过学习《Qt开发及实例 第三版》,读者能够全面了解Qt开发技术和应用实践,能够独立开发Qt应用程序,并且能够运用Qt的各种特性和模块来实现不同的功能。同时,课后答案提供了对书中知识点的回顾和巩固,帮助读者更好地理解和掌握所学内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值