Qt的元对象(meta object)系统

MOC:元对象编译器;

元对象(meta object)意思是描述另一个对象结构的对象,比如获得一个对象有多少成员函数,有哪些属性。在Qt中,我们将要用到的是QMetaObject这个类。 

Qt的元对象系统系统建立在以下三个方面:

  1. QObject类是所有使用元对象系统类的基类
  2. 必须在一个类的开头插入宏Q_OBJECT,这样这个类才可以使用元对象系统的特性
  3. MOC为每个QObject的子类提供必要的代码来实现元对象系统的特性

1 QObject类

  QObject类是所有使用元对象系统类的基类

元对象系统的特性是通过QObject的一些函数实现的,主要包括以下几个部分:

  • 元对象:函数metaObject()返回这个元对象指针。所以。获取一个对象的元对象有两种方式,示意代码如下:

        QPushButton *btn=new QPushButton();

        const QMetaObject *metaPtr=btn->metaObject();        //获取元对象指针

        const QMetaObject metaObj=btn->staticMetaObject;        //获取元对象

  • 类型信息
  • 动态翻译
  • 对象树:表示对象间从属关系的树状结构;对象树中的某个对象被删除时,它的子对象就会被自动删除,因此,一个窗口被删除时,它上面的所有界面组件也会被自动删除;
  • 信号与槽:在类定义中插入宏Q_OBJECT,就可以使用Qt扩展的c++语言特性编程;
  • 属性系统:在类的定义中利用宏Q_PROPERTY定义属性,QObjectsetProperty()函数会设置属性的值或定义动态属性;property()函数会返回属性的值;


QObject元对象核心类https://zhuanlan.zhihu.com/p/43598693

2 QMetaObject类

元对象QMetaObject类型的实例。元对象存储了类的实例所属类的各种元数据,包括类信息元数据、方法元数据、属性元数据等。所以,元对象实质上是对类的描述

QMetaObject类实际上是通过一些接口函数来获取所属类的各种元数据,包括类信息元数据、方法元数据、属性元数据等。

3 运行时类型信息(RTTI) P50

(1)函数QMetaObject::className():该函数运行时返回类名称的字符串 

(2)函数QObjetc::inhetits()。可以判断一个对象是不是继承自某个类的实例。顶层的父类是QObject ;

(3)函数QMetaObject::superClass()。用来返回该元对象所描述类的父类的元对象,通过父类的元对象可以获取父类的一些元数据;

(4)函数qobject_cast(): 对于Object及其子类对象,可以使用函数qobject_cast()进行动态类型转换,此处可以理解为c++中的强制类型转换;如下:

QObject *btn=new QPushButton();      //创建QPushButton对象,但是使用QObject指针
const QMetaObject *meta=btn->metaObject();
QString str1=QString(meta->clasName());    //str1="QPushButton"

QPushButton *btnPush=qobject_cast<QPushButton*>(btn);    //转换成功,将Object类型转换成QPushButton类型
const QMetaObject *meta2=btnPush->metaObject();
QString str2=QString(meta2->clasName());    //str1="QPushButton"
#此时的转换是成功的,因为btn就是QPushButton对象指针,但是,如果将btn转换成QCheckBox对象指针就会失败,因为QChechBox不是QPushButton的父类;

4 属性系统

在QObject的子类中,使用宏Q_PROPERTY定义属性;格式如下:

Q_PROPERTY(type name
           (READ getFunction [WRITE setFunction] |
            MEMBER memberName [(READ getFunction | WRITE setFunction)])
           [RESET resetFunction]
           [NOTIFY notifySignal]
           [REVISION int]
           [DESIGNABLE bool]
           [SCRIPTABLE bool]
           [STORED bool]
           [USER bool]
           [CONSTANT]
           [FINAL])

MEMBER:指定一个成员变量与属性关联,使之成为可读可写的属性,指定后无需再设置READ和WRITE。

RESET:是可选的,用于将属性设置为上下文指定的默认值

Q_PROPERTY这个宏,简单用法如下:

Q_PROPERTY(type name READ getFunction WRITE setFunction)

Q_PROPERTY(参数类型 参数名称 READ 获得属性值函数 WRITE 设置属性值函数)

比如Q_PROPERTY(bool bIsDoubi READ getDoubi WRITE setDoubi),属性类型是bool类型,bIsDoubi是属性名称。除此之外还需要写两个函数,第一个是设置属性的函数void setDoui(bool),第二个是获得属性的函数bool getDoubi()。

QMetaObject类的一些函数可以提供元对象所描述类的属性元数据,属性元数据用QMetaProperty类描述,它有各种函数可反应属性的一些特性,例如下面的一段代码:

const QMetaObject *meta=ui->spinBoy->metaObject();    //获取一个SpinBox的元对象
int index=meta->indexOfProperty("value");             //获取属性value的序号
OMetaProperty prop=meta->property(index);             //获取属性value的元数据
bool res=prop.isWritable();                 //属性是否可写,值为true
res=prop.isDesignable();                    //属性是否可设计,值为true
res=prop.hasNotifySignal();                 //属性是否有反映属性值变化的信号,值为true

5 信号与槽

qt使用信号与槽机制实现对象之间的通信,它隐藏了复杂的底层实现;是Qt的核心特性;

5.1 connect函数不同的参数形式

connect(sender,SIGNAL(signal()),receiver,SLOT(slot())); 如下:

connect(ui->radioButton_red, SIGNAL(clicked()),this, SLOT(do_fontcolor()));
connect(ui->radioButton_blue, &QRadioButton::clicked,this, &do_fontcolor);

当槽函数是overload型时,需要使用模板函数qOverload()来明确参数类型;

//如果在窗口类中包含下列两个槽函数
void do_click(bool checked);
void do_click();

connect(ui->checkBox,&QcheckBox::clicked,this,qOverload<bool>(&Widget::do_click));
connect(ui->checkBox,&QcheckBox::clicked,this,qOverload<>(&Widget::do_click));

注意:遇到重载的槽函数一定要使用qOverload()模板函数来明确参数类型; 

对于overload型信号,只要槽函数不是overload型,就可以使用传递函数指针的connect()来进行信号与槽的关联;Qt会根据槽函数的参数自动确定使用哪个信号;

QObject::connect(pushButton_ok, &QPushButton::clicked, Dialog, qOverload<>(&QDialog::accept));
QObject::connect(pushButton_close, &QPushButton::clicked, Dialog, qOverload<>(&QDialog::close));

5.2  disconnect()函数的使用

disconnect():用于解除信号与槽的连接;

使用方式如下:

(1)解除与一个发射者所有信号的连接,例如:

disconnect(myobject,nullptr,nullptr,nullptr);    //静态函数形式
myobject->disconnect();                          //成员函数形式

(2)解除与一个特定信号的所有连接,例如:

disconnect(myobject,SIGNAL(mysignal()),nullptr,nullptr);    //静态函数形式
myobject->disconnect(SIGNAL(mysignal()));    //成员函数的形式

(3)解除与一个特定接收者的所有连接,例如:

disconnect(myobject,nullptr,myreceiver,nullptr);    //静态函数形式
myobject->disconnect(myreceiver);    //成员函数的形式

(4)解除特定的一个信号与槽的连接,例如:

disconnect(lineEdit,&QLineEdit::textChanged,label,&QLabel::setText);    //静态函数形式

6 对象树 (P57)

使用QObject及其子类创建的对象(统称为QObject对象)是以对象树的形式来组织的;父对象被删除,其全部子对象就会被自动删除;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值