一、前言
所有的QML对象类型都是源自QObject类型,因此,QML引擎可以使用Qt元对象系统动态的实例化QML对象,并获取所创建对象的属性与方法。也就是说一旦创建了QML对象,就可以使用C++获取它的属性、函数与信号处理。
主要从以下几个方面介绍:
1、从C++加载QML对象,并读写属性
2、调用QML的函数
3、接收QML发出的信号
二、详细说明
1、QML属性读写
假设存在一个名为MyItem.qml的文件,内容如下:
import QtQuick 2.0
Item {
width: 100; height: 100
}
在C++中,QML文档可以使用 QQmlComponent
或 QQuickView
来加载。加载方法如下:
// Using QQmlComponent
QQmlEngine engine;
QQmlComponent component(&engine,
QUrl::fromLocalFile("MyItem.qml"));
QObject *object = component.create();
...
delete object;
使用QQmlComponent
需要调用QQmlComponent::create()
创建一个QObject 实例。
// Using QQuickView
QQuickView view;
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
QObject *object = view.rootObject();
QQuickView
会自动的创建一个QObject 实例,可以通过view.rootObject()
来获取。
获取QObject 对象之后可以通过以下两种方法来设置属性:
object->setProperty("width", 500);//法1
QQmlProperty(object, "width").write(500);//法2
法2相对于法1,会移除上例中的width
绑定属性
除此之外,还可以将对象强制转换为实际类型,然后使用调用函数来设置属性。如下所示:
QQuickItem *item = qobject_cast<QQuickItem*>(object);
item->setWidth(500);
此时可以使用QMetaObject::invokeMethod()
和QObject::connect()
来调用item的行数和信号处理。详情见后文。
1.1通过 objectName 来获取QML对象
假设MyItem.qml的内容如下,Item
中存在一个objectName
为“rect”的矩形
import QtQuick 2.0
Item {
width: 100; height: 100
Rectangle {
anchors.fill: parent
objectName: "rect"
}
}
则 上述 矩形可以通过 如下方式获取:
QObject *rect = object->findChild<QObject*>("rect");
if (rect)
rect->setProperty("color", "red");
如果存在多个objectName相同的对象,比如listView的Delegate中设置了一个特定的对象名称,则可以使用QObject::findChildren()
来获取所有子对象。
警告: 尽管可以从C++中获取和操作QML对象,但是除非为了测试和原型设计,并不建议这样做。因为QML和C ++集成的优势之一是能够在QML中实现与C ++逻辑和后端分离的UI。
1.2从C ++访问QML对象类型的成员
在QML中使用property
声明的属性可以在C++中被获取。假设MyItem.qml的内容如下:
// MyItem.qml
import QtQuick 2.0
Item {
property int someNumber: 100
}
则someNumber属性值可以通过QQmlProperty
,QObject::setProperty()
和QObject::property()
来访问。
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
qDebug() << "Property value:" << QQmlProperty::read(object, "someNumber").toInt();
QQmlProperty::write(object, "someNumber", 5000);
qDebug() << "Property value:" << object->property("someNumber").toInt();
object->setProperty("someNumber", 100);
注意:你必须通过QObject::setProperty(), QQmlProperty or QMetaProperty::write()
这三种方法来设置QML的属性,才能够保证QML引擎对你的修改可知。
2、调用QML函数
所有的QML函数都暴露在Qt元对象系统中,可以被C++使用QMetaObject::invokeMethod()
来访问。向QML传递的函数参数和QML的返回值需要在C ++中转换为QVariant值,因为这是QML函数参数和返回值的通用数据类型。例如:
// MyItem.qml
import QtQuick 2.0
Item {
function myQmlFunction(msg) {
console.log("Got message:", msg)
return "some return value"
}
}
C++ 代码如下:
// main.cpp
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;
3、连接QML信号
所有的QML信号均可以在C++中被访问,可以像普通Qt的C++信号一样使用。
QML信号参数为string
:
// MyItem.qml
import QtQuick 2.0
Item {
id: item
width: 100; height: 100
signal qmlSignal(string msg)
MouseArea {
anchors.fill: parent
onClicked: item.qmlSignal("Hello from QML")
}
}
C++处理方式如下:
class MyClass : public QObject
{
Q_OBJECT
public slots:
void cppSlot(const QString &msg) {
qDebug() << "Called the C++ slot with message:" << msg;
}
};
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
QObject *item = view.rootObject();
MyClass myClass;
QObject::connect(item, SIGNAL(qmlSignal(QString)),
&myClass, SLOT(cppSlot(QString)));
view.show();
return app.exec();
}
需要注意的是,当信号参数时QML对象时,参数类型应该为var
,C++中槽函数的参数应该为QVariant
。
QML文件如下:
// MyItem.qml
import QtQuick 2.0
Item {
id: item
width: 100; height: 100
signal qmlSignal(var anObject)
MouseArea {
anchors.fill: parent
onClicked: item.qmlSignal(item)
}
}
则C++处理方式如下:
class MyClass : public QObject
{
Q_OBJECT
public slots:
void cppSlot(const QVariant &v) {
qDebug() << "Called the C++ slot with value:" << v;
QQuickItem *item =
qobject_cast<QQuickItem*>(v.value<QObject*>());
qDebug() << "Item dimensions:" << item->width()
<< item->height();
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
QObject *item = view.rootObject();
MyClass myClass;
QObject::connect(item, SIGNAL(qmlSignal(QVariant)),
&myClass, SLOT(cppSlot(QVariant)));
view.show();
return app.exec();
}
参考链接:http://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html