对象树、QT的坐标系、信号和槽机制

目录

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中什么是对象树

在创建 QObject 对象时,可以提供一个其父对象,我们创建 的这个 QObject 对象会自动
添加到其父对象的 children()列表。
当父对象析构的时候,这个列表中的所有对象也会 被析构。(注意,这 里的父对象并不是继承意义上的父类!)
QWidget 继承自 QObject,因此也继承了这种对象树关系。一个孩子自 动地成为父组件
的一个子组件
我们也可以自己删除子对象,它们会自动从其父对象列表中删除
综上所述:所有的控件 尽量在 堆区 创建

2、QT的坐标系

以左上角为原点(0,0),X 向右增加,Y 向下增加

3、信号和槽机制

3.1、信号槽的理解

具体的信号是不需要实现具体要执行的动作,这个只需要定义函数,不需要实现函数体,信号接受者的槽函数要定义函数,还要实现函数体,来实现信号发起者的命令

3.2、信号槽的工作原理

某个事件发生之后 ,比如,按钮检测到自己被点击了一下, 它就会发出一个信号(signal) 。这种发出是没有目的的,类似广播( 谁都能听到或者看到,比如项羽摔杯的发出的响声和动作 )。 如果有对象对这个信号感兴趣,它就会使用连接(connect)函数 ,意思是, 将想要处理的信号和自己的一个函数(称为槽(lot))绑定来处理这个信号 。也就是说, 当信号发出时,被连接 的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

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
定义槽函数:
在 student.h中 类的关键字public slots下实现:

#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

测试如下(无参和有参)

 

3.3.4、信号和槽的注意

一个信号 连接 多个槽
多个信号 连接 一个槽
disconnect取消信号和槽的连接
槽函数的参数 一定要 小于等于 信号的参数个数

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q渡劫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值