QMetaObject类包含有关Qt对象的元信息。在Qt中,Qt元对象系统负责信号和槽的对象间通信机制、运行时类型信息以及Qt属性系统。每个应用程序中使用的QObject子类都创建一个QMetaObject实例,该实例存储QObject子类的所有元信息。该对象可通过QObject::metaObject()方法获得。
通常在应用程序编程中不需要使用这个类,但在编写元应用程序(如脚本引擎或GUI构建器)时非常有用。您可能最有用的函数是这些:
indexOfConstructor()、indexOfMethod()、indexOfEnumerator()和indexOfProperty()等索引函数将构造函数、成员函数、枚举器或属性名称映射到元对象中的索引。例如,在将信号连接到槽时,Qt在内部使用indexOfMethod()。
类还可以具有其他类信息的名称-值对列表,存储在QMetaClassInfo对象中。 classInfoCount()返回对数,classInfo()返回单个对,indexOfClassInfo()可用于搜索对。
###invokeMethod()
用法
invokeMethod()函数是QObject类的一个成员函数,它可以动态调用一个QObject对象的特定方法(成员函数)。这种方法调用开销较大,应该尽可能避免使用。可以直接调用对象方法来执行所需操作。
该函数的原型为:
bool QObject::invokeMethod(const QObject *context, const char *method,
Qt::ConnectionType type = Qt::AutoConnection,
QGenericReturnArgument ret = QGenericReturnArgument(),
QGenericArgument val0 = QGenericArgument(),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument());
其中,context参数是一个QObject指针,指定要调用方法的对象;method参数是一个成员函数名,以字符串形式指定;type参数是Qt::ConnectionType类型,指定调用方法时的连接类型;ret参数和val0~val9参数分别是返回值和函数参数,以QGenericReturnArgument和QGenericArgument类型封装。
#include
#include
#include
#include
class MyObject : public QObject {
Q_OBJECT
public:
MyObject(QObject* parent = nullptr) : QObject(parent) {}
public slots:
void myMethod() {
qDebug() << "Running in thread" << QThread::currentThread();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyObject obj;
QThread thread;
// 将QObject移到另一个线程中
obj.moveToThread(&thread);
// 连接线程开始信号到槽
QObject::connect(&thread, &QThread::started, &obj, [&](){
// 在另一个线程中调用QObject的myMethod()方法
QMetaObject::invokeMethod(&obj, "myMethod", Qt::QueuedConnection);
});
thread.start();
return a.exec();
}
上述示例步骤:
运行结果如下所示:
Running in thread QThread(0x7fffc8000820)
从输出结果可以看出,myMethod()方法确实在另一个线程中执行了。这种方式可以用于实现QObject对象的跨线程方法调用。
#include
#include
#include
class MyObject : public QObject {
Q_OBJECT
public:
MyObject(QObject* parent = nullptr) : QObject(parent) {}
public slots:
void myMethod() {
qDebug() << "Hello from MyObject!";
}
QString myStringMethod(int num) {
return QString("My number is %1").arg(num);
}
};
int main(int argc, char* argv[]) {
QCoreApplication a(argc, argv);
MyObject obj;
const QMetaObject* metaObj = obj.metaObject();
// 获取类名
qDebug() << "Class name:" << metaObj->className();
// 获取父类的元对象
const QMetaObject* superClass = metaObj->superClass();
qDebug() << "Superclass name:" << superClass->className();
// 获取方法数量
int methodCount = metaObj->methodCount();
qDebug() << "Method count:" << methodCount;
// 遍历方法
for (int i = 0; i < methodCount; ++i) {
QMetaMethod method = metaObj->method(i);
qDebug() << "Method name:" << method.name();
// 判断是否是槽函数
if (method.methodType() == QMetaMethod::Slot) {
qDebug() << " Is a slot function!";
}
// 判断是否有返回值
if (method.returnType() != QMetaType::Void) {
qDebug() << " Return type:" << method.typeName();
}
// 输出参数类型
int argCount = method.parameterCount();
for (int j = 0; j < argCount; ++j) {
qDebug() << " Arg" << j << "type:" << method.parameterType(j);
}
}
// 调用对象的方法
QString result = "";
QMetaObject::invokeMethod(&obj, "myStringMethod", Q_RETURN_ARG(QString, result), Q_ARG(int, 42));
qDebug() << result;
return a.exec();
}
输出结果如下所示:
Class name:MyObject
Superclass name:QObject
Method count:3
Method name:destroyed
Method name:deleteLater
Method name:myMethod
Is a slot function!
Method name:myStringMethod
Return type:QString
Arg0 type:int
My number is 42