QMetaObject::invokeMethod简单应用

 

1.概要

QMetaObject::invokeMethod 是 Qt 框架中的一个静态方法,用于在运行时调用对象的成员函数。这个方法提供了一种动态调用方法的方式,不需要在编译时知道具体的方法名或参数。QMetaObject::invokeMethod 可以用于调用任何对象的任何可调用方法,包括信号、槽和普通成员函数,只要它们符合一定的条件。

当使用 invokeMethod 时,还需要注意以下几点:

  • 确保对象 object 是有效的,并且其类使用了 Q_OBJECT 宏。
  • 方法 method 必须是可调用的,这通常意味着它是一个槽或使用了 Q_INVOKABLE 宏。
  • 如果方法需要参数,确保提供的参数与方法的期望类型匹配。
  • 如果方法返回值,确保正确处理这个返回值。

2.代码

1.目录结构

2.工程文件

cmake_minimum_required(VERSION 3.14)

project(untitled8 LANGUAGES CXX)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)

add_executable(untitled8
  main.cpp
  MyClass.h
)
target_link_libraries(untitled8 Qt${QT_VERSION_MAJOR}::Core)

include(GNUInstallDirs)
install(TARGETS untitled8
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

3.主函数

#include <QCoreApplication>
#include <QObject>
#include <QMetaObject>
#include <QDebug>
#include "MyClass.h"


int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    MyClass obj;

    QMetaObject::invokeMethod(&obj, "myFunction", Qt::QueuedConnection);

    return app.exec();
}

4.类

#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QMetaObject>
#include <QDebug>

class MyClass : public QObject {
    Q_OBJECT
public:
//public slots:
    Q_INVOKABLE void myFunction() {
        qDebug() << "My function executed!";
    }
};

#endif // MYCLASS_H

3.运行结果

QMetaObject::invokeMethod: No such method QObject::myFunction()

4.实验2 

代码变更

#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QMetaObject>
#include <QDebug>

class MyClass : public QObject {
    //Q_OBJECT
public:
//public slots:
    Q_INVOKABLE void myFunction() {
        qDebug() << "My function executed!";
    }
    Q_INVOKABLE void myFunction2(int a,int b) {
        qDebug() << "My function executed!"<<a<<b;
    }
};

#endif // MYCLASS_H
#include <QCoreApplication>
#include <QObject>
#include <QMetaObject>
#include <QDebug>
#include "MyClass.h"


int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    MyClass obj;

    QMetaObject::invokeMethod(&obj, "myFunction", Qt::QueuedConnection);
    QMetaObject::invokeMethod(&obj, "myFunction2", Q_ARG(int, 1),Q_ARG(int, 2));
    QMetaObject::invokeMethod(&obj, "myFunction");

    return app.exec();
}

运行结果

QMetaObject::invokeMethod: No such method QObject::myFunction()
QMetaObject::invokeMethod: No such method QObject::myFunction2(int,int)
QMetaObject::invokeMethod: No such method QObject::myFunction()

实验结果

类的 Q_OBJECT是否必须:不是必须

Qt::QueuedConnection是否必须:不是必须,但是会影响函数运行所在的线程

添加参数实验:成功

4.说明

QMetaObject::invokeMethod

QMetaObject::invokeMethod 是 Qt 框架中的一个静态方法,用于在运行时调用对象的成员函数。这个方法提供了一种动态调用方法的方式,不需要在编译时知道具体的方法名或参数。QMetaObject::invokeMethod 可以用于调用任何对象的任何可调用方法,包括信号、槽和普通成员函数,只要它们符合一定的条件。

使用条件

要使用 QMetaObject::invokeMethod,需要满足以下条件:

  1. 对象需要有一个有效的元对象:这意味着对象所属的类需要使用 Q_OBJECT 宏。这个宏为类提供了一个元对象,其中包含了关于类的信息,比如方法、信号和槽。

  2. 方法需要是公开(public)的invokeMethod 不能调用私有(private)或受保护(protected)的方法。

  3. 方法需要是槽或者标记为Q_INVOKABLE:在 Qt 中,槽是特殊的成员函数,可以被信号触发。如果一个方法既不是槽也不是通过 Q_INVOKABLE 宏标记的,那么它不能被 invokeMethod 调用。Q_INVOKABLE 宏允许非槽的成员函数被元对象系统调用。

调用方式

QMetaObject::invokeMethod 有几种重载形式,但最常用的一种是:

bool QMetaObject::invokeMethod(QObject *object, const char *method,  
                               QGenericArgument val0 = QGenericArgument(nullptr),  
                               QGenericArgument val1 = QGenericArgument(nullptr),  
                               QGenericArgument val2 = QGenericArgument(nullptr),  
                               QGenericArgument val3 = QGenericArgument(nullptr),  
                               QGenericArgument val4 = QGenericArgument(nullptr),  
                               QGenericArgument val5 = QGenericArgument(nullptr),  
                               QGenericArgument val6 = QGenericArgument(nullptr),  
                               QGenericArgument val7 = QGenericArgument(nullptr),  
                               QGenericArgument val8 = QGenericArgument(nullptr),  
                               QGenericArgument val9 = QGenericArgument(nullptr))
  • object:要调用方法的对象。
  • method:要调用的方法的名称。
  • val0 - val9:方法的参数,最多支持10个。使用 QGenericArgument 类型封装参数。

返回值

invokeMethod 返回一个布尔值,表示方法是否成功调用。如果方法成功被调用,返回 true;如果方法不存在、对象无法找到、参数类型不匹配或方法不是可调用的,返回 false

示例

假设有一个类 MyClass,它有一个槽 mySlot,可以接受两个整数作为参数:

class MyClass : public QObject  
{  
    Q_OBJECT  
public slots:  
    void mySlot(int a, int b) {  
        qDebug() << a << b;  
    }  
};

可以这样使用 invokeMethod

MyClass obj;  
QMetaObject::invokeMethod(&obj, "mySlot", Q_ARG(int, 10), Q_ARG(int, 20));

这行代码将调用 obj 的 mySlot 方法,并传递两个整数参数 10 和 20。

QMetaObject::invokeMethod的几种重载 

QMetaObject::invokeMethod 在 Qt 框架中是一个强大的静态方法,它提供了几种重载形式来适应不同的调用需求。以下是 QMetaObject::invokeMethod 的几种常见重载形式:

  1. 基础重载

    bool QMetaObject::invokeMethod(QObject *object, const char *method,  
                                   Qt::ConnectionType type = Qt::DirectConnection,  
                                   QGenericReturnArgument ret = QGenericReturnArgument(nullptr),  
                                   QGenericArgument val0 = QGenericArgument(nullptr),  
                                   QGenericArgument val1 = QGenericArgument(nullptr),  
                                   ... // 最多到 val9  
                                   )

    这是最常用的重载形式。它允许你指定要调用的对象、方法名、连接类型(同步或异步)、返回值以及最多10个参数。

  2. 无返回值重载

    bool QMetaObject::invokeMethod(QObject *object, const char *method,  
                                   Qt::ConnectionType type = Qt::DirectConnection,  
                                   QGenericArgument val0 = QGenericArgument(nullptr),  
                                   ... // 最多到 val9  
                                   )

    这个重载与上一个类似,但它不期望方法返回任何值。这在你只关心方法是否被成功调用,而不关心其返回值时很有用。

  3. 带返回值的重载(简化版):

    bool QMetaObject::invokeMethod(QObject *object, const char *method,  
                                   Qt::ConnectionType type,  
                                   QGenericReturnArgument ret)

    这个重载允许你指定一个返回值,但不支持传递参数给方法。它适用于那些不需要参数但期望返回值的场景。

  4. 异步调用重载
    虽然这不是一个完全独立的重载,但值得注意的是,invokeMethod 支持异步调用。你可以通过指定 Qt::QueuedConnection 作为连接类型来实现这一点。当使用异步调用时,方法将在事件循环的下一个迭代中被调用,这允许你在不阻塞当前线程的情况下调用方法。

  5. 模板重载(C++11及更高版本):
    在 C++11 及更高版本中,Qt 提供了模板化的 invokeMethod,它允许你更直接地传递参数而不需要使用 QGenericArgument。这个重载在编译时根据提供的参数类型自动推断,并调用相应的方法。然而,这个模板重载在 Qt 的某些版本中可能不是直接作为 QMetaObject 的静态成员函数提供的,而是作为 QMetaObject::invokeMethod 的一个帮助器函数或模板特化存在的。

请注意,具体可用的重载形式可能因 Qt 的版本而异。在使用时,建议查阅你正在使用的 Qt 版本的官方文档以获取最准确的信息。

此外,当使用 invokeMethod 时,还需要注意以下几点:

  • 确保对象 object 是有效的,并且其类使用了 Q_OBJECT 宏。
  • 方法 method 必须是可调用的,这通常意味着它是一个槽或使用了 Q_INVOKABLE 宏。
  • 如果方法需要参数,确保提供的参数与方法的期望类型匹配。
  • 如果方法返回值,确保正确处理这个返回值。

Q_INVOKABLE 

Q_INVOKABLE 是 Qt 框架中的一个宏,用于标记类的成员函数,以便它们可以通过 Qt 的元对象系统被动态调用。这个宏通常用于以下几种场景:

  1. QML 与 C++ 交互
    当你想在 QML 中调用 C++ 类的方法时,可以使用 Q_INVOKABLE 标记这些方法。这样,QML 就可以通过对象的方法名直接调用这些方法,而无需将它们声明为槽。

  2. 动态调用
    Q_INVOKABLE 允许你在运行时使用 QMetaObject::invokeMethod 动态地调用成员函数。这在某些情况下非常有用,比如当你需要根据条件决定调用哪个方法时。

  3. 跨线程通信
    在 Qt 中,跨线程通信通常通过信号和槽机制实现。然而,如果你需要在跨线程环境中调用普通成员函数,而不是槽,可以使用 Q_INVOKABLE 标记这些方法,并通过 QMetaObject::invokeMethod 进行调用。

使用 Q_INVOKABLE 宏时,需要注意以下几点:

  • Q_INVOKABLE 必须放在成员函数的返回类型前面。
  • 被 Q_INVOKABLE 标记的函数必须是公开的(public),因为元对象系统无法访问私有或受保护的成员函数。
  • Q_INVOKABLE 函数可以像普通成员函数一样被调用,但它们也可以被 Qt 的元对象系统识别和调用。

以下是一个简单的示例,展示了如何使用 Q_INVOKABLE

#include <QObject>  
#include <QDebug>  
  
class MyClass : public QObject  
{  
    Q_OBJECT  
  
public:  
    Q_INVOKABLE void myInvokableMethod(int a, const QString &b)  
    {  
        qDebug() << "Called myInvokableMethod with" << a << b;  
    }  
};  
  
int main(int argc, char *argv[])  
{  
    QCoreApplication app(argc, argv);  
  
    MyClass obj;  
    QMetaObject::invokeMethod(&obj, "myInvokableMethod",  
                              Q_ARG(int, 42),  
                              Q_ARG(QString, "Hello, Qt!"));  
  
    return app.exec();  
}

在这个示例中,MyClass 类有一个使用 Q_INVOKABLE 标记的成员函数 myInvokableMethod。在 main 函数中,我们使用 QMetaObject::invokeMethod 动态地调用了这个方法,并传递了两个参数。

需要注意的是,虽然 Q_INVOKABLE 提供了动态调用成员函数的灵活性,但过度使用它可能会导致代码难以理解和维护。因此,建议仅在确实需要动态调用时才使用 Q_INVOKABLE

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值