qt 自定义信号与槽

13 篇文章 3 订阅

  在qt中,信号与槽,发送方和接收方都是可以自定义的。
  这里作为实验,我们定义两个类:一个是老师,一个是学生。当下课的时候,老师作为发送方发送信号“该下课了”,作为接收方的学生则提供槽函数,回复老师“该干饭了”。
  qt提供的机制令c++程序在其中可以较为方便地实现回调,很值得学习。

编写信号与槽函数

  首先在源文件中新建两个class:
在这里插入图片描述
  这里稍微注意一下,qt中新建类的时候会让你选择该新类的父类。显然该实验中我们的自定义类和qt里的类没有什么关系,但是如果继承了qt内的类的话,就可以享受qt里面的对象树机制,可以安全地自动化回收新建对象,因此我们新建类的时候可以选择QObject作为父类。
  QObject是qt的“终极爸爸”,一切类的父类,所以继承它很安全。
  新建出来的类会自动提供一个模板,以student.h为例。

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
    Q_OBJECT //一个宏定义,表明该类允许使用qt里的信号与槽
public:
    explicit Student(QObject *parent = nullptr);

signals:
	//信号函数需要写在此处
	//只需要声明,不需要实现

public slots:
    //在早期版本  槽函数只能写在此处
    //需要声明与实现
   
};

#endif // STUDENT_H

  从初始的类模板中可以看出,qt为新建类能够使用信号和槽特地做了准备。首先使用宏定义Q_OBJECT对该类进行了使能,令其有资格使用信号与槽;此外还在类中划分了专门区域分别用来声明信号函数和槽函数。
  信号函数和槽函数最大的区别是:信号函数可以只声明不实现,槽函数必须又声明又实现
  比如说在这个实验里,老师需要一个函数(信号函数),用来说“该下课了”;而学生需要一个函数(槽函数),用来说“该干饭了”。
  结果就是,老师的函数只需要声明,没必要实现,老师没必要真的去说“该下课了”。
  但是学生的函数需要声明和实现,学生是必须回复“该干饭了”的。
  因此在student.h中必须声明函数。

void treat();

在这里插入图片描述
  另外在stduent.cpp中,实现该函数。

#include <QDebug>

void Student::treat(){
    qDebug()<<"it is time for lunch";
}

  qDebug()<<的用法和cout<<一样,用于打印特定信息。
  
在这里插入图片描述
  teacher.h中需要加入信号函数,只需要声明就好了。

void dismiss();

在这里插入图片描述
  ok,信号与槽定义完毕,接下来准备对接。

连接信号与槽

  回顾一下qt中信号与槽的连接函数:

connect(发送信号的对象(指针),信号函数(指针),接收信号的对象(指针),槽函数(指针));

  从中可见,信号函数和槽函数已经有了,但是两个对象还没有。
  因此需要在mywidget类里面声明两个成员变量,这两个成员变量实例化后就是对象。

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>
#include "student.h" //新增头文件
#include "teacher.h" //新增头文件

class myWidget : public QWidget
{
    Q_OBJECT //宏,允许使用信号与槽

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

private:
    Teacher *tea;//指向teacher类的指针
    Student *stu;//指向student类的指针
};

#endif // MYWIDGET_H

  随后在mywidget的构造函数中初始化两个对象。

myWidget::myWidget(QWidget *parent): QWidget(parent)
{
    this->tea = new Teacher(this);
    this->stu = new Student(this);

}

  这里需要注意,在初始化的同时,可以令每个对象的父类为当前类(窗口),这样两个对象就等于加入了该工程的对象树,在程序中可以自动回收。
  随后编写连接函数,将四大元素都注册上:

connect(tea,&Teacher::dismiss,stu,&Student::treat);

  这样,直接运行就会有效果吗?
  我们可以回忆关于信号与槽的最早的例程:按键和XX。假设我将按键的click信号与窗口的关闭做了链接,那程序运行时一定是按下那个按键之后,窗口再关闭。
  回到这个实验中来,虽然我们做好了连接,但是总感觉缺了点什么。按键与窗口关闭的试验至少我们还点了下按键,这次却什么都没做。
  我们思考一下该实验的场景:“下课的时候……”,是不是发现问题了?程序怎么知道什么时候下课呢?不通过下课怎么能触发信号,并由槽函数接收呢?
  经以上分析后可以得出:我们需要自定义一个函数,通过该函数触发信号,就像用鼠标点击按键一样。

private:
    Teacher *tea;
    Student *stu;
    void classDissmissed();

  在mywidget.h里面的类中声明一个函数void classDissmissed(),在该函数中我们去实现触发信号这个功能。该函数的实现如下:

void myWidget::classDissmissed(){
    emit tea->dismiss();
}

  注意这里使用了关键字emit,该关键字的用法很简单:在该关键字后面加入的对象的函数,就是要触发的信号。
  实现了之后记得要调用才行:

#include "mywidget.h"


myWidget::myWidget(QWidget *parent): QWidget(parent)
{
    this->tea = new Teacher(this);
    this->stu = new Student(this);
    connect(tea,&Teacher::dismiss,stu,&Student::treat);
    this->classDissmissed();//调用
}

void myWidget::classDissmissed(){
    emit tea->dismiss();
}

myWidget::~myWidget()
{

}

  实验结果如下:
在这里插入图片描述
  

总结

  总结一下,自定义信号与槽,需要五大元素:
  发送方,信号函数,接收方,槽函数。这四个是老客户了,需要注意一下的是,发送方和接收方一定是实例对象。
  第五个元素则是在不使用自定义信号与槽时容易忽略的存在,我在这里称其为“触发机制”。在定义的过程中,触发机制也是需要自己编写的,一般触发机制是自己编写的触发函数。
  此外,信号函数和槽函数都应当返回void。

后续改动

  在该实验中,一运行程序就“下课”,这样的处理方式太过简陋,很不qt。
  在qt中,信号不仅可以触发槽,信号还可以触发其他信号。
  因此我们可以新建一个按钮,令其触发下课条件。

#include "mywidget.h"
#include <qpushbutton>

myWidget::myWidget(QWidget *parent): QWidget(parent)
{
    this->tea = new Teacher(this);
    this->stu = new Student(this);
    this->resize(600,400); //固定窗口大小
    QPushButton *btn1 = new QPushButton("dismissed",this); //新建一个按钮对象
    connect(tea,&Teacher::dismiss,stu,&Student::treat); //信号触发槽
    //this->classDissmissed(); //不需要函数来触发信号了
    connect(btn1,&QPushButton::clicked,tea,&Teacher::dismiss); //信号触发信号
}

void myWidget::classDissmissed(){
    emit tea->dismiss();
}

myWidget::~myWidget()
{

}

  以上代码中出现了两个connect函数,分别用来建立老师宣布下课和学生干饭的连接、点击按钮和老想宣布下课的连接。
  这样也就出现了一个“点击按钮——老师宣布下课——学生去干饭”的消息链。
  并且第二个connect函数(即点击按钮——老师宣布下课)就相当于前面总结中所提到的触发函数。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值