QML与C++通信
一、QML中如何使用C++的类和对象
前提条件:
1.从 QObject 或 QObject 的派生类继承
2.使用 Q_OBJECT 宏
这两个条件是为了让一个类能够进入 Qt 强大的元对象系统(meta-object system)中,只有使用元对象系统,一个类的某些方法或属性才可能通过字符串形式的名字来调用,才具有了在 QML 中访问的基础条件。
一旦导出了一个类,在 QML 中就必然要访问该类的实例的属性或方法来达到某种目的,而具有什么特征的属性或方法才可以被 QML 访问呢?
信号和槽(针对C++中类的函数而言)
class ColorMaker : public QObject
{
Q_OBJECT
public:
ColorMaker(QObject *parent = 0);
~ColorMaker();
signals:
void colorChanged(const QColor & color);
void currentTime(const QString &strTime);
public slots:
void start();
void stop();
};
我们定义了 start() / stop() 两个槽, colorChanged() / currentTime() 两个信号,都可以在 QML 中通过对象的方法直接使用,例如:
ColorMaker{
id:colormaker
}
colormaker.start();或者colormaker.colorChanged(color);
使用Q_INVOKABLE 宏修饰的普通函数(针对C++中类的函数而言)
在定义一个类的成员函数时使用 Q_INVOKABLE 宏来修饰,使用 Q_INVOKABLE 将某个方法注册到元对象系统中,就可以让该方法被元对象系统调用。这个宏必须放在返回类型前面。
class ColorMaker : public QObject
{
Q_OBJECT
public:
ColorMaker(QObject *parent = 0);
~ColorMaker();
Q_INVOKABLE GenerateAlgorithm algorithm() const;
Q_INVOKABLE void setAlgorithm(GenerateAlgorithm algorithm);
signals:
void colorChanged(const QColor & color);
void currentTime(const QString &strTime);
public slots:
void start();
void stop();
};
algorithm()和setAlgorithm(GenerateAlgorithm algorithm)都可以在在 QML 中通过对象的方法直接使用,例如:
ColorMaker{
id:colormaker
}
colormaker.algorithm();
使用Q_ENUMS 宏修饰的枚举类型(针对C++中类的枚举类型而言)
class ColorMaker : public QObject
{
Q_OBJECT
Q_ENUMS(GenerateAlgorithm)
public:
ColorMaker(QObject *parent = 0);
~ColorMaker();
enum GenerateAlgorithm{
RandomRGB,
RandomRed,
RandomGreen,
RandomBlue,
LinearIncrease
};
Q_INVOKABLE GenerateAlgorithm algorithm() const;
Q_INVOKABLE void setAlgorithm(GenerateAlgorithm algorithm);
signals:
void colorChanged(const QColor & color);
void currentTime(const QString &strTime);
public slots:
void start();
void stop();
};
QML中可通过ColorMaker.LinearIncrease直接使用。
使用Q_PROPERTY 宏修饰的变量类型(针对C++中类的变量而言)
class QQuickText : public QQuickImplicitSizeItem
{
Q_OBJECT
Q_ENUMS(HAlignment)
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
...
public:
...
};
综合运用上述方法和属性:
class ColorMaker : public QObject
{
Q_OBJECT
Q_ENUMS(GenerateAlgorithm)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(QColor timeColor READ timeColor)
public:
ColorMaker(QObject *parent = 0);
~ColorMaker();
enum GenerateAlgorithm{
RandomRGB,
RandomRed,
RandomGreen,
RandomBlue,
LinearIncrease
};
QColor color() const;
void setColor(const QColor & color);
QColor timeColor() const;
Q_INVOKABLE GenerateAlgorithm algorithm() const;
Q_INVOKABLE void setAlgorithm(GenerateAlgorithm algorithm);
signals:
void colorChanged(const QColor & color);
void currentTime(const QString &strTime);
public slots:
void start();
void stop();
protected:
void timerEvent(QTimerEvent *e);
private:
GenerateAlgorithm m_algorithm;
QColor m_currentColor;
int m_nColorTimer;
};
(一)QML中使用C++中的类
方法:在 C++ 中实现一个类,注册到 QML 环境中, QML 环境中使用该类型创建对象
要注册一个 QML 类型,有多种方法可用,如 qmlRegisterSingletonType() 用来注册一个单例类型, qmlRegisterType() 注册一个非单例的类型, qmlRegisterTypeNotAvailable() 注册一个类型用来占位, qmlRegisterUncreatableType() 通常用来注册一个具有附加属性的附加类型
qmlRegisterType() 是个模板函数
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
使用qmlRegisterType 需要包含 QtQml 头文件。
先说模板参数 typename ,它就是你实现的 C++ 类的类名。
qmlRegisterType() 的第一个参数 uri ,让你指定一个唯一的包名,类似 Java 中的那种,一是用来避免名字冲突,而是可以把多个相关类聚合到一个包中方便引用。比如我们常写这个语句 “import QtQuick.Controls 1.1” ,其中的 “QtQuick.Controls” 就是包名 uri ,而 1.1 则是版本,是 versionMajor 和 versionMinor 的组合。 qmlName 则是 QML 中可以使用的类名。
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QtQml>
#include "colorMaker.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<ColorMaker>("an.qt.ColorMaker", 1, 0, "ColorMaker");
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/colorMaker/main.qml"));
viewer.showExpanded();
return app.exec();
}
上面的代码将 ColorMaker 类注册为 QML 类 ColorMaker ,主版本为 1 ,次版本为 0 ,而我起的包名则是 an.qt.ColorMaker 。注册动作一定要放在 QML 上下文创建之前。
QML中使用此类的方法:
import an.qt.ColorMaker 1.0
Rectangle {
width: 360;
height: 360;
ColorMaker {
id: colorMaker;
color: Qt.green;
}
}
(二)QML中使用C++中的对象
方法:在 C++ 中构造一个对象,将这个对象设置为 QML 的上下文属性,在 QML 环境中直接使用该属性
可以把 C++ 中创建的对象作为属性传递到 QML 环境中,然后在 QML 环境中访问。
main.cpp:
QQmlContext *context = engine.rootContext();
context->setContextProperty("myobject", myobject);
还有一点要说明,因为去掉了 qmlRegisterType() 调用,所以在 main.qml 中不能再访问 ColorMaker 类了,比如你不能通过类名来引用它定义的 GenerateAlgorithm 枚举类。
此种方法QML中无需import导入,可以直接使用myobject对象访问其属性和方法,例如myobject.iValue
二、C++中使用QML中的函数
QML 对象对应的类型,原本就是 C++ 类型,比如 Image 对应 QQuickImage , Text 对应 QQuickText……但是,这些与 QML 类型对应的 C++ 类型都是私有的,你写的 C++ 代码也不能直接访问。肿么办?
Qt 最核心的一个基础特性,就是元对象系统,通过元对象系统,你可以查询 QObject 的某个派生类的类名、有哪些信号、槽、属性、可调用方法等等信息,然后也可以使用 QMetaObject::invokeMethod() 调用 QObject 的某个注册到元对象系统中的方法。而对于使用 Q_PROPERTY 定义的属性,可以使用 QObject 的 property() 方法访问属性,如果该属性定义了 WRITE 方法,还可以使用 setProperty() 修改属性。所以只要我们找到 QML 环境中的某个对象,就可以通过元对象系统来访问它的属性、信号、槽等。
engine.load(url);
auto list = engine.rootObjects();
auto window = list.first();
//auto name = window->objectName();//
QObject* obj = window->findChild<QObject*>("myobjects");//myobjects为某个控件的objectname
qDebug() << obj;
QVariant res;
QVariant arg = 15;
QMetaObject::invokeMethod(obj, "func", Q_RETURN_ARG(QVariant, res),
Q_ARG(QVariant,arg));
qDebug() << res;
return app.exec();
参考文章:http://blog.csdn.net/foruok