目录
1、QT中什么是对象树
2、QT的坐标系
3、信号和槽机制
3.1、信号槽的理解
3.2、信号槽的工作原理
3.3、信号槽的使用
3.3.1、系统的信号和槽
3.3.2、自定义信号和槽函数
3.3.3、信号和槽函数之间的参数传递
3.3.4、信号和槽的注意
1、QT中什么是对象树
2、QT的坐标系
3、信号和槽机制
3.1、信号槽的理解
具体的信号是不需要实现具体要执行的动作,这个只需要定义函数,不需要实现函数体,信号接受者的槽函数要定义函数,还要实现函数体,来实现信号发起者的命令
3.2、信号槽的工作原理
3.3、信号槽的使用
信号槽有系统自定义的,但是系统自定义的只能解决 80 % 的问题,剩下的 20 % 需要我们自己定义
3.3.1、系统的信号和槽
3.3.1.1、查找系统的信号(找不到就自定义)
3.3.1.2、查找系统的槽(找不到就自定义)
由于当前的 窗口 是 Widget,所以 btn 被按下发出信号,Widget 响应,做出关闭动作,所以去 Widget 中查找 关闭窗口函数
3.3.1.3、使用按钮关闭当前主窗口
#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//设置主窗口大小
this->resize(400,300);
//创建一个按钮
QPushButton *btn = new QPushButton("关闭", this);
#if 0 //通过 0 和 1来控制使用 QT5 还是 QT4
// 建立信号和槽的关系(Qt5的方式),向下兼容,QT5兼容QT4,拿到&QPushButton::clicked的入口地址
// 拿到&Widget::close的入口地址
connect( btn, &QPushButton::clicked ,this, &Widget::close );
#else
// 建立信号和槽的关系(Qt4的方式) SIGNAL将()里面当成字符串看待 不会判断信号是否存在
// 所以 QT4 是最稳妥的方式,QT5 能兼容
connect( btn, SIGNAL(clicked()) ,this, SLOT(close()) );
#endif
}
Widget::~Widget()
{
}
3.3.2、自定义信号和槽函数
可以自定义信号选择系统槽函数,可以选择系统信号自定义槽函数,或者同时自定义信号和槽函数,根据需求选择一方即可
点击添加文件,添加发出信号者的类和接受信号者的类,并且使他们符合 QT 的槽机制(创建文件时选择 Widget 作为他们的基类),如下
#include "teacher.h"
Teacher::Teacher(QWidget *parent) : QWidget(parent)
{
//信号发出者
}
#include "student.h"
Student::Student(QWidget *parent) : QWidget(parent)
{
//信号接受者
}
创建文件时如果不选择 Widget 作为他们的基类,那么创建的类就是普普通通的类,是不会拥有 QT 的信号槽机制 定义信号: 在 teacher.h中类的关键字signals下实现:
#ifndef TEACHER_H
#define TEACHER_H
#include <QWidget>
class Teacher : public QWidget
{
Q_OBJECT
public:
explicit Teacher(QWidget *parent = 0);
signals:
//信号的返回值类型为void 可以有参(重载),不能实现函数体
void hungury(void);
public slots:
};
#endif // TEACHER_H
#ifndef STUDENT_H
#define STUDENT_H
#include <QWidget>
#include <QDebug>
class Student : public QWidget
{
Q_OBJECT
public:
explicit Student(QWidget *parent = 0);
signals:
public slots:
//槽函数返回值类型为void ,可以有参数(重载),槽函数的参数就是接受的信号的参数,信号有参数槽函数就必须有参数, 必须实现函数体,接到信号之后要执行的具体动作
void treat(void)
{
qDebug()<<"请老师吃饭了"<<endl; //相当于打印输出,QT中没有 cout
}
};
#endif // STUDENT_H
建立老师和学生的关系
在 widget.cpp中建立老师和学生的关系_即老师饿了的信号,学生就执行请吃饭的动作
#include "widget.h"
#include "teacher.h"
#include "student.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(400,300);
//实例化老师的控件
Teacher *tea = new Teacher(this);
//实例化学生的控件
Student *stu = new Student(this);
//建立老师和学生的关系,connect(tea,"饿了",stu,"请吃饭")
connect(tea,&Teacher::hungury,stu,&Student::treat);
}
Widget::~Widget()
{
}
但是现在问题是——》老师什么时候饿了,也即缺少信号的发起过程,所以设置按钮,点击按钮时,老师下课了,说饿了,学生请吃饭,所以要在 teacher.h中建立 Teacher 类的槽函数
在 widget.cpp中实现 按钮和 老师的关系建立
最后在 teacher.h中 实现当老师下课的时候,发出老师饿了的信号
上述流程执行如下
widget.cpp中的源代码如下
#include "widget.h"
#include "teacher.h"
#include "student.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(400,300);
//实例化老师的控件
Teacher *tea = new Teacher(this);
//实例化学生的控件
Student *stu = new Student(this);
# if 1
//建立老师和学生的关系,connect(tea,"饿了",stu,"请吃饭")
connect(tea,&Teacher::hungury,stu,&Student::treat);
# else
# endif
//但是现在问题是——》老师什么时候饿了,也即缺少信号的发起过程,所以设置按钮,点击按钮时,老师下课了,说饿了,学生请吃饭
QPushButton *btn = new QPushButton("下课", this);
//建立按钮和老师之间的关系,这个时候 btn 就是一个信号,老师是一个槽函数,按动按钮,老师下课了
connect(btn, &QPushButton::clicked, tea, &Teacher::classOver);
}
Widget::~Widget()
{
}
3.3.3、信号和槽函数之间的参数传递
widget.cpp中实现如下
#include "widget.h"
#include "teacher.h"
#include "student.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(400,300);
//实例化老师的控件
Teacher *tea = new Teacher(this);
//实例化学生的控件
Student *stu = new Student(this);
# if 1
//无参使用这种(QT5的方式)
//建立老师和学生的关系,connect(tea,"饿了",stu,"请吃饭")
void (Teacher:: *p1)() = &Teacher::hungury;
void (Student:: *p2)() = &Student::treat;
connect(tea,p1,stu,p2);
# else
//有参使用这种,当 信号 或者 槽 发生 重载使,使用函数指针作为区分
void (Teacher:: *p1)(QString) = &Teacher::hungury;
void (Student:: *p2)(QString) = &Student::treat;
connect(tea,p1,stu,p2);
# endif
//但是现在问题是——》老师什么时候饿了,也即缺少信号的发起过程,所以设置按钮,点击按钮时,老师下课了,说饿了,学生请吃饭
QPushButton *btn = new QPushButton("下课", this);
//建立按钮和老师之间的关系,这个时候 btn 就是一个信号,老师是一个槽函数,按动按钮,老师下课了
connect(btn, &QPushButton::clicked, tea, &Teacher::classOver);
}
Widget::~Widget()
{
}
teacher.h中的 Teacher 类中,hungury信号有参数,触发信号的classOver槽函数中的hungury信号必然有参数
#ifndef TEACHER_H
#define TEACHER_H
#include <QWidget>
#include <QDebug>
class Teacher : public QWidget
{
Q_OBJECT
public:
explicit Teacher(QWidget *parent = 0);
signals:
//信号的返回值类型为void 可以有参(重载),不能实现函数体
void hungury(void);
//参数重载
void hungury(QString foodName);
public slots:
//下课的槽函数
void classOver(void)
{
qDebug()<<"下课了"<<endl;
//emit 发出老师饿了的信号
emit this->hungury();
emit this->hungury("兰州牛肉面"); //QT自动实现参数传递解析
}
};
#endif // TEACHER_H
student.h 中的Student 类中,进行槽函数重载,实现参数传递
#ifndef STUDENT_H
#define STUDENT_H
#include <QWidget>
#include <QDebug>
class Student : public QWidget
{
Q_OBJECT
public:
explicit Student(QWidget *parent = 0);
signals:
public slots:
//槽函数返回值类型为void ,可以有参数(重载),槽函数的参数就是接受的信号的参数,信号有参数槽函数就有参数, 必须实现函数体,接到信号之后要执行的具体动作
void treat(void)
{
qDebug()<<"请老师吃饭了"<<endl;
}
void treat(QString foodName){
qDebug()<<"请老师吃饭了"<<":"<<foodName<<endl;
}
};
#endif // STUDENT_H
测试如下(无参和有参)