添加信号槽机制
信号和槽
举个例子:
当你需要打字的时候,你手指按下键盘的任意一个键,屏幕就会根据你按的键位显示对应的值。这个过程你就可以理解为,你手值按下的动作就发送了一个信号,屏幕接收到这个信号,然后去做相对应的显示——槽函数来实现
// 需求 b2 关闭窗口
// connect(b2, 发出的信号, this, 处理信号的槽函数);
connect(b2,&QPushButton::clicked,this,&MyWidget::close);
//connect(&b1,&QPushButton::clicked,this,&MyWidget::close);
/*
* b2: 信号的发出者, 此参数是一个指针
* &QPushButton::clicked: 信号发出者, 内部的一个信号
* 格式: & + 信号发出者类的名字 + :: + 信号的名字
* this: 信号的接收者, 此参数是一个指针
* &MyWidget::close: 信号的处理函数, 属于this
*/
常见信号(发出者)
信号处理函数(接收者)
创建一个新的SignalAndSlot——MainWidget
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include <QPushButton>
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
private:
QPushButton* b1;
QPushButton* b2;
};
#endif // MAINWIDGET_H
#include "mainwidget.h"
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
b1 = new QPushButton("登陆",this);
b1->move(20,320);
b2 = new QPushButton;
b2->setParent(this);
b2->setText("退出");
b2->move(300,320);
this->setFixedSize(400,400);
this->setWindowTitle("QQ");
this->setWindowIcon(QIcon("/home/yangyu/DailyFILE/picture/52.jpg"));
connect(b2,&QPushButton::clicked,this,&MainWidget::close);
}
MainWidget::~MainWidget()
{
}
这是一个普通的信号槽,也是需要使用直接去帮助文档查即可。
connect(b2,&QPushButton::clicked,this,&MainWidget::close);
标准格式:b2的作用域+信号 this的作用域+槽函数
表示从QPushButton拿到对应的函数地址,槽函数也是如此,实际上就是个回调函数
回调函数在调用时不立刻执行,而是满足一定条件后(如接受指定信号)才执行
- 信号和槽都是函数
- 信号只有函数声明,不要函数定义
- 槽函数就需要声明也要定义
自定义槽函数
需求:按下b1按钮,b2的值发生改变
- 自定义槽函数
- 槽函数可以是任意的类成员函数,全局函数,静态函数,lambda表达式(隐式函数,没函数名)
- 槽函数需要与信号对应(返回值,参数)
- 信号没有返回值,槽函数返回值:void
void mysig(int , double,Qstring)
void myslot(int,double,Qstring)
- 槽函数的参数是为了接收信号传过来的数据
- 槽函数的参数应该是不能够大于信号的参数个数,可以少于信号的参数个数
- 槽函数可以重载
调用
- connect(b1,&QPushButton::pressed,this,&MainWidget::slotForMainWidget);
如果给b2自定义槽函数,需要再创建一个类来继承QPushButton,因此很麻烦。
因此采用通过b2的父类MyWidget设置b2的值
上面的操作只是在同一个窗口中进行操作。
自定义信号
需求:按下mainwidget窗口中的登录即可隐藏自己,显示subwidget窗口
下图中红色部分,定义了mainwidget下的对象指针b3,以及subwidget类对象subw。
绿色部分是对他们的定义.
执行以后可以得到 点击登录即可隐藏QQ登录界面显示,QQ邮箱界面
那么点击退出如何实现隐藏QQ邮箱,显示QQ登录呢?
- 首先,subwidget中的QPushButton::*bt2肯定是不能直接给mainwidget发送信号的。
-
原因是bt2是subwidget的成员变量,肯定不可能跨类去给另外一个类发送信号。
-
因此需要一个间接的方式,比如通过bt2给自己的父类发送一个信号,(由于父类subwidget是属于mainwidget的)MySlot是自定义信号
4. 接下来如下图父类对象也是mainwidget的一个成员变量,因此父类收到bt2发送来的信号,再发送一个自定义信号,给它subw的父类,从而对mainwidget可以收并做处理
如下图,在subwidget中自定义信号和槽函数,由bt2发送普通信号,subwidget的对象收到信号,用自定义槽函数进行处理。接下来由subw发送自定义信号给mainwidget。mainwidget使用自定义槽函数进行处理。
#ifndef SUBWIDGET_H
#define SUBWIDGET_H
#include <QWidget>
#include <QPushButton>
class SubWidget : public QWidget
{
Q_OBJECT
public:
explicit SubWidget(QWidget *parent = nullptr);
~SubWidget();
signals:
//自定义信号,必须用signals进行声明
//信号是不用定义的,声明即可
void sigSub();
//可以有参数,重载,
//返回值为void,
//发送信号使用emit
public slots:
//自定义槽函数
void MySlot();
private:
QPushButton *bt1;//(确认)
QPushButton *bt2;//(退出)隐藏自己,显示QQ登陆
};
#endif // SUBWIDGET_H
发送自定义信号
void loginwidget::loginslots()
{
emit loginsignal();//发送自定义信号
}
结果显示
总结一下。顶层窗口自定义信号槽函数中进行事件处理。顶层窗口的派生窗口(按钮)可以直接发送信号给顶层窗口。
而派生窗口中的变量,想要发送信号给顶层窗口,只能通过派生类的对象this。不可以直接从当前类直接给另外一个类发送信号。