Monday, August 27, 2007

by Harald Fernengel translated by jams.lee
Qt使用MOC(元对象编译器)来收集自定义类的信息.这些被应用于信号/槽机制,并且使Qt应用程序可以是自省(introspection)的。在Qt4 中,三个新特性—-动态槽调用,排队信号(queued signals),对用户自定义类型的支持—-需要我们扩展Qt的元类型信息。



Qt引入了QMetaType类来支持在运行时注册一个新的数据类型。任何一个具有公有构造函数、公有拷贝构造函数和一个公有析构函数的类或结构都可以被注册。例如:




qRegisterMetaType<employee>("Employee")


类Employee就会被注册。这样QMetaType就会知道如何构造、拷贝和析构这个类的实例。每一个注册了的数据类型都拥有一个唯一的ID号,这个ID号可以通过 QMetaType::type() 获得:




int employeeId = QMetaType::type("Employee");


我们就可以使用这个ID动态的构造、拷贝、析构Employee




void *original = QMetaType::construct(employeeId, 0);
void *copy = QMetaType::construct(employeeId, original);
QMetaType::destroy(employeeId, original);
QMetaType::destroy(employeeId, copy);


在大多数Qt应用程序中,我们只需要关注 qRegisterMetaType() 就可以了。Qt会根据需要相应地调用 construct()destroy() 。在以后各节中,我们介绍Qt4构建于QMetaType基础之上的各种特性。



动态槽调用



QMetaObject可以使QObject子类的信号和槽是自省的。这通常被应用于测试框架、脚本绑定,以及一些accessibility utilities。
在Qt的早期版本中,动态调用一个槽的唯一方法是将一个信号和这个槽连接,并引发这个信号。在Qt4中,槽可以通过 QMetaObject::invokeMember() 来调用:




QMetaObject::invokeMember(object, "clear");


如果这个槽需要参数,可以使用QArgument来传递,或者使用更方便的Q_ARG()宏:




QMetaObject::invokeMember(statusBar, "showMessage",
Q_ARG(QString, tr("Ready")),
Q_ARG(int, 2000));


QMetaType在幕后负责数据类型的列集(marshalling),任何已经注册的数据类型都可以通过QArgument或者Q_ARG()宏来传递。像int这样的原生类型和QString这样的Qt类都已经被预注册过了,所以我们可以不受限制的传递这些类型。



排队信号
在Qt3中,信号是同步传送的。Qt4引入了排队信号的概念,它可以使槽被异步调用。与发送事件类似,信号在应用下一次进入消息循环时被传递。事实上,排队信号被实现为事件(event)。