QT系列文章(1):QT与QML的简单交互

说直白一点,QML主要用来开发界面,QT C++主要用来开发软件功能逻辑,我们希望,界面是界面,逻辑是逻辑,分的开一些不会显得十分混乱,所以就免不了QML和C++之间的相互交互,主要包括QML调用C++类的方法,信号传递等。

一、让QML能调用C++类的方法

有两种方法可以实现,这里先讲一种

首先讲一下Q_PROPERTY() 的使用方法:

Q_PROPERTY(double value1 READ value1 WRITE setValue1 NOTIFY value1Changed)

解释:

有一个double类型的变量value1,

读取这个变量的值的方法是value1();

修改这个变量值的方法是 setValue1(double value1);

一旦value1的值发生变化,会发出value1Changed(); 信号(不会自动发出哦,需要自己手动emit发射信号,这里只是声明给QML(告诉QML这回事,不是会自动完成,实现方法后面会说),包括读取和修改变量值的方法,都是要自己实现的,Q_PROPERTY主要就是用来做这些简单的变量可以让QML直接读写操作,读写函数改变信号都打包好给QML.

我这里放一个DemoClass实例:

#ifndef DEMOCLASS_H
#define DEMOCLASS_H

#include <QObject>

class DemoClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(double value1 READ value1 WRITE setValue1 NOTIFY value1Changed)
    Q_PROPERTY(int value2 READ value2 WRITE setValue2 NOTIFY value2Changed)
    Q_PROPERTY(bool value3 READ value3 WRITE setValue3 NOTIFY value3Changed)

public:
    explicit DemoClass(QObject *parent = nullptr);
    ~DemoClass();

    double value1() const;
    int value2() const;
    bool value3() const;

    void setValue1(double value1);
    void setValue2(int value2);
    void setValue3(bool value3);

    Q_INVOKABLE void qmlInterfaceExample();

signals:
    void value1Changed();
    void value2Changed();
    void value3Changed();

    void exampleSignalToBackGround();



private:
    double mf64_value1;
    int mi_value2;
    bool mb_value3;
};

#endif // DEMOCLASS_H

这段示例代码中就包括了三个不同类型的变量的读取、修改、信号发射,并且Q_PROPERTY()声明。新建类不要忘了继承QObject类,并且加上Q_OBJECT宏(代码加粗部分),其中涉及的Q_INVOKABLE是把 方法暴露给QML,可以在QML里面直接调用。Q_PROPERTY主要是打包一些变量修改读取等操作,Q_INVOKABLE就是把想暴露给QML的类的方法直接暴露出去,QML直接可以调用。

下面是DemoClass类的具体实现,包括读写函数和信号发射。

#include "DemoClass.h"

#include <QDebug>

DemoClass::DemoClass(QObject *parent) : QObject(parent)
{
    mf64_value1 = 0;
    mi_value2 = 0;
    mb_value3 = 0;
}

DemoClass::~DemoClass()
{

}

double DemoClass::value1() const
{
    return mf64_value1;
}

void DemoClass::setValue1(double value1)
{
    if (mf64_value1 != value1)
    {
        mf64_value1 = value1;
        emit value1Changed();
    }
}

int DemoClass::value2() const
{
    return mi_value2;
}

void DemoClass::setValue2(int value2)
{
    if (mi_value2 != value2)
    {
        mi_value2 = value2;
        emit value2Changed();
    }
}

bool DemoClass::value3() const
{
    return mb_value3;
}

void DemoClass::setValue3(bool value3)
{
    if (mb_value3 != value3)
    {
        mb_value3 = value3;
        emit value3Changed();
    }
}

void DemoClass::qmlInterfaceExample()
{
    qDebug() << "DemoClass::qmlInterfaceExample";
    emit exampleSignalToBackGround();
}

DemoClass类已经完成之后,如何才能从QML里面直接调用呢?看下去

我们到项目下main.cpp中:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTranslator>
#include <QtDebug>
#include "demo/DemoClass.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);
    QQmlApplicationEngine engine;

    QQmlContext* rootContext = engine.rootContext();
    DemoClass* demoClass = new DemoClass(&app);
    rootContext->setContextProperty("demoClass", demoClass);

    const QUrl url(QStringLiteral("qrc:/qml/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();
}

注意看加粗部分就可以,引用QQmlContext,引用我们自己新建的DemoClass类,新建一个QQmlContext实例( QQmlContext* rootContext = engine.rootContext(); ),新建一个DemoClass实例( DemoClass* demoClass = new DemoClass(&app); ),设置上下文属性( rootContext->setContextProperty(“demoClass”, demoClass); ),至此设置完毕。我们到QML文件中进行引用:

 demoClass.value1 = 0;
 console.log("demoClass.value1: ", demoClass.value1)
 demoClass.value1 = 2;
 console.log("demoClass.value1: ", demoClass.value1)
 demoClass.qmlInterfaceExample();

可以看到设置了上下文属性之后,我们直接使用 demoClass.value1 = 0; 就可以对C++类里面的value1进行写操作, demoClass.value1 进行读操作,demoClass.qmlInterfaceExample();可以直接调用Q_INVOKABLE修饰的方法,十分方便。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注