精华内容
下载资源
问答
  • QMetaObject Struct 译文

    2021-03-05 15:57:10
    QMetaObject 类包含Qt对象元信息。 头文件:#include <QMetaObject> qmake: QT += core 公共类型 class Connection 公共方法 QMetaClassInfo classInfo(intindex) const int ...
    QMetaObject 类包含Qt对象元信息。
    头文件:#include <QMetaObject>
    qmake: QT += core
     

    公共类型

    class Connection
     

    公共方法

    QMetaClassInfoclassInfo(int index) const
    intclassInfoCount() const
    intclassInfoOffset() const
    const char *className() const
    QMetaMethodconstructor(int index) const
    intconstructorCount() const
    QMetaEnumenumerator(int index) const
    intenumeratorCount() const
    intenumeratorOffset() const
    intindexOfClassInfo(const char *name) const
    intindexOfConstructor(const char *constructor) const
    intindexOfEnumerator(const char *name) const
    intindexOfMethod(const char *method) const
    intindexOfProperty(const char *name) const
    intindexOfSignal(const char *signal) const
    int
    indexOfSlot(const char * slot) const
    boolinherits(const QMetaObject *metaObject) const
    QMetaMethodmethod(int index) const
    int
    methodCount() const
    intmethodOffset() const
    QObject *newInstance(QGenericArgument val0 = QGenericArgument(nullptr), 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()) const
    QMetaPropertyproperty(int index) const
    intpropertyCount() const
    intpropertyOffset() const
    const QMetaObject *superClass() const
    QMetaPropertyuserProperty() const

    静态公共成员

    boolcheckConnectArgs(const char *signal, const char *method)
    boolcheckConnectArgs(const QMetaMethod &signal, const QMetaMethod &method)
    voidconnectSlotsByName(QObject *object)
    bool
    invokeMethod(QObject * obj, const char * member, Qt::ConnectionType  type, QGenericReturnArgument  ret, QGenericArgument  val0 = QGenericArgument(nullptr), 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())
    boolinvokeMethod(QObject *obj, const char *member, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(0), 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())
    boolinvokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericArgument val0 = QGenericArgument(0), 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())
    boolinvokeMethod(QObject *obj, const char *member, QGenericArgument val0 = QGenericArgument(0), 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())
    boolinvokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr)
    boolinvokeMethod(QObject *context, Functor function, FunctorReturnType *ret)
    QByteArraynormalizedSignature(const char *method)
    QByteArraynormalizedType(const char *type)

    宏定义

    QGenericArgument
    Q_ARG( Type, const Type & value)
    QGenericReturnArgumentQ_RETURN_ARG(Type, Type &value)
     

    详细说明

    Qt元对象系统负责信号与槽内部对象交互机制,运行时类型信息,Qt属性系统。为应用程序中每一个QObject子类对象创建一个QMetaObject实例,这个实例为QObject子类对象存储所有元信息。通过QObject::metaObject()获得该对象。
     
    普通应用程序不需要这个类,但如果写元应用程序,像脚本引擎,GUI编辑器,就需要使用。
     
    一些很有用的方法:
    • className() 返回类名
    • superClass() 返回父类元对象
    • method()和methodCount() 提供类的元方法信息(信号,槽和其他可调用成员方法)
    • enumerator()和enumeratorCount() 提供类枚举信息
    • propertyCount()和property() 提供类属性信息
    • constructor()和constructorCount() 提供类元构造函数信息
     
    索引函数  indexOfConstructor(),  indexOfMethod(),  indexOfEnumerator(), 和  indexOfProperty() 将 构造函数,成员函数, 枚举,或者属性 的名字映射到元对象的索引上。例如,当你连接信号和槽的时候,Qt内部用 indexOfMethod()。
     
    类还可以有一个附加类信息的 键值对 队列表,存储在QMetaClassInfo对象中。 classInfoCount () 获得键值对的个数, classInfo () 获得每个单独的键值对,自主搜索使用 indexOfClassInfo ()。
     
    注意:元对象系统的操作通常都是线程安全的,具有代表性的是QMetaObjects在编译时,生成静态只读实例。然而,如果元对象被应用程序动态修改(例如使用QQmlPropertyMap),那么应用程序必须显示的同步访问各自的元对象。
     
     

    成员方法文档

    [static]bool QMetaObject::checkConnectArgs(const char* signal, const char* method) 

    如果信号和方法参数匹配则返回true,否则返回false
    信号和方法都需要标准化

    [static]bool QMetaObject::checkConnectArgs(const QMetaMethod &signal, const QMetaMethod &method)

    这是一个重载方法。
    如果信号和方法参数匹配则返回true,否则返回false
    此方法在 Qt5.0 引入

    QMetaClassInfo QMetaObject::classInfo(int index) const

    通过索引返回类信息的元数据
    例子:
    class MyClass : public QObject 
    {
        Q_OBJECT
        Q_CLASSINFO("author", "Sabrina Schweinsteiger")
        Q_CLASSINFO("url", "http://doc.moosesoft.co.uk/1.0/")
    
        public:
            ...
    
    };

    查看 classInfoCount(), classInfoOffset(), 和 indexOfClassInfo().


    int QMetaObject::classInfoCount() const

    返回类中,类信息项的数量

    查看 classInfo(), classInfoOffset(), 和 indexOfClassInfo().


    int QMetaObject::classInfoOffset() const

    返回类中,类信息偏移量,即第一个类信息项的索引位置。
     
    如果类没有父类,那么类信息偏移量为0,否则偏移量是父类的类信息项的总个数。
    查看   classInfo (),  classInfoCount (), 和  indexOfClassInfo ().

    const char *QMetaObject::className() const

    返回类名称
    查看   superClass ().

    [static]void QMetaObject::connectSlotsByName(QObject *object)

    递归查询给定参数对象的所有子对象,并按照如下规则,将匹配的子对象信号,连接到槽:
    void on_<object name>_<signal name>(<signal parameters>);
    我们假设我们的对象有一个QPushButton类型的子对象,子对象含有对象名 button1。那么可以捕获到按钮 clicked() 信号的槽应该是:
    void on_button1_clicked();

    如果对象本身有一个恰当的对象名,那么它自己的信号同样也可以连接到它自己的槽上。

    查看   QObject::setObjectName ().

    QMetaMethod QMetaObject::constructor(int index) const

    按照索引返回构造函数的元数据
    该方法在 Qt4.5 引入。
    查看  constructorCount () 和  newInstance ().

    int QMetaObject::constructorCount() const

    返回类中构造函数的数量
    该方法在 Qt4.5 引入。
    查看  constructor () 和  indexOfConstructor ().

    QMetaEnum QMetaObject::enumerator(int index) const

    按索引返回枚举的元数据
    查看   enumeratorCount (),  enumeratorOffset (), 和  indexOfEnumerator ().

    int QMetaObject::enumeratorCount() const

    返回枚举的数量
    查看    enumerator (),  enumeratorOffset (), 和  indexOfEnumerator ().

    int QMetaObject::enumeratorOffset() const

    返回类的枚举偏移量,即类中第一个枚举的索引位置。
    如果类没有父类,那么偏移量为0,否则偏移量为父类枚举数量的总和。
    查看    enumerator (),  enumeratorCount (), 和  indexOfEnumerator ().

    int QMetaObject::indexOfClassInfo(const char *name) const

    按名字找到类信息项的索引,没找到返回-1。
    查看    classInfo (),  classInfoCount (), 和  classInfoOffset ().

    int QMetaObject::indexOfConstructor(const char *constructor) const

    查找构造函数的索引,没找到返回-1。
    注意 构造函数必须是格式化标准,就像  normalizedSignature () 返回的那样。
    该方法在 Qt4.5 引入。
    查看    constructor (),  constructorCount (), 和  normalizedSignature ().

    int QMetaObject::indexOfEnumerator(const char *name) const

    返回枚举的索引,没找到返回-1。
    查看    enumerator (),  enumeratorCount (), 和  enumeratorOffset ().

    int QMetaObject::indexOfMethod(const char *method) const

    返回方法的索引,没找到返回-1。
    注意 方法必须是格式化标准,就像  normalizedSignature () 返回的那样。
    查看 method(), methodCount(), methodOffset(), 和 normalizedSignature().

    int QMetaObject::indexOfProperty(const char *name) const

    返回属性的索引,没有返回-1。
    查看  property (),  propertyCount (), 和  propertyOffset ().

    int QMetaObject::indexOfSignal(const char *signal) const

    返回信号的索引,没有返回-1。
    和  indexOfMethod () 类似,只是如果方法存在但不是信号,会返回-1。
    注意 信号必须是标准格式的,就像  normalizedSignature(). 返回的那样。
    查看  indexOfMethod(), normalizedSignature(), method(), methodCount(), 和 methodOffset().

    int QMetaObject::indexOfSlot(const char *slot) const

    返回槽的索引,没有返回-1。
    和  indexOfMethod () 类似,只是如果方法存在但不是槽,会返回-1。
    查看  indexOfMethod(), method(), methodCount(), 和 methodOffset().

    bool QMetaObject::inherits(const QMetaObject *metaObject) const

    如果是继承自QMetaObject类型,则返回true,否则返回 false。
    被认为是自我类型继承。
    该方法在 Qt5.7 引入。

    bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(nullptr), 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())

    调用对象 obj 的成员函数(信号或槽)。如果可以调用返回true,如果没有这样的成员 或者 参数不匹配返回 false。
    调用方式可以是同步的也可以是异步的,取决于类型:
    • 类型是 Qt::DirectConnection, 立即调用
    • 类型是 Qt::QueuedConnection,当应用程序进入主循环,发送一个 QEvent ,成员立即调用
    • 类型是 Qt::BlockingQueuedConnection,和 Qt::QueuedConnection 的调用方式一致,事件发送前,当前线程阻塞。同线程对象间,使用这种方式通信,会造成死锁
    • 类型是  Qt::AutoConnection,如果 obj 和 调用者在同线程,成员会同步调用。否则成员异步调用
    调用成员函数的返回值是ret。如果异步调用,返回值无法评估。你可以传入10个参数。
     
    QGenericArgument 和 QGenericReturnArgument 是内部助手类。因为信号和槽可以动态调用,你必须使用 Q_ARG() 和 Q_RETURN_ARG() 宏把参数括起来。Q_ARG() 接收参数类型和常量参数,Q_RETURN_ARG() 接收参数类型和非常量参数。
    你只需向此函数传递信号或者槽的名称,而非整个参数签名。例如,要QThread中异步调用quit(),使用下面代码:
    QMetaObject::invokeMethod(thread, "quit", Qt::QueuedConnection);

    异步函数调用,参数必须使用Qt 元对象系统已知类型,因为Qt 需要在幕后复制参数并存储。如果你使用队列连接会出现错误提示:

    QMetaObject::invokeMethod:: Unable to handle unregistered datatype 'MyType'

    在调用 invokeMethod()方法前,调用 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”槽没有按照规定顺序收到参数,本次调用失败。

    注意:此函数线程安全

    查看  Q_ARG (),  Q_RETURN_ARG (),  qRegisterMetaType (), 和  QMetaMethod::invoke ().

    bool QMetaObject::invokeMethod(QObject *obj, const char *member, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(0), 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())

    此函数重载invokeMethod()
    这个重载总是使用  Qt::AutoConnection 调用成员
    注意:此函数线程安全

    bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericArgument val0 = QGenericArgument(0), 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())

    此函数重载invokeMethod()
    如果对返回值不感兴趣,可使用此重载。
    注意:此函数线程安全

    bool QMetaObject::invokeMethod(QObject *obj,char *member, 

    QGenericArgument val0 =QGenericArgument(0),

     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())

    此函数重载invokeMethod()
    这个重载使用 Qt::AutoConnection 连接类型调用成员,并忽略返回值。
    注意:此函数线程安全

    template <typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr)

    这是一个重载函数
    在上下文事件循环中使用  Qt::AutoConnection 连接类型 调用函数。参数function可以是一个函数题,或成员函数指针。如果函数可以调用返回true。找不到函数或参数不匹配返回 false。函数返回值放在ret。
    注意:此函数线程安全
    此函数在 Qt 5.10 引入

    QMetaMethod QMetaObject::method(int index) const

    返回索引方法的元数据。
    查看  methodCount (),  methodOffset (), 和  indexOfMethod ().

    int QMetaObject::methodCount() const

    返回方法数量,包括每个基类提供的方法数量。信号和槽,也作为普通函数参与计数。
    下面代码,将类中method特性传递给QStringList类型的列表:
    const QMetaObject* metaObject = obj->metaObject();
    QStringList methods;
    for (int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
        methods << QString::fromLatin1(metaObject->method(i).methodSignature());
    查看    method (),  methodOffset (), 和  indexOfMethod ().

    int QMetaObject::methodOffset() const方法

    返回类中的方法偏移量,即第一个方法的索引位置。
    偏移量是父类方法的总和(总是正数,因为QObject 有 deleteLater()槽和destroyed()信号)。
    查看    method (),  methodCount (), 和  indexOfMethod ().

    QObject *QMetaObject::newInstance(QGenericArgument val0 = QGenericArgument(nullptr), 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()) const

    构造类的实例,可以传递10个参数。返回新对象,如果没有匹配成功,返回nullptr。
    注意:只有用 Q_INVOKABLE 声明符修饰的构造函数才能通过元对象系统使用。
    该方法 在 Qt 4.5 引入。
    查看    Q_ARG () 和  constructor ().

    [static] QByteArray QMetaObject::normalizedSignature(const char *method)

    规范化方法签名
    Qt 使用规范化签名来决定给定的信号和槽是否兼容。规范化将空格减少到最小,将 ‘const’ 前移到适当的位置,从值类型中移除‘const’并将const引用替换为值。
    查看  checkConnectArgs () 和  normalizedType ().

    [static] QByteArray QMetaObject::normalizedType(const char *type)

    规范化类型
    如果规范化和   QMetaObject::normalizedSignature () 类似
    例子:
    QByteArray normType = QMetaObject::normalizedType(" int    const  *");
    // normType is now "const int*"
    
    
    该方法 Qt 4.2 引入
    查看  normalizedSignature ().

    QMetaProperty QMetaObject::property(int index) const

    返回索引属性的元数据,如果没找到,返回null
    查看  propertyCount (),  propertyOffset (), 和  indexOfProperty ().

    int QMetaObject::propertyCount() const

    返回类中属性的数量,包括基类的属性数量。
    如下代码,获取指定类的属性特性,存到QStringList列表:
    const QMetaObject* metaObject = obj->metaObject();
    QStringList properties;
    for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
        properties << QString::fromLatin1(metaObject->property(i).name());

    查看  property(), propertyOffset(), 和 indexOfProperty().


    int QMetaObject::propertyOffset() const

    返回属性偏移量,即第一个属性的索引位置。
    偏移量是基类属性的总和(总是正数,因为QObject有 name() 属性)。
    查看  property (),  propertyCount (), and  indexOfProperty ().

    const QMetaObject *QMetaObject::superClass() const

    返回基类元对象,如果没有返回nullptr
    查看 className()。

    QMetaProperty QMetaObject::userProperty() const

    返回将用户标记设置为true的属性
    该方法在 Qt 4.2 引入
    查看    QMetaProperty::isUser ()。

    宏 文档

    QGenericArgument Q_ARG(Type, const Type &value)

    这个宏接收一个类型,和该类型的值,返回一个 可以传入QMetaObject::invokeMethod() 的QGenericArgument 对象。
    查看  Q_RETURN_ARG ().

    QGenericReturnArgument Q_RETURN_ARG(Type, Type &value)

    这个宏接收一个类型和,该类型非常量值。返回一个可以传入QMetaObject::invokeMethod() 的QGenericReturnArgument 对象。
    查看   Q_ARG ().

     
    展开全文
  • 用于生锈的QMetaObject板条箱qmetaobject板条箱是用于将生锈的对象暴露于Qt和QML的板条箱。 目标Rust程序宏(用于Rust的QMetaObject板条箱)qmetaobject箱是用于将锈对象暴露于Qt和QML的板条箱。Objective Rust程序...
  • QMetaObject 的使用说明

    千次阅读 2020-03-28 22:48:59
    在Q_OBJECT的代码中,QMetaObject是一个很重要的角色,字面意思就称为元对象吧,有道词典的解释 可以看看Qt助手的解释 The QMetaObject class contains meta-information about Qt objects. QMetaObject...

            在Q_OBJECT的代码中,QMetaObject是一个很重要的角色,字面意思就称为元对象吧,有道词典的解释

            可以看看Qt助手的解释

            The QMetaObject class contains meta-information about Qt objects.

            QMetaObject类包含关于Qt对象的元信息。

            The Qt Meta-Object System in Qt is responsible for the signals and slots inter-object communication mechanism, runtime type information, and the Qt property system. A single QMetaObject instance is created for each QObject subclass that is used in an application, and this instance stores all the meta-information for the QObject subclass. This object is available as QObject::metaObject().

            Qt中的Qt元对象系统负责信号和插槽的对象间通信机制、运行时类型信息和Qt属性系统。为应用程序中使用的每个QObject子类创建一个QMetaObject实例,该实例存储QObject子类的所有元信息。这个对象可以作为QObject::metaObject()使用。

           This class is not normally required for application programming, but it is useful if you write meta-applications, such as scripting engines or GUI builders.

           这个类通常不是应用程序编程所需要的,但是如果您编写元应用程序(例如脚本引擎或GUI构建器),它就非常有用。

           The functions you are most likely to find useful are these:

          The index functions indexOfConstructor(), indexOfMethod(), indexOfEnumerator(), and indexOfProperty() map names of constructors, member functions, enumerators, or properties to indexes in the meta-object. For example, Qt uses indexOfMethod() internally when you connect a signal to a slot.

           索引函数indexOfConstructor()、indexOfMethod()、indexOfEnumerator()和indexOfProperty()将构造函数、成员函数、枚举器或属性的名称映射到元对象中的索引。例如,当您将信号连接到插槽时,Qt在内部使用indexOfMethod()。

          Classes can also have a list of name--value pairs of additional class information, stored in QMetaClassInfo objects. The number of pairs is returned by classInfoCount(), single pairs are returned by classInfo(), and you can search for pairs with indexOfClassInfo().

          类还可以有一个名称—附加类信息的值对列表,存储在QMetaClassInfo对象中。对的数量由classInfoCount()返回,单个对由classInfo()返回,您可以使用indexOfClassInfo()搜索对。

           Note: Operations that use the meta object system are generally thread- safe, as QMetaObjects are typically static read-only instances generated at compile time. However, if meta objects are dynamically modified by the application (for instance, when using QQmlPropertyMap), then the application has to explicitly synchronize access to the respective meta object.

           注意:使用元对象系统的操作通常是线程安全的,因为QMetaObjects通常是在编译时生成的静态只读实例。但是,如果应用程序动态地修改了元对象(例如,在使用QQmlPropertyMap时),则应用程序必须显式地同步对相应元对象的访问。

           可以在代码中测试,根据第二段翻译,为应用程序中使用的每个QObject子类创建一个QMetaObject实例,该实例存储QObject子类的所有元信息。这个对象可以作为QObject::metaObject()使用。

            参看Q_OBJECT宏的代码可知:

    #define Q_OBJECT \
    public: \
        QT_WARNING_PUSH \
        Q_OBJECT_NO_OVERRIDE_WARNING \
        static const QMetaObject staticMetaObject; \
        virtual const QMetaObject *metaObject() const; \
        virtual void *qt_metacast(const char *); \
        virtual int qt_metacall(QMetaObject::Call, int, void **); \
        QT_TR_FUNCTIONS \
    private: \
        Q_OBJECT_NO_ATTRIBUTES_WARNING \
        Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
        QT_WARNING_POP \
        struct QPrivateSignal {}; \
        QT_ANNOTATE_CLASS(qt_qobject, "")

             我们可以直接使用staticMetaObject来调用QMetaObject的相关信息

    qDebug() << staticMetaObject.className();   //当前类的名字
    qDebug() << staticMetaObject.superClass()->className();  //父类名称
    qDebug() << staticMetaObject.constructorCount();  //构造函数个数
    qDebug() << staticMetaObject.methodCount();   //方法个数

             输出如下:

             没毛病,我的类如下:

    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
    
    private slots:
        void onButton();
        void slot2(int data);
    
    signals:
        void sig1();
        void sig2();
        void sig3();
    
    private:
        Ui::Widget *ui;
    };


           QMetaObject是一个结构体,代码如下:

    struct Q_CORE_EXPORT QMetaObject
    {
        class Connection;
        const char *className() const;
        const QMetaObject *superClass() const;
    
        bool inherits(const QMetaObject *metaObject) const Q_DECL_NOEXCEPT;
        QObject *cast(QObject *obj) const;
        const QObject *cast(const QObject *obj) const;
    
    #if !defined(QT_NO_TRANSLATION) || defined(Q_CLANG_QDOC)
        QString tr(const char *s, const char *c, int n = -1) const;
    #endif // QT_NO_TRANSLATION
    
        int methodOffset() const;
        int enumeratorOffset() const;
        int propertyOffset() const;
        int classInfoOffset() const;
    
        int constructorCount() const;
        int methodCount() const;
        int enumeratorCount() const;
        int propertyCount() const;
        int classInfoCount() const;
    
        int indexOfConstructor(const char *constructor) const;
        int indexOfMethod(const char *method) const;
        int indexOfSignal(const char *signal) const;
        int indexOfSlot(const char *slot) const;
        int indexOfEnumerator(const char *name) const;
        int indexOfProperty(const char *name) const;
        int indexOfClassInfo(const char *name) const;
    
        QMetaMethod constructor(int index) const;
        QMetaMethod method(int index) const;
        QMetaEnum enumerator(int index) const;
        QMetaProperty property(int index) const;
        QMetaClassInfo classInfo(int index) const;
        QMetaProperty userProperty() const;
    
        static bool checkConnectArgs(const char *signal, const char *method);
        static bool checkConnectArgs(const QMetaMethod &signal,
                                     const QMetaMethod &method);
        static QByteArray normalizedSignature(const char *method);
        static QByteArray normalizedType(const char *type);
    
        // internal index-based connect
        static Connection connect(const QObject *sender, int signal_index,
                            const QObject *receiver, int method_index,
                            int type = 0, int *types = nullptr);
        // internal index-based disconnect
        static bool disconnect(const QObject *sender, int signal_index,
                               const QObject *receiver, int method_index);
        static bool disconnectOne(const QObject *sender, int signal_index,
                                  const QObject *receiver, int method_index);
        // internal slot-name based connect
        static void connectSlotsByName(QObject *o);
    
        // internal index-based signal activation
        static void activate(QObject *sender, int signal_index, void **argv);
        static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
        static void activate(QObject *sender, int signal_offset, int local_signal_index, void **argv);
    
        static bool invokeMethod(QObject *obj, const char *member,
                                 Qt::ConnectionType,
                                 QGenericReturnArgument ret,
                                 QGenericArgument val0 = QGenericArgument(nullptr),
                                 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());
    
        static inline bool invokeMethod(QObject *obj, const char *member,
                                 QGenericReturnArgument ret,
                                 QGenericArgument val0 = QGenericArgument(nullptr),
                                 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())
        {
            return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3,
                    val4, val5, val6, val7, val8, val9);
        }
    
        static inline bool invokeMethod(QObject *obj, const char *member,
                                 Qt::ConnectionType type,
                                 QGenericArgument val0 = QGenericArgument(nullptr),
                                 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())
        {
            return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2,
                                     val3, val4, val5, val6, val7, val8, val9);
        }
    
        static inline bool invokeMethod(QObject *obj, const char *member,
                                 QGenericArgument val0 = QGenericArgument(nullptr),
                                 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())
        {
            return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0,
                    val1, val2, val3, val4, val5, val6, val7, val8, val9);
        }
    
    #ifdef Q_CLANG_QDOC
        template<typename Functor, typename FunctorReturnType>
        static bool invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr);
        template<typename Functor, typename FunctorReturnType>
        static bool invokeMethod(QObject *context, Functor function, FunctorReturnType *ret);
    #else
    
        // invokeMethod() for member function pointer
        template <typename Func>
        static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
                                       && !std::is_convertible<Func, const char*>::value
                                       && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
        invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
                     Func function,
                     Qt::ConnectionType type = Qt::AutoConnection,
                     typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
        {
            return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), type, ret);
        }
    
        template <typename Func>
        static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
                                       && !std::is_convertible<Func, const char*>::value
                                       && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
        invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
                     Func function,
                     typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
        {
            return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), Qt::AutoConnection, ret);
        }
    
        // invokeMethod() for function pointer (not member)
        template <typename Func>
        static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
                                       && !std::is_convertible<Func, const char*>::value
                                       && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
        invokeMethod(QObject *context, Func function,
                     Qt::ConnectionType type = Qt::AutoConnection,
                     typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
        {
            return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), type, ret);
        }
    
        template <typename Func>
        static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
                                       && !std::is_convertible<Func, const char*>::value
                                       && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
        invokeMethod(QObject *context, Func function,
                     typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
        {
            return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), Qt::AutoConnection, ret);
        }
    
        // invokeMethod() for Functor
        template <typename Func>
        static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
                                       && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
                                       && !std::is_convertible<Func, const char*>::value, bool>::type
        invokeMethod(QObject *context, Func function,
                     Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr)
        {
            return invokeMethodImpl(context,
                                    new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
                                    type,
                                    ret);
        }
    
        template <typename Func>
        static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
                                       && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
                                       && !std::is_convertible<Func, const char*>::value, bool>::type
        invokeMethod(QObject *context, Func function, typename std::result_of<Func()>::type *ret)
        {
            return invokeMethodImpl(context,
                                    new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
                                    Qt::AutoConnection,
                                    ret);
        }
    
    #endif
    
        QObject *newInstance(QGenericArgument val0 = QGenericArgument(nullptr),
                             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()) const;
    
        enum Call {
            InvokeMetaMethod,
            ReadProperty,
            WriteProperty,
            ResetProperty,
            QueryPropertyDesignable,
            QueryPropertyScriptable,
            QueryPropertyStored,
            QueryPropertyEditable,
            QueryPropertyUser,
            CreateInstance,
            IndexOfMethod,
            RegisterPropertyMetaType,
            RegisterMethodArgumentMetaType
        };
    
        int static_metacall(Call, int, void **) const;
        static int metacall(QObject *, Call, int, void **);
    
        struct { // private data
            const QMetaObject *superdata;
            const QByteArrayData *stringdata;
            const uint *data;
            typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
            StaticMetacallFunction static_metacall;
            const QMetaObject * const *relatedMetaObjects;
            void *extradata; //reserved for future use
        } d;
    
    private:
        static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret);
    };

    展开全文
  • QMetaObject分析

    2015-06-02 19:06:48
    Q_OBJECT 宏 在QObject子类中,包含Q_OBJECT宏可以使用Qt的信号槽特性。 class showObject : public QObject... const QMetaObject showObject::staticMetaObject; // 每一个QObject派生的子类都包含有一个静态的QMeta
    • Q_OBJECT 宏
      在QObject子类中,包含Q_OBJECT宏可以使用Qt的信号槽特性。
    class showObject : public QObject
    {
        Q_OBJECT
        ....
    }
    宏展开后会出现:
        const QMetaObject showObject::staticMetaObject; // 每一个QObject派生的子类都包含有一个静态的QMetaObject对象
    private:    
        Q_DECL_HIDDEN_STATIC_METACALL 
        static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
    • QMetaObject 属性
    struct { // private data
            const QMetaObject *superdata;
            const QByteArrayData *stringdata;
            const uint *data;
            typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
            StaticMetacallFunction static_metacall; // (核心)指向子类函数showObject::qt_static_metacall
            const QMetaObject **relatedMetaObjects;
            void *extradata; //reserved for future use
        } d;
    • QMetaObject 函数
    /*
        \since 4.5
        Constructs a new instance of this class. You can pass up to ten arguments
        (\a val0, \a val1, \a val2, \a val3, \a val4, \a val5, \a val6, \a val7,
        \a val8, and \a val9) to the constructor. Returns the new object, or 0 if
        no suitable constructor is available.
    
        Note that only constructors that are declared with the Q_INVOKABLE
        modifier are made available through the meta-object system.
    
        \sa Q_ARG(), constructor()
    */
    QObject *QMetaObject::newInstance(QGenericArgument val0,
                                      QGenericArgument val1,
                                      QGenericArgument val2,
                                      QGenericArgument val3,
                                      QGenericArgument val4,
                                      QGenericArgument val5,
                                      QGenericArgument val6,
                                      QGenericArgument val7,
                                      QGenericArgument val8,
                                      QGenericArgument val9) const
    此方法在showObject 子类的构造函数使用/* Q_INVOKABLE */宏修饰的时候有效
    public:
        Q_INVOKABLE explicit showObject(QObject *parent = 0);
    
    使用:
        const QMetaObject *meta = &showObject::staticMetaObject;
        QObject *o = meta->newInstance();
        delete o;
    原理:
        QMetaObject::newInstance
        {
            .....
            QObject *returnValue = 0; 
            // returnValue 传入param
            void *param[] = {&returnValue, val0.data(),... val9.data()};
            // 关键在这里
            QMetaObject::static_metacall(CreateInstance, idx, param)
            return returnValue;
        }
    
        int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
        {
            // 这里又调用
            d.static_metacall(0, cl, idx, argv);// 指向 showObject::qt_static_metacall
        }
    
        // 最终实现之地,终于找到了
        showObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
        {
            if (_c == QMetaObject::CreateInstance) {
            switch (_id) {
            // 终于找到 new 了,从此多了一种动态创建showObject的方法,就是使用 QMetaObject::newInstance
            case 0: { showObject *_r = new showObject((*reinterpret_cast< QObject*(*)>(_a[1])));
                if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
            case 1: { showObject *_r = new showObject();
                if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
            }
        }
        }

    // 未完待续。。。

    展开全文
  • Qt--QMetaObject

    千次阅读 2017-11-15 10:58:42
    QMetaObject接口分析上一节中我们概述了Meta-Object Model的架构,它通过提供了一个QObject的基类,使用Q_OBJECT宏,这样moc编译器就会自动帮我们生成带有QMetaObject记录了元信息的源码。这节我们看下QMetaObject...

    QMetaObject接口分析

    上一节中我们概述了Meta-Object Model的架构,它通过提供了一个QObject的基类,使用Q_OBJECT宏,这样moc编译器就会自动帮我们生成带有QMetaObject记录了元信息的源码。

    这节我们看下QMetaObject提供了哪些接口去获取或使用这些元信息

    上源代码:

    struct Q_CORE_EXPORT QMetaObject
    {
        class Connection;
        const char *className() const;
        const QMetaObject *superClass() const;
    
        bool inherits(const QMetaObject *metaObject) const Q_DECL_NOEXCEPT;
        QObject *cast(QObject *obj) const;
        const QObject *cast(const QObject *obj) const;
    
    #ifndef QT_NO_TRANSLATION
        QString tr(const char *s, const char *c, int n = -1) const;
    #endif // QT_NO_TRANSLATION
    
        int methodOffset() const;
        int enumeratorOffset() const;
        int propertyOffset() const;
        int classInfoOffset() const;
    
        int constructorCount() const;
        int methodCount() const;
        int enumeratorCount() const;
        int propertyCount() const;
        int classInfoCount() const;
    
        int indexOfConstructor(const char *constructor) const;
        int indexOfMethod(const char *method) const;
        int indexOfSignal(const char *signal) const;
        int indexOfSlot(const char *slot) const;
        int indexOfEnumerator(const char *name) const;
        int indexOfProperty(const char *name) const;
        int indexOfClassInfo(const char *name) const;
    
        QMetaMethod constructor(int index) const;
        QMetaMethod method(int index) const;
        QMetaEnum enumerator(int index) const;
        QMetaProperty property(int index) const;
        QMetaClassInfo classInfo(int index) const;
        QMetaProperty userProperty() const;
    
        static bool checkConnectArgs(const char *signal, const char *method);
        static bool checkConnectArgs(const QMetaMethod &signal,
                                     const QMetaMethod &method);
        static QByteArray normalizedSignature(const char *method);
        static QByteArray normalizedType(const char *type);
    
        // internal index-based connect
        static Connection connect(const QObject *sender, int signal_index,
                            const QObject *receiver, int method_index,
                            int type = 0, int *types = Q_NULLPTR);
        // internal index-based disconnect
        static bool disconnect(const QObject *sender, int signal_index,
                               const QObject *receiver, int method_index);
        static bool disconnectOne(const QObject *sender, int signal_index,
                                  const QObject *receiver, int method_index);
        // internal slot-name based connect
        static void connectSlotsByName(QObject *o);
    
        // internal index-based signal activation
        static void activate(QObject *sender, int signal_index, void **argv);
        static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
        static void activate(QObject *sender, int signal_offset, int local_signal_index, void **argv);
    
        static bool invokeMethod(QObject *obj, const char *member,
                                 Qt::ConnectionType,
                                 QGenericReturnArgument ret,
                                 QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
                                 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());
    
        static inline bool invokeMethod(QObject *obj, const char *member,
                                 QGenericReturnArgument ret,
                                 QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
                                 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())
        {
            return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3,
                    val4, val5, val6, val7, val8, val9);
        }
    
        static inline bool invokeMethod(QObject *obj, const char *member,
                                 Qt::ConnectionType type,
                                 QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
                                 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())
        {
            return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2,
                                     val3, val4, val5, val6, val7, val8, val9);
        }
    
        static inline bool invokeMethod(QObject *obj, const char *member,
                                 QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
                                 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())
        {
            return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0,
                    val1, val2, val3, val4, val5, val6, val7, val8, val9);
        }
    
        QObject *newInstance(QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
                             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()) const;
    
        enum Call {
            InvokeMetaMethod,
            ReadProperty,
            WriteProperty,
            ResetProperty,
            QueryPropertyDesignable,
            QueryPropertyScriptable,
            QueryPropertyStored,
            QueryPropertyEditable,
            QueryPropertyUser,
            CreateInstance,
            IndexOfMethod,
            RegisterPropertyMetaType,
            RegisterMethodArgumentMetaType
        };
    
        int static_metacall(Call, int, void **) const;
        static int metacall(QObject *, Call, int, void **);
    
        struct { // private data
            const QMetaObject *superdata;
            const QByteArrayData *stringdata;
            const uint *data;
            typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
            StaticMetacallFunction static_metacall;
            const QMetaObject * const *relatedMetaObjects;
            void *extradata; //reserved for future use
        } d;
    };

    从接口命名就可以简单分析出可以获取类名、类信息、方法(细分为信号、槽、构造函数、一般函数)、属性、枚举等信息

    枚举类型Call中实际给出了可以进行的操作,包括调用方法、读写属性、查询属性各种特性、创建实例、注册属性类型、注册方法参数类型

    enum Call {
       InvokeMetaMethod,
       ReadProperty,
       WriteProperty,
       ResetProperty,
       QueryPropertyDesignable,
       QueryPropertyScriptable,
       QueryPropertyStored,
       QueryPropertyEditable,
       QueryPropertyUser,
       CreateInstance,
       IndexOfMethod,
       RegisterPropertyMetaType,
       RegisterMethodArgumentMetaType
    };
    

    还给出了activate(发射信号实际调用的函数),connect(连接信号与槽),disconnect(断连信号与槽)的接口

    QMetaObject实现分析

    获取超类QMetaObject 指针

    inline const QMetaObject *QMetaObject::superClass() const
    { return d.superdata; }
    

    获取类名
    先看一个转换函数

    static inline const QMetaObjectPrivate *priv(const uint* data)
    { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
    

    这个函数将uint*指针转化为QMetaObjectPrivate ,也就是说QMetaObject中的d.data实际就是一个QMetaObjectPrivate 结构体指针

    那么让我们看看QMetaObjectPrivate 这个结构体

    struct QMetaObjectPrivate
    {
        enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus
    
        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 
        //...
    }
    

    原来这个结构体就是对应我们上节的qt_meta_data_MyClass整型数组,里面记录了类、方法、属性等名称字符串的索引、参数的类型信息等

    那么再来看获取类名的步骤

    const char *QMetaObject::className() const
    {
        return objectClassName(this);
    }
    
    static inline const char *objectClassName(const QMetaObject *m)
    {
        return rawStringData(m, priv(m->d.data)->className);
    }
    
    static inline const char *rawStringData(const QMetaObject *mo, int index)
    {
        return stringData(mo, index).data();
    }
    
    static inline const QByteArray stringData(const QMetaObject *mo, int index)
    {
        const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
        return data;
    }
    

    实际就是通过d.data中记录的索引找到d.stringdata中的字符串,即mo->d.stringdata[index]

    判断继承关系

    bool QMetaObject::inherits(const QMetaObject *metaObject)
    {
        const QMetaObject *m = this;
        do {
            if (metaObject == m)
                return true;
        } while ((m = m->d.superdata));
        return false;
    }
    

    就是循环比较超类的QMetaObject是否等于这个metaObject

    方法偏移

    int QMetaObject::methodOffset() const
    {
        int offset = 0;
        const QMetaObject *m = d.superdata;
        while (m) {
            offset += priv(m->d.data)->methodCount;
            m = m->d.superdata;
        }
        return offset;
    }
    

    返回所有基类的方法数之和

    方法总数

    int QMetaObject::methodCount() const
    {
        int n = priv(d.data)->methodCount;
        const QMetaObject *m = d.superdata;
        while (m) {
            n += priv(m->d.data)->methodCount;
            m = m->d.superdata;
        }
        return n;
    }
    

    返回自身和基类所有的方法数之和

    方法索引

    int QMetaObject::indexOfMethod(const char *method) const
    {
        const QMetaObject *m = this;
        int i;
        QArgumentTypeArray types;
        QByteArray name = QMetaObjectPrivate::decodeMethodSignature(method, types);
        i = indexOfMethodRelative<0>(&m, name, types.size(), types.constData());
        if (i >= 0)
            i += m->methodOffset();
        return i;
    }
    

    说明下decodeMethodSignature用来解析一个函数字符串如func(int a, QMap<int, QString> b),返回值是函数名func,types中记录参数类型

    然后通过indexOfMethodRelative去匹配是否有函数名和参数个数,参数类型都一样的,有就返回索引,最后和方法偏移相加,就是该方法的最终索引

    根据索引获取方法

    QMetaMethod QMetaObject::method(int index) const
    {
        int i = index;
        i -= methodOffset();
        if (i < 0 && d.superdata)
            return d.superdata->method(index);
    
        QMetaMethod result;
        if (i >= 0 && i < priv(d.data)->methodCount) {
            result.mobj = this;
            result.handle = priv(d.data)->methodData + 5*i;
        }
        return result;
    }
    

    返回的是一个QMetaMethod类,Qt提供了QMetaClassInfo,QMetaMethod、QMetaProperty、QMetaEnum来包装这些元信息和对其的一些操作,比如QMetaMethod就提供了name、parameterTypes、invoke等接口。

    其它QMetaObejct中classinfo、property、enum的接口与上面method的接口实现类似。

    继续探索QMetaOjbect中invokeMethod接口的实现

    bool QMetaObject::invokeMethod(QObject *obj,
                                   const char *member,
                                   Qt::ConnectionType type,
                                   QGenericReturnArgument ret,
                                   QGenericArgument val0,
                                   QGenericArgument val1,
                                   QGenericArgument val2,
                                   QGenericArgument val3,
                                   QGenericArgument val4,
                                   QGenericArgument val5,
                                   QGenericArgument val6,
                                   QGenericArgument val7,
                                   QGenericArgument val8,
                                   QGenericArgument val9)
    {
        if (!obj)
            return false;
    
        QVarLengthArray<char, 512> sig;
        int len = qstrlen(member);
        if (len <= 0)
            return false;
        sig.append(member, len);
        sig.append('(');
    
        const char *typeNames[] = {ret.name(), val0.name(), val1.name(), val2.name(), val3.name(),
                                   val4.name(), val5.name(), val6.name(), val7.name(), val8.name(),
                                   val9.name()};
    
        int paramCount;
        for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
            len = qstrlen(typeNames[paramCount]);
            if (len <= 0)
                break;
            sig.append(typeNames[paramCount], len);
            sig.append(',');
        }
        if (paramCount == 1)
            sig.append(')'); // no parameters
        else
            sig[sig.size() - 1] = ')';
        sig.append('\0');
    
        const QMetaObject *meta = obj->metaObject();
        int idx = meta->indexOfMethod(sig.constData());
        if (idx < 0) {
            QByteArray norm = QMetaObject::normalizedSignature(sig.constData());
            idx = meta->indexOfMethod(norm.constData());
        }
    
        if (idx < 0 || idx >= meta->methodCount()) {
            // This method doesn't belong to us; print out a nice warning with candidates.
            qWarning("QMetaObject::invokeMethod: No such method %s::%s%s",
                     meta->className(), sig.constData(), findMethodCandidates(meta, member).constData());
            return false;
        }
        QMetaMethod method = meta->method(idx);
        return method.invoke(obj, type, ret,
                             val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
    }

    嗯,就是根据函数名、函数返回类型、参数类型,构建函数签名sig,然后通过indexOfMethod获取索引号,再通过method得到QMetaMethod ,最后实际调用的是QMetaMethod 的invoke接口

    bool QMetaMethod::invoke(QObject *object,
                             Qt::ConnectionType connectionType,
                             QGenericReturnArgument returnValue,
                             QGenericArgument val0,
                             QGenericArgument val1,
                             QGenericArgument val2,
                             QGenericArgument val3,
                             QGenericArgument val4,
                             QGenericArgument val5,
                             QGenericArgument val6,
                             QGenericArgument val7,
                             QGenericArgument val8,
                             QGenericArgument val9) const
    {
        if (!object || !mobj)
            return false;
    
        Q_ASSERT(mobj->cast(object));
    
        // check return type
        if (returnValue.data()) {
            const char *retType = typeName();
            if (qstrcmp(returnValue.name(), retType) != 0) {
                // normalize the return value as well
                QByteArray normalized = QMetaObject::normalizedType(returnValue.name());
                if (qstrcmp(normalized.constData(), retType) != 0) {
                    // String comparison failed, try compare the metatype.
                    int t = returnType();
                    if (t == QMetaType::UnknownType || t != QMetaType::type(normalized))
                        return false;
                }
            }
        }
    
        // check argument count (we don't allow invoking a method if given too few arguments)
        const char *typeNames[] = {
            returnValue.name(),
            val0.name(),
            val1.name(),
            val2.name(),
            val3.name(),
            val4.name(),
            val5.name(),
            val6.name(),
            val7.name(),
            val8.name(),
            val9.name()
        };
        int paramCount;
        for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
            if (qstrlen(typeNames[paramCount]) <= 0)
                break;
        }
        if (paramCount <= QMetaMethodPrivate::get(this)->parameterCount())
            return false;
    
        // check connection type
        QThread *currentThread = QThread::currentThread();
        QThread *objectThread = object->thread();
        if (connectionType == Qt::AutoConnection) {
            connectionType = currentThread == objectThread
                             ? Qt::DirectConnection
                             : Qt::QueuedConnection;
        }
    
    #ifdef QT_NO_THREAD
        if (connectionType == Qt::BlockingQueuedConnection) {
            connectionType = Qt::DirectConnection;
        }
    #endif
    
        // invoke!
        void *param[] = {
            returnValue.data(),
            val0.data(),
            val1.data(),
            val2.data(),
            val3.data(),
            val4.data(),
            val5.data(),
            val6.data(),
            val7.data(),
            val8.data(),
            val9.data()
        };
        int idx_relative = QMetaMethodPrivate::get(this)->ownMethodIndex();
        int idx_offset =  mobj->methodOffset();
        Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6);
        QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;
    
        if (connectionType == Qt::DirectConnection) {
            if (callFunction) {
                callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
                return true;
            } else {
                return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) < 0;
            }
        } else if (connectionType == Qt::QueuedConnection) {
            if (returnValue.data()) {
                qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
                         "queued connections");
                return false;
            }
    
            int nargs = 1; // include return type
            void **args = (void **) malloc(paramCount * sizeof(void *));
            Q_CHECK_PTR(args);
            int *types = (int *) malloc(paramCount * sizeof(int));
            Q_CHECK_PTR(types);
            types[0] = 0; // return type
            args[0] = 0;
    
            for (int i = 1; i < paramCount; ++i) {
                types[i] = QMetaType::type(typeNames[i]);
                if (types[i] != QMetaType::UnknownType) {
                    args[i] = QMetaType::create(types[i], param[i]);
                    ++nargs;
                } else if (param[i]) {
                    // Try to register the type and try again before reporting an error.
                    void *argv[] = { &types[i], &i };
                    QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType,
                                          idx_relative + idx_offset, argv);
                    if (types[i] == -1) {
                        qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
                                typeNames[i]);
                        for (int x = 1; x < i; ++x) {
                            if (types[x] && args[x])
                                QMetaType::destroy(types[x], args[x]);
                        }
                        free(types);
                        free(args);
                        return false;
                    }
                }
            }
    
            QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
                                                            0, -1, nargs, types, args));
        } else { // blocking queued connection
    #ifndef QT_NO_THREAD
            if (currentThread == objectThread) {
                qWarning("QMetaMethod::invoke: Dead lock detected in "
                            "BlockingQueuedConnection: Receiver is %s(%p)",
                            mobj->className(), object);
            }
    
            QSemaphore semaphore;
            QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
                                                            0, -1, 0, 0, param, &semaphore));
            semaphore.acquire();
    #endif // QT_NO_THREAD
        }
        return true;
    }

    代码首先检查返回值的类型是否正确;
    再检查参数的个数是否匹配;
    再依据当前线程和被调对象所属 线程来调整connnection type;
    如果是Qt::DirectConnection,直接调用

    QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, methodIndex, param)
    

    如果是Qt::QueuedConnection,即异步调用

    QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,0, -1, nargs, types, args));
    

    当然还有一种Qt::BlockingQueuedConnection阻塞式异步调用,通过QSemaphore信号量来等待调用结束后再继续执行

    QSemaphore semaphore;
    QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction, 0, -1, 0, 0, param, &semaphore));
    semaphore.acquire();
    

    关于异步调用,是在对象所属线程中的事件循环中,从事件队列中取得这个事件时,再去调用这个函数

    int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
    {
        if (object->d_ptr->metaObject)
            return object->d_ptr->metaObject->metaCall(object, cl, idx, argv);
        else
            return object->qt_metacall(cl, idx, argv);
    }
    

    如果是QObject类,那就直接调用metaCall,否则就是QObject的派生类,调用qt_metacall,就是moc文件自动生成的代码了。

    moc_myclass.cpp参考上一章,下面回顾下qt_metacall的代码加深理解

    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) {
            if (_id < 3)
                qt_static_metacall(this, _c, _id, _a);
            _id -= 3;
        } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
            if (_id < 3)
                *reinterpret_cast<int*>(_a[0]) = -1;
            _id -= 3;
        }
    #ifndef QT_NO_PROPERTIES
       else if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty
                || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {
            qt_static_metacall(this, _c, _id, _a);
            _id -= 1;
        } else if (_c == QMetaObject::QueryPropertyDesignable) {
            _id -= 1;
        } else if (_c == QMetaObject::QueryPropertyScriptable) {
            _id -= 1;
        } else if (_c == QMetaObject::QueryPropertyStored) {
            _id -= 1;
        } else if (_c == QMetaObject::QueryPropertyEditable) {
            _id -= 1;
        } else if (_c == QMetaObject::QueryPropertyUser) {
            _id -= 1;
        }
    #endif // QT_NO_PROPERTIES
        return _id;
    }

    可以看到如果是QMetaObject::InvokeMetaMethod,那么将调用

    qt_static_metacall(this, _c, _id, _a);
    
    void MyClass::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
    {
        if (_c == QMetaObject::CreateInstance) {
            switch (_id) {
            case 0: { MyClass *_r = new MyClass((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QObject*(*)>(_a[2])));
                if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
            default: break;
            }
        } else if (_c == QMetaObject::InvokeMetaMethod) {
            MyClass *_t = static_cast<MyClass *>(_o);
            Q_UNUSED(_t)
            switch (_id) {
            case 0: _t->signal1((*reinterpret_cast< int(*)>(_a[1]))); break;
            case 1: { int _r = _t->slot1((*reinterpret_cast< int(*)>(_a[1])));
                if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; }  break;
            case 2: { int _r = _t->method1((*reinterpret_cast< int(*)>(_a[1])));
                if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; }  break;
            default: ;
            }
        } else if (_c == QMetaObject::IndexOfMethod) {
            int *result = reinterpret_cast<int *>(_a[0]);
            void **func = reinterpret_cast<void **>(_a[1]);
            {
                typedef void (MyClass::*_t)(int );
                if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&MyClass::signal1)) {
                    *result = 0;
                    return;
                }
            }
        }
    #ifndef QT_NO_PROPERTIES
        else if (_c == QMetaObject::ReadProperty) {
        } else if (_c == QMetaObject::WriteProperty) {
        } else if (_c == QMetaObject::ResetProperty) {
        }
    #endif // QT_NO_PROPERTIES
    }

    这段代码将调用最终转到我们自己的实现的函数(这里是signal1、slot1、method1)中来。这个函数不仅提供了method的动态调用,而且也提供了property的动态操作方法。可想而知,property的动态调用的实现方式一定和invocalbe method是类似的。

    总结

    通过上一节moc文件分析,和这一节的QMetaObject源码分析,我们应该是对Qt Meta-Object Model有了一个清楚的认识

    • Qt提供了一个QObject的基类
    • Qt扩展了C++语法,提供了Q_OBJECT、Q_INVOKABLE、signals、slots、emit、SIGNAL,SLOT、Q_PROPERT、Q_ENUM、Q_FLAG、Q_CLASSINFO等宏,moc会识别这些宏并生成对应的moc源代码
    • Q_OBJECT宏中声明了QMetaObject的静态对象,QMetaObject中记录了classiofo、method、property、enum,并提供了metacall来操作

    *关于信号与槽机制关键几个接口activate和connect、disconect的实现,见下一节

    展开全文
  • QMetaObject使用

    千次阅读 2015-03-14 15:25:03
    QT的metaobject十分有意思,有了它,QT才能支持Property、信号槽、RTTI。 链接... QMetaObject中的d成员变量存储了metaobject信息 struct { // private da
  • 用于 Rust 的 QMetaObject 板条箱qmetaobject crate 是一个 crate,用于将 Rust 对象暴露给 Qt 和 QML。目标Rust 程序宏(自定义派生)在编译时生成QMetaObject 。使用cpp!绑定主要 Qt 类型cpp!来自cpp crate 的宏。...
  • Qt:QMetaObject结构体

    2021-04-10 21:43:49
    QMetaObject类包含有关Qt对象的元信息。 头文件: #include <QMetaObject> cmake: find_package(Qt6 COMPONENTS Core REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Core) qmake: QT += core ...
  • Qt之QMetaObject::invokeMethod()使用简介

    万次阅读 多人点赞 2019-07-31 19:00:23
    为应用程序中使用的每个QObject子类创建一个QMetaObject实例,此实例存储QObject子类的所有元信息。通过元对象系统,你可以查询QObject的某个派生类的类名、有哪些信号、槽、属性、可调用方法等信息,然后可以使用...
  • qt - QMetaObject 

    2021-01-24 21:57:38
    QMetaObject qt 官方说明 TheQMetaObjectclass contains meta-information about Qt objects. The QtMeta-Object Systemin Qt is responsible for the signals and slots inter-object communication mechanism,...
  • QMetaObject::invokeMethod()

    2020-06-05 11:01:24
    概述 Qt元对象系统是Qt最核心的一个基础特性,元对象系统负责信号和插槽对象间通信机制、运行时类型信息和...为应用程序中使用的每个QObject子类创建一个QMetaObject实例,此实例存储QObject子类的所有元信息。通过元对
  • QMetaObject包含了QObject的元数据,也就是QObject信息的一些描述信息:除了类型信息外, signal&slot信息,Property等。数据都保存在d指针里面( QMetaObject.h 最后有声明d指针变量)。 QMetaObject.h struct Q_...
  • QMetaObject::connectSlotsByName 分析

    千次阅读 2017-07-10 00:54:05
    查看Qt4的一些示例项目的时候,使用设计器打开其UI文件,在文件中竟然找不到signal和slot的连接。但是最终的程序,slot却又能准确的响应信号。打开通过ui文件自动生成的c++文件,... QMetaObject::connectSlotsByName
  • QMetaObject之invokeMethod说明和使用

    万次阅读 2015-09-23 13:41:56
    QMetaObject之invokeMethod 点滴记录(有时间在看看) 分类: QT编程 qtsemaphoreconstructorobjectsignalfunction 目录(?)[+] QMetaObject之invokeMethod 点滴记录 2010-10-18 16:53...
  • QMetaObject::connectSlotsByName: No matching signal for问题的解决方法
  • QMetaObject::invokeMethod()方法应用

    千次阅读 2019-07-14 13:37:33
    前言 Qt信号槽的需要一种机制,就是通过名称以类型安全的方式来间接调用那些槽函数。当调用槽函数时就是通过invokeMethod()方法来...[static] bool QMetaObject::invokeMethod(QObject *obj, const char *membe...
  • 之前一直只知道用connect把...原型是:[static] bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument
  • QMetaObject::invokeMethod(m_pObj,"invokableMethod",Q_ARG(QString,"this is AA!")); class Window : public QWidget { Q_OBJECT public: Window(); void normalMethod(); Q_INVOKABLE void ...
  • 本篇从Qt MetaObject源代码解读相关接口的实现,这些接口都定义于qmetaobject.cpp中。 QMetaObject::className() inline const char *QMetaObject::className() const { return d.stringdata; } 从前一篇...
  • 在做回QMeta调的过程中遇到这个问题,但是有的函数就成功了,有的不行,怎么改都是提示QMetaObject::invokeMethod: No such method QObject* obj = temp.caller; QByteArray slotName = temp.slotName; if(obj != ...
  • 这个问题是没有与 xxx 这个槽函数匹配的信号,但是我做了 QMetaObject::connectSlotsByName(this);, 自动连接。并且确保了函数名和信号名是没有错误的,还是提示我找不到信号源。 解决 通过对比designer生成的文件,...
  • QWT错误static struct QMetaObject const QwtPlot 博客分类:  Qt QWT错误staticstructQMetaObject  使用QWT例子oscilloscope出现如下错误: error LNK2001: unresolved external symbol "public: ...
  • QMetaObject::connectSlotsByName: No matching signal for on_mySectionBtnRClick() 虽然实际功能并没有受影响,但是对于强迫症患者就想把它去掉。 采用显式 connect的方法,又将槽函数的名字起成了“on_控件名_...
  • 最近才看到在一个线程中接收到数据后需要UI线程刷新时,没有在子线程中直接刷新,而是用到了QMetaObject::invokeMethod的方法。 参考文章:Qt带返回值的信号发射方式(使用QMetaObject::invokeMethod) ...
  • QMetaObject之invokeMethod 点滴记录

    千次阅读 2012-10-08 21:29:58
    QMetaObject之invokeMethod 点滴记录 起源 C++ GUI Qt4 编程 一书多线程部分提到invokeMethod的用法 QMetaObject::invokeMethod(label, SLOT(setText(const QString&)), Q_ARG(QString, "Hello")); 而 Qt ...
  • 后续查了一下,可以使用元对象来达到使用QString 来创建类主要功能,通过QMetaObject可以只需要插入类名就可以做一个基础的映射 最后通过map来做一个for循环创建对于上百个类来说比较符合场景 实际是QMetaObject自带...
  • Qt 小例子学习30 - QMetaObject::invokeMethod 骚操作 Widget.h #ifndef WIDGET_H #define WIDGET_H #include "worker.h" #include <QThread> #include <QWidget> class Widget : public QWidget { ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,376
精华内容 2,550
关键字:

qmetaobject