一、描述
此类包含有关Qt对象的元信息。Qt为应用程序中使用的每个 QObject 子类创建一个 QMetaObject 实例,该实例存储 QObject 子类的所有元信息。
二、静态成员函数
1、QByteArray normalizedSignature(const char *method)
规范化给定方法的签名。Qt使用规范化签名来决定给定的信号和槽是否兼容。
规范化:
- 将空格减少到最小
- 将 const 移到最前面适当的位置,
- 用值替换 const 引用。
signals:
void userNameChanged(const QString & userName);
void passwordChanged(const QString password);
qDebug()<<this->staticMetaObject.normalizedSignature(SIGNAL(userNameChanged(const QString & userName)));
qDebug()<<this->staticMetaObject.normalizedSignature(SIGNAL(passwordChanged(const QString password)));
2、QByteArray normalizedType(const char *type)
规范化类型。
QByteArray normType = QMetaObject::normalizedType(" int const *");
// normType == "const int*"
3、bool checkConnectArgs(const char *signal, const char *method)
信号和方法参数是否兼容。信号和方法均应规范化。
static const QMetaObject meteObject = this->staticMetaObject;
qDebug()<<meteObject.checkConnectArgs(meteObject.normalizedSignature(SIGNAL(userNameChanged(const QString & userName))),
meteObject.normalizedSignature(SLOT(onUserChanged(const QString & userName))));
qDebug()<<meteObject.checkConnectArgs(SIGNAL(userNameChanged(const QString & userName)),
SLOT(onUserChanged(const QString & userName)));
bool checkConnectArgs(const QMetaMethod &signal, const QMetaMethod &method)
signals:
void userNameChanged(const QString & userName);
private slots:
void onUserChanged(const QString &userName);
auto meteObject = this->staticMetaObject;
auto signalIndex = meteObject.indexOfSignal("userNameChanged(QString)");
QMetaMethod signal = meteObject.method(signalIndex);
auto funIndex = meteObject.indexOfMethod("onUserChanged(QString)");
QMetaMethod fun = meteObject.method(funIndex);
qDebug()<<meteObject.checkConnectArgs(signal,fun);//true
4、void connectSlotsByName(QObject *object)
递归搜索给定对象及其所有子对象,并将来自这些子对象的匹配信号连接到以下形式的槽:
void on_<object name>_<signal name>(<signal parameters>);
假设一个类型为 QPushButton 的对象,对象名为 button1,捕捉按钮 clicked() 信号的槽为:void on_button1_clicked();
5、bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(nullptr), QGenericArgument val1 = QGenericArgument(), ......)
调用对象obj上的成员 member(信号或槽)。如果可以调用该成员,则返回 true。如果没有此成员或参数不匹配,则返回false。
调用可以是同步的,也可以是异步的,具体取决于 type:
- Qt::DirectConnection:立即调用该成员。
- Qt::QueuedConnection:应用程序进入主事件循环后发送 QEvent 并调用该成员。
- Qt::BlockingQueuedConnection:将以与 Qt::QueuedConnection 相同的方式调用该成员,但当前线程将阻塞。使用此连接类型与在同一线程中的对象之间通信将导致死锁。
- Qt::AutoConnection:如果 obj 与调用者位于同一线程中,则同步调用该成员,否则将异步调用该成员。
调用的返回值放在 ret 中。如果调用是异步的,则无法计算返回值。
最多可以向成员函数传递十个参数(val0、val1、val2、val3、val4、val5、val6、val7、val8、val9)。
QGenericArgument 和 QGenericReturnArgument 是内部帮助程序类。因为可以动态调用信号和槽,所以必须使用 Q_ARG() 和 Q_RETURN_ARG() 宏将参数括起来。Q_ARG() 接受类型名称和该类型的常量引用,Q_RETURN_ARG() 接受类型名和非常量引用。
只需要将信号或槽的名称传递给此函数,而不需要传递整个签名(只传递名称不用包含参数)。
例如,在 QThread 上异步调用 quit() 槽:
QMetaObject::invokeMethod(thread, "quit",Qt::QueuedConnection);
对于异步方法调用,参数必须是Qt的元对象系统已知的类型,因为Qt需要复制参数以在幕后事件中存储它们。对于自定义类型,在调用之前需要使用 qRegisterMetaType() 注册数据类型。
示例:同步调用某个任意对象 obj 上的 compute(QString, int, double) 槽:
QString retVal; QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection, Q_RETURN_ARG(QString, retVal), Q_ARG(QString, "sqrt"), Q_ARG(int, 42), Q_ARG(double, 9.7));
这里如果 “compute” 槽没有按指定顺序精确地接受一个QString、一个int、一个double,则调用将失败。
bool invokeMethod(QObject *obj, const char *member, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(0), ......)
此重载始终使用连接类型 Qt::AutoConnection 调用成员。
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericArgument val0 = QGenericArgument(0), ......)
如果成员函数无返回值,则可以使用此重载。
bool invokeMethod(QObject *obj, const char *member, QGenericArgument val0 = QGenericArgument(0), ......)
此重载使用连接类型 Qt::AutoConnection 调用成员函数,并忽略返回值。
template <typename Functor, typename FunctorReturnType> bool invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr)
在 context 的事件循环中调用 function 。function 可以是函子或指向成员函数的指针。
如果可以调用函数,则返回 true。如果没有此类函数或参数不匹配,则返回 false。
函数调用的返回值放在 ret 中。
class test
{
public:
test() = default;
void operator()()
{
qDebug()<<"run test()";
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
QMetaObject::invokeMethod(&a,test());
return a.exec();
}
template <typename Functor, typename FunctorReturnType> bool invokeMethod(QObject *context, Functor function, FunctorReturnType *ret)
使用连接类型 Qt::AutoConnection 在 context 的事件循环中调用 function。function 可以是函子或指向成员函数的指针。
如果可以调用函数,则返回 true。如果没有此类成员或参数不匹配,则返回 false。
函数调用的返回值放在 ret 中。
三、非静态成员函数
1、QMetaClassInfo classInfo(int index)
返回具有给定索引的类信息项的元数据。
class Widget : public QWidget
{
Q_OBJECT
Q_CLASSINFO("作者", "张三")
Q_CLASSINFO("时间", "2020-1-1")
......
};
QMetaClassInfo info = this->staticMetaObject.classInfo(0);
qDebug()<<info.name()<<info.value()<<(info.enclosingMetaObject() == this->metaObject());//作者 张三 true
2、int classInfoCount()
返回此类中类信息的项数。
3、int classInfoOffset()
返回此类的类信息偏移量,即该类第一个类信息项的索引位置。
如果类没有包含类信息的超类,则偏移量为0;否则,偏移量是类超类中所有类信息项的总和。
class Widget : public QWidget
{
Q_OBJECT
Q_CLASSINFO("作者", "张三")
Q_CLASSINFO("时间", "2020-1-1")
........
};
class Widget_child : public Widget
{
Q_OBJECT
Q_CLASSINFO("此类作者", "李四")
public:
Widget_child(QWidget *parent = nullptr);
};
Widget_child::Widget_child(QWidget *parent)
:Widget(parent)
{
qDebug()<<this->staticMetaObject.classInfoOffset();//2
}
4、const char * className()
返回类名。
5、int indexOfClassInfo(const char *name)
查找类信息项名称并返回其索引,没有这个名词的类信息项则返回-1。
class Widget : public QWidget
{
Q_OBJECT
Q_CLASSINFO("作者", "张三")
Q_CLASSINFO("时间", "2020-1-1")
......
};
qDebug()<<this->staticMetaObject.indexOfClassInfo("时间");//1
6、int constructorCount()
返回此类中构造函数的数目。构造函数加上 Q_INVOKABLE 宏才能被元对象系统识别。
class Widget : public QWidget
{
Q_OBJECT
public:
Q_INVOKABLE Widget(QWidget *parent = nullptr);
~Widget();
......
7、QMetaMethod constructor(int index)
返回具有给定索引的构造函数的元数据。
8、int indexOfConstructor(const char *constructor)
查找构造函数并返回其索引,找不到则返回 -1。
构造函数必须是规范化的形式,如 normalizedSignature() 返回的那样。
void Widget::on_pushButton_clicked()
{
auto metaObject = this->staticMetaObject;
qDebug()<<metaObject.indexOfConstructor(QMetaObject::normalizedSignature("Widget()"));
}
9、int enumeratorCount()
返回此类中的枚举数。枚举加上 Q_FLAG() 才能被元对象系统识别。
enum test01
{
};
Q_FLAG(test01)
enum class test02
{
};
Q_FLAG(test02)
qDebug()<<this->staticMetaObject.enumeratorCount();//2
10、QMetaEnum enumerator(int index)
返回具有给定索引的枚举的元数据。
11、int enumeratorOffset()
返回此类的枚举偏移量,即此类第一个枚举的索引位置。
如果类没有带枚举的超类,则偏移量为0;否则,偏移量是类超类中所有枚举数的总和。
12、int indexOfEnumerator(const char *name)
查找枚举并返回其索引,找不到则返回 -1。
13、QMetaMethod method(int index)
返回具有给定索引的方法的元数据。加上 Q_INVOKABLE 宏的方法才能被元对象系统识别。
14、int methodCount()
返回此类中的方法数,包括所有基类提供的方法数。这包括了信号和槽。
获取包含特定于给定类的方法:
const QMetaObject* metaObject = obj->metaObject();
QStringList methods;
for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
methods << QString::fromLatin1(metaObject->method(i).methodSignature());
15、int indexOfMethod(const char *method)
查找函数并返回其索引,找不到则返回 -1。
method 必须是规范化的形式,如由 normalizedSignature() 返回。
void Widget::on_pushButton_clicked()
{
auto metaObject = this->staticMetaObject;
qDebug()<<metaObject.indexOfMethod(QMetaObject::normalizedSignature("on_pushButton_clicked()"));
}
16、int methodOffset()
返回此类的方法偏移量,即该类第一个成员函数的索引位置。
偏移量是类的超类中所有方法的总和。
17、int indexOfSignal(const char *signal)
查找信号并返回其索引,找不到则返回 -1。
这与 indexOfMethod() 相同,只是如果方法存在但不是信号则将返回 -1。
signal 必须是规范化的形式,如由 normalizedSignature() 返回。
18、int indexOfSlot(const char *slot)
查找槽并返回其索引,找不到则返回 -1。
这与 indexOfMethod() 相同,只是如果该方法存在但不是槽则将返回-1。
19、QMetaProperty property(int index)
返回具有给定索引的属性的元数据。属性使用 Q_PROPERTY 宏定义。
20、int indexOfProperty(const char *name)
查找属性并返回其索引,找不到则返回 -1。
class Widget : public QWidget
{
Q_OBJECT
Q_PROPERTY(int test READ getTest WRITE setTest NOTIFY testChanged)
......
};
auto metaObject = this->staticMetaObject;
qDebug()<<metaObject.indexOfProperty("test");
21、int propertyCount()
返回此类中的属性数,包括所有基类提供的属性数。
获取包含特定于给定类的属性:
const QMetaObject* metaObject = obj->metaObject();
QStringList properties;
for(int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
properties << QString::fromLatin1(metaObject->property(i).name());
22、int propertyOffset()
返回此类的属性偏移量,即此类第一个属性的索引位置。偏移量是类的超类中所有属性的总和。
23、bool inherits(const QMetaObject *metaObject)
当前 QMetaObject 描述的类是否继承 metaObject 所描述的类型。类型被视为继承自身。
24、QMetaType metaType()
返回与此元对象对应的元类型。
namespace test
{
class testClass : public QObject
{
Q_OBJECT
public:
testClass() = default;
};
}
class Widget : public QWidget
{
Q_OBJECT
......
};
void Widget::on_pushButton_clicked()
{
qDebug()<<this->staticMetaObject.metaType().name(); //Widget
test::testClass t1;
qDebug()<<t1.staticMetaObject.metaType().name(); //test::testClass
}
25、QObject * newInstance(QGenericArgument val0 = QGenericArgument(nullptr), QGenericArgument val1 = QGenericArgument(), ......)
构造此类的新实例。最多可以向构造函数传递十个参数(val0、val1、val2、val3、val4、val5、val6、val7、val8、val9)。
返回新对象,如果没有合适的构造函数,则返回nullptr。
要注意只有使用 Q_INVOKABLE 宏声明的构造函数才能通过元对象系统使用。
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Widget w;
// w.show();
if(Widget * w = qobject_cast<Widget*>(Widget::staticMetaObject.newInstance()))
{
w->show();
}
return a.exec();
}
26、const QMetaObject * superClass()
返回超类的元对象,如果没有此类对象,则返回nullptr。
27、QMetaProperty userProperty()
返回 USER 标志设置为 true 的属性。见:Qt属性系统。
四、宏成员
1、QGenericArgument Q_ARG(Type, const Type &value)
此宏接受 Type 和对该类型值的常量引用,并返回可以传递给 QMetaObject::invokeMethod() 的 QGenericArgument 对象。
2、QGenericReturnArgument Q_RETURN_ARG(Type, Type &value)
此宏接受 Type 和对该类型值的非常量引用,并返回可以传递给 QMetaObject::invokeMethod() 的QGenericReturnArgument 对象。