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修饰的方法,十分方便。