天天看点

在C++中与QML对象交互简述从 C++ 加载 QML 对象根据 objectName 访问加载的 QML 对象从 C++ 访问 QML 对象类型的成员

所有的 qml 对象类型 - 无论由引擎内部实现还是由第三方源定义,都是 qobject 派生的类型。这意味着,qml 引擎可以使用 qt 元对象系统动态实例化任何 qml 对象类型并检查创建的对象。

这对于在 c++ 中创建 qml 对象非常有用,无论是显示一个可视化呈现的 qml 对象,还是将非可视 qml 对象数据集成到 c++ 应用程序中。一旦 qml 对象被创建,就可以从 c++ 中检查它,以便读取和写入属性、调用方法、以及接收信号通知。

<a href="#%e7%ae%80%e8%bf%b0">简述</a>

<a href="#%e4%bb%8e-c-%e5%8a%a0%e8%bd%bd-qml-%e5%af%b9%e8%b1%a1">从 c 加载 qml 对象</a>

<a href="#%e6%a0%b9%e6%8d%ae-objectname-%e8%ae%bf%e9%97%ae%e5%8a%a0%e8%bd%bd%e7%9a%84-qml-%e5%af%b9%e8%b1%a1">根据 objectname 访问加载的 qml 对象</a>

<a href="#%e4%bb%8e-c-%e8%ae%bf%e9%97%ae-qml-%e5%af%b9%e8%b1%a1%e7%b1%bb%e5%9e%8b%e7%9a%84%e6%88%90%e5%91%98">从 c 访问 qml 对象类型的成员</a>

<a href="#%e5%b1%9e%e6%80%a7">属性</a>

<a href="#%e8%b0%83%e7%94%a8-qml-%e6%96%b9%e6%b3%95">调用 qml 方法</a>

<a href="#%e8%bf%9e%e6%8e%a5%e5%88%b0-qml-%e4%bf%a1%e5%8f%b7">连接到 qml 信号</a>

<a href="#%e5%9f%ba%e6%9c%ac%e7%b1%bb%e5%9e%8b%e7%9a%84%e4%bf%a1%e5%8f%b7%e5%8f%82%e6%95%b0">基本类型的信号参数</a>

<a href="#%e5%af%b9%e8%b1%a1%e7%b1%bb%e5%9e%8b%e7%9a%84%e4%bf%a1%e5%8f%b7%e5%8f%82%e6%95%b0">对象类型的信号参数</a>

可以使用 qquickview 或 qqmlcomponent 来加载 qml 文档。qqmlcomponent 将 qml 文档加载为一个 c++ 对象,然后可以从 c++ 代码中修改该对象。qquickview 也做到了这一点,但由于 qquickview 是一个基于 qwindow 的派生类,加载的对象也将被渲染至可视化显示,qquickview 通常用于将一个可视化的 qml 对象集成到应用程序的用户界面中。

例如,有一个 qml 文件,如下所示:

可以使用 qqmlcomponent 或 qquickview 的 c++ 代码加载该 qml 文档。当使用 qqmlcomponent 时,需要调用 qqmlcomponent::create() 来创建组件的新实例:

而 qquickview 会自动创建组件的实例,该实例可以通过 qquickview::rootobject() 来访问:

实例(object)创建后,就可以使用 qobject::setproperty() 或者 qqmlproperty 来修改其属性:

或者,将 object 转换为其实际类型,并使用编译时安全性调用方法。在这种情况下,main.qml 的基本对象是一个 item,由 qquickitem 类定义:

qml 组件实质上是具有子对象的对象树,子对象有兄弟,也有孩子。可以使用 qobject::objectname 属性和 qobject::findchild() 来定位 qml 组件的子对象。

例如,如果 qml 中的根 item 有一个 rectangle 子项:

可以通过这样来定位孩子:

注意: 一个对象可能有多个具有相同 objectname 的子项,这种情况下,qobject::findchildren() 可用于查找具有匹配 objectname 的所有子项。

警告: 虽然可以使用 c++ 深入对象树中访问和操作 qml 对象,但建议不要在应用程序测试和原型设计之外采用此方法。qml 和 c++ 集成的一个优势是实现 qml 用户界面独立于 c++ 逻辑和数据集后端,如果 c++ 端深入到 qml 组件中直接操作它们,这种策略就会被打破。对于 c++ 实现,最好尽可能少地了解 qml 用户界面实现和 qml 对象树的组成。

qml 中声明的任何属性都可以从 c++ 中访问。

例如,下面的 qml 声明了一个简单的字符串:

在 c++ 中,属性 hey 的值可以使用 qqmlproperty 来设置和读取,也可使用 qobject::setproperty() 和 qobject::property():

输出如下:

property value: “hello, qter!” property value: “hello, qt!” property value: “hello, qml!”

注意: 应该始终使用 qobject::setproperty()、qqmlproperty 或 qmetaproperty::write() 来改变 qml 的属性值,以确保 qml 引擎感知属性的变化。

例如,有一个自定义类型 pushbutton,它有一个 buttontext 属性。在内部,该属性以成员变量 m_buttontext 来反映值,可以像下面这样直接修改成员变量:

但这并不是一个好主意。由于值被直接改变,绕过了 qt 元对象系统,qml 引擎并没有意识到属性的变化。这意味着,绑定到 buttontext 的属性不会被更新,并且 onbuttontextchanged 处理程序也不会被调用。

所有的 qml 方法都被暴露给了 qt 元对象系统,可以使用 qmetaobject::invokemethod() 从 c++ 中调用。从 qml 传递的方法参数和返回值在 c++ 中被转换为 qvariant 值。

写一个简单的 qml,并为其添加一个方法:

然后,在 c++ 中使用 qmetaobject::invokemethod() 进行调用:

got message: hello, qml! qml function returned: “hello, qter!”

注意: qmetaobject::invokemethod() 的 q_return_arg() 和 q_arg() 参数必须被指定为 qvariant 类型,因为这是用于 qml 方法参数和返回值的通用数据类型。

所有的 qml 信号在 c++ 中都是可用的,和普通的 qt c++ 信号一样,可以使用 qobject::connect() 进行连接。反过来,任何 c++ 信号可以由 qml 对象使用信号处理器来接收。

这里有一个 qml 组件,包含一个名为 qmlsignal 的信号,该信号包含一个 string 类型参数:

写一个 c++ 类,并实现一个槽函数,用于接收 qml 发射的信号:

将信号连接至 c++ 对象的槽函数,当发出 qmlsignal 信号时,就会调用:

点击鼠标后,输出如下:

called the c++ slot with message: “hello, qter!”

当信号的参数为 qml 对象类型时,应使用 var 作为参数类型,并且在 c++ 中应使用 qvariant 类型接收该值。

例如,将上述示例中的参数改为 qml 对象类型:

要接收该信号,c++ 类中的槽函数的参数应该改为 qvariant 类型:

当然,连接信号槽的的参数类型也需要修改:

called the c++ slot with value: qvariant(qobject*, qquickitem_qml_0(0x1f4b4cb38d0)) item size: 100 100

继续阅读