qt中的信号和槽:(重点)
//需求:点击按钮,关闭窗口;
4个主要内容:
connect(信号的发送者【按钮】,发送的信号【点击的信号】,信号的接受者,处理的函数【槽函数】)
处理的过程:按钮发送一个“点击”的信号,窗口接受一个“点击”的信号,将信号传递给“槽函数”。
//4 signals inherited from QAbstractButton,connect中的信号查找。
示例如下:
//需求:点击btn 关闭窗口
//参数1 信号的发送者 参数2 发送的信号(信号地址) 参数3 信号的接受者 参数4 处理的槽函数(槽函数的地址)
//槽函数:public slot
connect(btn,&QPushButton::clicked,this,&myWidget::close);
优点:松散耦合。左右事件本来不是相关的,利用connect关联起来,将信号发送和信号接收连接起来。
//****************************************************************************************
//****************************************************************************************
第二个项目:
自定义的信号和槽
qt的自定义信号:
返回值 void
需要声明,不需要实现
可以有参数
自定义槽函数:
返回值void
需要声明,需要实现
可以有参数
触发自定义的信号
emit
//teacher.h
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
//自定义的信号需要写到signal下:
//返回的类型必须是void,
//信号只需要声明,不需要实现,
//信号可以有参数,可以重载;
void hungry();
public slots:
//自定槽函数的地方;
//高版本可以写到public下,或者写成全局函数;(个人感觉写到这里更规范)。
};
#endif // TEACHER_H
//stude.h
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class student : public QObject
{
Q_OBJECT
public:
explicit student(QObject *parent = nullptr);
signals:
public slots:
//自定槽函数的地方;
//高版本可以写到public下,或者写成全局函数;(个人感觉写到这里更规范)。
//槽函数需要声明也需要实现;
//槽函数也可以有函数,也可以重载;
void treat();
};
#endif // STUDENT_H
//mywidget2.h
#ifndef MYWIDGET2_H
#define MYWIDGET2_H
#include <QWidget>
#include "teacher.h"
#include "student.h"
class mywidget2 : public QWidget
{
Q_OBJECT
public:
mywidget2(QWidget *parent = 0);
~mywidget2();
//声明两个对象:
//成员属性可以保存它;
Teacher * zt;
student * st;
void classOver();
};
#endif // MYWIDGET2_H
//teacher.cpp
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
//student.cpp
#include "student.h"
#include <QDebug>
student::student(QObject *parent) : QObject(parent)
{
}
void student:: treat()
{
qDebug()<<"请老师吃饭";
}
//mywidget2.cpp
#include "mywidget2.h"
//***************************************************************************************************************************************************
项目实践:
//需求:创建两个类:teacher 类 ,student 类
//下课后,老师teacher zt 会发出一个信号---饿了 (发出信号)----自定义信号
//学生响应信号student st 处理 信号的槽函数,请客吃饭;
//mywidget2.cpp
#include "mywidget2.h"
//需求:创建两个类:teacher 类 ,student 类
//下课后,老师teacher zt 会发出一个信号---饿了 (发出信号)----自定义信号
//学生响应信号student st 处理 信号的槽函数,请客吃饭;
mywidget2::mywidget2(QWidget *parent)
: QWidget(parent)
{
zt = new Teacher(this);//将老师对象扔到childre表里去了;
st = new student(this);//
//连接老师和学生:
connect(zt,&Teacher::hungry,st,&student::treat);
//需要时机触发:
classOver();
}
void mywidget2::classOver()
{
//触发老师饿了的信号
//老师饿了的信号属于自定义信号,触发自定义信号的关键字 emit
emit zt->hungry();
}
mywidget2::~mywidget2()
{
}
//main.cpp
#include "mywidget2.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
mywidget2 w;
w.show();
return a.exec();
}
//只用在源文件mywidget2.cpp中更改即可
//********************************************************************************************
当自定义信号和自定义槽函数发生重载时解决方法:
用函数指针明确调用的是有参还是无参的函数;
比如:将上述无参的自定义信号和自定义槽改为有参的情况,则:
//student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class student : public QObject
{
Q_OBJECT
public:
explicit student(QObject *parent = nullptr);
signals:
public slots:
//自定槽函数的地方;
//高版本可以写到public下,或者写成全局函数;(个人感觉写到这里更规范)。
//槽函数需要声明也需要实现;
//槽函数也可以有函数,也可以重载;
void treat();
void treat(QString foodname);
};
#endif // STUDENT_H
//teacher .h
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
//自定义的信号需要写到signal下:
//返回的类型必须是void,
//信号只需要声明,不需要实现,
//信号可以有参数,可以重载;
void hungry();
void hungry(QString foodname);//信号有参的情况
public slots:
//自定槽函数的地方;
//高版本可以写到public下,或者写成全局函数;(个人感觉写到这里更规范)。
};
#endif // TEACHER_H
//mywidget2.h
#define MYWIDGET2_H
#include <QWidget>
#include "teacher.h"
#include "student.h"
class mywidget2 : public QWidget
{
Q_OBJECT
public:
mywidget2(QWidget *parent = 0);
~mywidget2();
//声明两个对象:
//成员属性可以保存它;
Teacher * zt;
student * st;
void classOver();
};
#endif // MYWIDGET2_H
//student.cpp
#include "student.h"
#include <QDebug>
student::student(QObject *parent) : QObject(parent)
{
}
void student:: treat()
{
qDebug()<<"请老师吃饭";
}
//槽函数有参的情况
void student::treat(QString foodname){
qDebug()<<"请老师吃饭,老师要吃:"<<foodname;
}
//teacher.cpp
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
//mywidget2.cpp
#include "mywidget2.h"
//需求:创建两个类:teacher 类 ,student 类
//下课后,老师teacher zt 会发出一个信号---饿了 (发出信号)----自定义信号
//学生响应信号student st 处理 信号的槽函数,请客吃饭;
mywidget2::mywidget2(QWidget *parent)
: QWidget(parent)
{
zt = new Teacher(this);//将老师对象扔到childre表里去了;
st = new student(this);//
//连接老师和学生:
//connect(zt,&Teacher::hungry,st,&student::treat);
//有参情况的连接:
//函数指针指向函数地址;
void (Teacher:: *teachersignal)(QString) = &Teacher::hungry;
void (student::*studentslot)(QString) = &student::treat;//这两句话是关键
connect(zt,teachersignal,st,studentslot);
//需要时机触发:
classOver();
}
void mywidget2::classOver()
{
//触发老师饿了的信号
//老师饿了的信号属于自定义信号,触发自定义信号的关键字 emit
emit zt->hungry();//触发无参信号
emit zt->hungry("热干面");//触发有参信号
}
mywidget2::~mywidget2()
{
}
//上述调用Connect时,有参函数的地址需要定义一个函数指针指向函数的地址,可以解决自定义信号和自定义槽函数的重载问题;
//在调用emit触发槽函数时,也要明确是调用的有参还是无参;
另附:
//QString 转 char*
qDebug()<<"请老师吃饭,老师要吃:"<<foodname.toUtf8().data();
//1.先转成Qbytearry类型、
//2.再转为char*
//******************************
归纳:
当自定义信号和槽 出现重载时候,原先写法失效,因为执行的函数地址不明确;
解决方法:利用函数指针,来明确指向哪个函数的地址
QString 转char* toUtf8() 转为 QBtyeArry类型,再利用data转成char*;
//系统自带的函数可能也会发生重载,此时也用上述方法进行解决。
//********************************************************************************************************
信号和槽的扩展:
//用按钮触发信号1,信号1连接信号2
//信号2触发槽函数;
//断开信号和槽:
disconnect();
//扩展:
//1.信号可以连接信号;
//2.信号和槽可以断开 disconnect
//3.一个信号可以触发多个槽函数;
//4.多个信号可以连接同一个槽函数;
//5.信号和槽的参数必须一一对应吗?不一定
//信号的参数个数必须多余槽函数的参数,但是类型必须一一对应。
参考:黑马程序员培训视频