qt android meta data,QT学习笔记 qt_meta_data

这两天开始使用QT,学习了一些入门皮毛知识,下面是学习笔记。

Qt的最大好处是跨平台,包括跨平台类库、集成开发工具和跨平台 IDE。使用 Qt 您只需一次性开发应用程序,无须重新编写源代码,便可跨不同桌面和嵌入式操作系统部署这些应用程序。

配置Qt的windows开发环境

1. 下载Qt的安装包和VS2010的Qt插件,大家可以到下面的地址进行下载(下面的下载都是基于Windows的,如果是其他环境的操作系统可以到这里下载).

Qt SDK: http://qt.nokia.com/downloads/sdk-windows-cpp

VS2010开发插件: http://qt.nokia.com/downloads/visual-studio-add-in

2. 安装Qt SDK

3. 安装Qt的VS开发插件

同安装Qt SDK一样,一路上回车即可,安装后在VS2010上新增一菜单Qt

QT从.h文件生成.cpp文件

1. 头文件“配置属性”->“自定义生成步骤”->“命令行”

“$(QTDIR)/bin/moc.exe” “%(FullPath)” -o “%(RootDir)%(Directory)moc_%(Filename).cpp”

2. 头文件“配置属性”->“自定义生成步骤”->“输出”

%(RootDir)%(Directory)moc_%(Filename).cpp;%(Outputs)

3. 头文件“配置属性”->“自定义生成步骤”->“说明”

Moc’ing file %(Filename)

moc生成文件分析

首先看一下简单含有的signal, slot代码

class myClass : public QObject

{

Q_OBJECT

public:

myClass();

~myClass();

void trigger();

void trigger2();

signals:

void signalFunc(double);

int signalFunc2(char, int);

protected slots:

void slotFunc(double);

int slotFunc2(char);

};

// 只是实例代码,用来生成moc_myClass

#include”myClass.h”

#include

using std::cout;

using std::endl;

myClass::myClass()

{

connect(this, SIGNAL(signalFunc),

this, SLOT(slotFunc));

connect(this, SIGNAL(signalFunc2),

this, SLOT(slotFunc2));

}

myClass::~myClass()

{

}

void myClass::slotFunc(double d)

{

cout << “slotFunc” << endl;

}

int myClass::slotFunc2(char c)

{

cout << “slotFunc2″ << endl;

return c;

}

void myClass::trigger()

{

}

void myClass::trigger2()

{

}

编译生成moc_myClass.cpp

static const uint qt_meta_data_myClass[] = {

// content:

4, // revision

0, // classname

0, 0, // classinfo

4, 14, // methods

0, 0, // properties

0, 0, // enums/sets

0, 0, // constructors

0, // flags

2, // signalCount

// signals: signature, parameters, type, tag, flags

9, 8, 8, 8, 0×05,

34, 32, 28, 8, 0×05,

// slots: signature, parameters, type, tag, flags

56, 8, 8, 8, 0×09,

73, 8, 28, 8, 0×09,

0 // eod

};

其中methods部分,4代表这个对象含有4个signal + slot, 14是基础数字,在moc代码里面也是硬编码,数一下content的个数,刚好是14,这个14其实就是个偏移量,偏移到signal的第一行.数一下

// content:

4, // revision             0

0, // classname        1

0, 0, // classinfo       2,3

4, 14, // methods     4,5

0, 0, // properties     6,7

0, 0, // enums/sets   8,9

0, 0, // constructors  10,11

0, // flags                    12

2, // signalCount        13

// signals: signature, parameters, type, tag, flags

9, 8, 8, 8, 0×05,         14

signal和slot的flag提供了一些属性,这个会在后面的QObject::connect讲到。

这里需要提出来一点是signal和slot的第一个数值,9, 34, 56, 73这几个,这个马上会讲到先提出来,留个印象

这里前14个数值是对应的QMetaObjectPrivate的值

[cpp] view plaincopyprint?

struct QMetaObjectPrivate

{

int revision;

int className;

int classInfoCount, classInfoData;

int methodCount, methodData;

int propertyCount, propertyData;

int enumeratorCount, enumeratorData;

int constructorCount, constructorData; //since revision 2

int flags; //since revision 3

int signalCount; //since revision 4

}

接下来是

static const char qt_meta_stringdata_myClass[] = {

“myClass/0/0signalFunc(double)/0int/0,/0″

“signalFunc2(char,int)/0slotFunc(double)/0″

“slotFunc2(char)/0″

};

从这个字符串里面,可以看到第一个值为这个类的类名(元对象可以不通过RTTI给出类名的原因就在这里)

在第一个/0后面会给出第一个signal的返回值类型,在这个例子中signalFunc没有返回值,所以没有任何内容,

在第二个/0后面会给出参数名,因为moc读取的是头文件,而我们在头文件中没定义参数名,所以为空

然后就是signal的名字和参数列表类型,这里需要注意的是,即使头文件给出了参数名,在这里也会被忽略掉,只提供类型

再下一个/0后面就是下一个函数的描述了,描述的方式跟前面是一样的。

刚刚提到的9, 34, 56, 73这几个数字,在这里是有用的,这几个数字,刚好是这个字符串对应的函数开头的部分。比如9,那我们在这个字符串中数9个字符,即signalFunc(double)这一段内容。

然后是源对象的数据定义:

const QMetaObject myClass::staticMetaObject = {

{ &QObject::staticMetaObject, qt_meta_stringdata_myClass,

qt_meta_data_myClass, 0 }

};

可以看到源对象的数据定义为:

struct { // private data

const QMetaObject *superdata;

const char *stringdata;

const uint *data;

const void *extradata;

}

这个名为staticMetaObject的对象是由Q_OBJECT引入的

第一个数据为父类名字, moc对于多继承的限制可能也在于此。

moc规定多继承的情况下,moc会假设第一个继承的类为QObject, 并且必须要保证在多继承中,只有唯一一个类是继承自QObject的。这样看上去,多余一个QObject继承的,第二个QObject根本没办法识别出来。

第二个数据就是上面的字符串数据

第三个也是上面的uint*数据。

这个源对象非常关键,后面的内容就靠他了。

[cpp] view plaincopyprint?

const QMetaObject &myClass::getStaticMetaObject() { return staticMetaObject; }

const QMetaObject *myClass::metaObject() const

{

return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;

}

这2个方法都是由Q_OBJECT引入的。目的是返回这个类的元对象

[cpp] view plaincopyprint?

void *myClass::qt_metacast(const char *_clname)

{

if (!_clname) return 0;

if (!strcmp(_clname, qt_meta_stringdata_myClass))

return static_cast(const_cast< myClass*>(this));

return QObject::qt_metacast(_clname);

}

还是由Q_OBJECT引入的

当传入的字符串数据是当前这个类的话,就将this指针转换成void指针传给外界:这个操作相当危险。

如果不是当前类的话,就调用父类的qt_metacast继续查询。

在这里,我的父类是QObject,所以自然就调用QObject::qt_metacase了

在看qt_metacall之前,先看下signal的定义。 额。。事实上signal不需要你自己定义,moc已经帮我们完成这点了。

具体内容如下:

// SIGNAL 0

void myClass::signalFunc(double _t1)

{

void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) };

QMetaObject::activate(this, &staticMetaObject, 0, _a);

}

我们看到他将所有的参数都转型成void*指针保存到 void *a的数组中,然后调用了

QMetaObject::activate(this, &staticMetaObject, 0, _a);

看到传入的参数为this, 源对象和参数

这个函数实际上就是触发消息的函数,在这里不过多关注他,有机会再写

最终,int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)

会被调用,用来处理对应的signal的消息

代码如下

int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)

{

_id = QObject::qt_metacall(_c, _id, _a);

if (_id < 0)

return _id;

if (_c == QMetaObject::InvokeMetaMethod) {

switch (_id) {

case 0: signalFunc((*reinterpret_cast< double(*)>(_a[1]))); break;

case 1: { int _r = signalFunc2((*reinterpret_cast< char(*)>(_a[1])),(*reinterpret_cast(_a[2])));

if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;

case 2: slotFunc((*reinterpret_cast< double(*)>(_a[1]))); break;

case 3: { int _r = slotFunc2((*reinterpret_cast< char(*)>(_a[1])));

if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;

default: ;

}

_id -= 4;

}

return _id;

}

这里可以注意下,有返回值和没有返回值的处理方法~

QT从.ui文件生成ui_***.h文件

1. 头文件“配置属性”->“自定义生成步骤”->“命令行”

“$(QTDIR)/bin/uic.exe” “%(FullPath)” -o “%(RootDir)%(Directory)ui_%(Filename).h”

2. 头文件“配置属性”->“自定义生成步骤”->“输出”

%(RootDir)%(Directory)ui_%(Filename).h;%(Outputs)

3. 头文件“配置属性”->“自定义生成步骤”->“说明”

Compiling UI file %(Filename)

UI文件的编辑使用 QT Designed进行。编辑完保存为.ui文件,然后使用上面的命令生成头文件。

你可能感兴趣的:(qt,android,meta,data)