Qml中调用C++类的三种方式详解(一)

1.C++对象注册到元对象系统

    第一步:新建一个类,QmlCpp

    qmlcpp.h文件:

#ifndef QMLCPP_H
#define QMLCPP_H

#include <QObject>

class QmlCpp : public QObject
{
    Q_OBJECT
public:
    explicit QmlCpp(QObject *parent = nullptr);

    Q_INVOKABLE void setValue(int nValue);
    Q_INVOKABLE int getValue();

signals:

public slots:

private:
    int m_nValue;
};

#endif // QMLCPP_H

可以看出首先使用  Q_INVOKABLE 这个宏修饰了两个成员函数。

官方文档中的描述:

Apply this macro to declarations of member functions to allow them to be invoked via the meta-object system. The macro is written before the return type

翻译:将此宏应用于成员函数的声明,以允许它们通过元对象系统被调用,宏将在返回类型之前写入。

Q_INVOKABLE这个宏是将函数申明为元对象系统可调用的函数。

QtQuick 也在元对象系统中,这样就可以在QtQuick中可以访问到这2个c++的函数了。

第二步:在main.cpp中进行注册:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "qmlcpp.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);// 在支持的平台上的Qt中启用高DPI缩放
    QGuiApplication app(argc, argv);
    
    QQmlApplicationEngine engine;

    QmlCpp qmlcpp;          // 先初始化一个类的实例
    qmlcpp.setValue(898);   //  设初值
    //  将这个 C++ 实例注册到 Qml 引擎上下文中标示为 “qmlpro” 的名字, 这样 Qml 中就可以通过 qmlpro 来访问这个 C++ 实例。
    engine.rootContext()->setContextProperty("qmlpro",&qmlcpp);

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

我们将 QmlCpp 的头文件引用进来,然后定义一个 QmlCpp 类的实例,调用设置整型的函数,并将这个 C++ 实例注册到 Qml 引擎上下文中标示为 “QmlCpp” 的名字, 这样 Qml 中就可以通过 QmlCpp 来访问这个 C++ 实例。

第三步:在Qml文件中进行调用:

import QtQuick 2.12
import QtQuick.Controls 2.12

Item {

    Button{
        id:btn
        height: 48
        width: 120
        text: "1"
        anchors.centerIn: parent

        onClicked: {
            text=qmlpro.getValue();
            console.log(text);
        }
    }
    Button{
        id:btn1
        height: 48
        width: 120
        anchors.top: btn.bottom
        anchors.topMargin: 12
        anchors.horizontalCenter: btn.horizontalCenter
        onClicked: {
            qmlpro.setValue(999);
        }
    }
}

其中在上述代码中,最关键的步骤是第二步,所以仔细来看一下第二步 在main.cpp中是是如何进行注册的:

 QQmlApplicationEngine engine;

首先看的是这个类  QQmlApplicationEngine,官方文档中的描述如下:

QQmlApplicationEngine提供了一种从单个QML文件加载应用程序的便捷方法。
此类结合了QQmlEngine和QQmlComponent来提供一种方便的方式来加载单个QML文件。它还向QML公开了一些中央应用程序功能,而C ++ / QML混合应用程序通常会从C ++控制这些功能。

通过官方描述得知是用来加载qml文件的。

QmlCpp qmlcpp;          // 先初始化一个类的实例
qmlcpp.setValue(898);   //  设初值
    //  将这个 C++ 实例注册到 Qml 引擎上下文中标示为 “qmlpro” 的名字, 这样 Qml 中就可以通过 qmlpro 来访问这个 C++ 实例。
    engine.rootContext()->setContextProperty("qmlpro",&qmlcpp);

接着初始化了一个实例qmlcpp,调用setValue()函数。

engine.rootContext() 返回的是一个引擎的根上下文,返回的是  QQmlContext 类型指针;

engine.rootContext()->setContextProperty("qmlpro",&qmlcpp);

设置根上下文 属性名为 “qmlpro”的值为 一个指针,该指针指向qmlcpp这个实例。

之后再qml中直接使用 qmlpro 调用2个公共函数。

Button{
        id:btn
        height: 48
        width: 120
        text: "1"
        anchors.centerIn: parent

        onClicked: {
            text= qmlpro.getValue()
        }
    }

2、补充:上述流程实现了在qml文件中调用 C++类中两个函数,这两个函数必须被Q_INVOKABLE宏进行修饰。

但是要直接访问 C++类中的属性,还需要使用到 Q_PROPERTY,

#ifndef QMLCPP_H
#define QMLCPP_H

#include <QObject>
#include <QJSValue>
#include <QQmlEngine>

class QmlCpp : public QObject
{
    Q_OBJECT
    
    // 新加的内容
    Q_PROPERTY(int value READ getValue WRITE setValue NOTIFY valueChange)
    
public:
    explicit QmlCpp(QObject *parent = nullptr);

    Q_INVOKABLE void setValue(int nValue);
    Q_INVOKABLE int getValue();

signals:
    //新增内容
    void valueChange();

public slots:

private:
    int m_nValue;
};

#endif // QMLCPP_H

C++类中新增一行代码:

Q_PROPERTY(int value READ getValue WRITE setValue NOTIFY valueChange)

这行代码的意思是:定义一个名称为value的属性,读取属性的函数是getValue,写入属性的函数是setValue,属性发生变化时触发的信号是valueChange。

所以在类中又新增了一个信号:

void valueChange();

然后就可以在QML文件中直接访问这个value:

Button{
        id:btn
        height: 48
        width: 120
        text: "1"
        anchors.centerIn: parent

        onClicked: {
            text= qmlpro.value;
        }
    }

3.qml中直接访问qmlCpp中的槽函数:

因为C++类中的槽函数本身就在元对象系统中,而我们已经把qmlCpp注册到元对象系统中,所以Qml可以直接对qmlCpp类中槽函数进行调用;

第一步:现在qmlCpp类中新建一个槽函数,addValue()

void QmlCpp::addValue(int nValue)
{    
    m_nValue += nValue;
}

在QML文件中直接调用:

  Button{
        id:btn
        height: 48
        width: 120
        text: "1"
        anchors.centerIn: parent

        onClicked: {
            qmlpro.addValue(10);
            text= qmlpro.value
            console.log(text)
        }
    }

 

总结:

至此,这篇博客讲述了如何在QML文件中访问 c++类的 成员函数、数据成员、槽函数的基本步骤。

1.先将自定义的C++类注册到元对象系统中。

2.使用Q_INVOKABLE宏修饰 类的成员函数。

3.使用Q_PROPERTY这个宏来定义 属性的名称 读取、写入、以及值发生变化所触发的信号。

4.直接调用槽函数。

 

下一篇博客 将介绍 将C++直接注册到QML系统中去,在Qml中进行类的实例化,并调用类的方法,访问类的属性、接受类的信号。

  • 11
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在 Qt ,可以通过在 QML 使用 `Qt.createQmlObject()` 或者 `Qt.createComponent()` 创建一个 C++ 对象,然后在 QML 调用该对象的方法或者访问其属性。 具体步骤如下: 1. 在 C++ 定义一个 QObject 的子,并在其声明 Q_INVOKABLE 的方法或者 Q_PROPERTY 的属性。 ```cpp // MyObject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include <QObject> class MyObject : public QObject { Q_OBJECT public: explicit MyObject(QObject *parent = nullptr); Q_INVOKABLE void myMethod(QString str); Q_PROPERTY(QString myProperty READ myProperty WRITE setMyProperty NOTIFY myPropertyChanged) void setMyProperty(const QString &str); QString myProperty() const; signals: void mySignal(); void myPropertyChanged(); }; #endif // MYOBJECT_H ``` ```cpp // MyObject.cpp #include "MyObject.h" MyObject::MyObject(QObject *parent) : QObject(parent) { } void MyObject::myMethod(QString str) { qDebug() << "myMethod called with arg" << str; } void MyObject::setMyProperty(const QString &str) { if (m_property != str) { m_property = str; emit myPropertyChanged(); } } QString MyObject::myProperty() const { return m_property; } ``` 2. 在 main.cpp 将该对象注册到 QML ,以便在 QML 访问。 ```cpp // main.cpp #include <QGuiApplication> #include <QQmlApplicationEngine> #include "MyObject.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; qmlRegisterType<MyObject>("com.mycompany.myobject", 1, 0, "MyObject"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); } ``` 3. 在 QML 使用 `Qt.createComponent()` 或者 `Qt.createQmlObject()` 创建该对象,并调用其方法或者访问其属性。 ```qml // main.qml import QtQuick 2.0 import com.mycompany.myobject 1.0 Rectangle { width: 400 height: 400 MyObject { id: myObject myProperty: "Hello, World!" Component.onCompleted: { myObject.myMethod("Hello, World!"); console.log(myObject.myProperty); } } } ``` 在上述代码,我们使用 `MyObject` 创建了一个名为 `myObject` 的对象,并调用了它的 `myMethod` 方法和 `myProperty` 属性。 需要注意的是,使用 `Qt.createComponent()` 或者 `Qt.createQmlObject()` 创建对象时,必须指定该对象的父对象,否则该对象将无法正常工作。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值