一、Cpp中调用QML方法
在Cpp中调用QML方法主要有两种途径,一是通过invokeMethod()方法,二是通过信号与槽机制。
接着上一篇内容的案例,我们在qml代码中,为Rectangle对象写一个toggleText()方法,该方法用来切换Text对象的显示状态,并且我们给Rectangle对象的objectName属性取一个名字“rectangle”(这里注意一定要加双引号),方便我们在cpp代码中找到这个对象。
接着我们希望在main.cpp代码中调用我们刚才写的qml方法-toggleText(),这里我们举例演示一下两种调用方法,首先我们需要通过engine的rootObjects()方法找到qml的根对象,然后通过objectName找到我们在qml写的rectangle对象,并用一个item指针指向它。
接下来可以通过invokeMethod(item,"toggleText")方法就可以成功调用qml中我们所写的方法了,
或者我们通过信号与槽机制,比如,我们可以创建一个timer对象,并为timer设置一个时间间隔,然后将timer的timeout()信号与qml对象的toggleText()方法连接,这样就实现了通过触发timeout()信号而调用toggleText()的效果,通过这个效果可以实现矩形内的文字出现闪烁。
二、Cpp与QML界面数据绑定
在开发过程中将后台数据在界面上进行显示是一个经常遇到的需求,在QML中提供了几种将CPP代码中的数据绑定在QML控件的方法,下面我们逐个介绍一下:
(1)绑定QStringList
qt提供了QStringList类,我们可以直接将其与QML的ListView容器进行绑定,首先我们在main.cpp文件中创建一个QStringList对象,并将它暴露给QML的上下文:
之后我们在qml中将刚暴露给上下文的myDataList绑定到ListView的mode属性上就可以在界面中显示我们的数据了:
效果如下:
(2)绑定 QList<T>
QStringList可以满足我们对于String类型数据的绑定需求,但是在开发过程中,我们往往有一些自定义数据格式绑定的需求,这时我们可以使用QList<T>来进行绑定,同样我们先写一个自定义的数据类DataObject用来演示:
之后与QStringList绑定类似,我们在main.cpp中暴露我们创建的对象,并将其绑定到qml中:
最终效果:
(3)QAbstractListModel
为了实现更好的封装效果和MVVM架构,在Qt中使用QAbstractListModel往往是最佳的实践选项,所以接下来我们讲解一下如何使用QAbstractListModel来实现后端与前端的数据绑定。
QAbstractListModel是qml中的一个基类,我们将自定义的数据结构继承自QAbstractListModel就能够实现复杂数据结构的绑定,首先我们定义一个简单的基本数据结构:
之后我们建立一个AnimalModel类,作为ViewModel(MVVM架构中的VM层),该类需要继承自QAbstractListModel,并实现几个关键的虚函数,接下来我们会着重介绍。
在qml中role扮演了后台数据与界面绑定之间重要的桥梁,role作为自定类型成员变量与qml绑定数据间的重要联系,帮助qml可以实现复杂的数据类型的绑定操作。
如上图所示,我们建立了一个枚举类型的AnimalRoles,内部定义了我们需要显示在界面的成员变量对应的Role,为了避免与Qt中标准的Role发生冲突,我们将枚举的Role从UserRole之后开始。
建立完Role之后,我们需要将Role与界面和数据类型联系起来,这里就需要实现两个方法,一个是roleNames,一个是data,这两个都是继承自QAbstractListModel中的方法。
roleNames方法中,我们建立了一个哈希表,用来给每个角色定义一个字符名称,因为enum中的变量实际是一个int值,所以我们在qml界面中需要一个角色对应的名称,方便我们在qml中进行使用,这样就完成了Role与界面之间的联系。 接下来我们建立Role与数据类型之间的联系:
我们通过实现data方法,让qml能够通过Role找到我们所需要的类型的成员变量,这样就完成了Role与数据类型之间联系的建立。
之后qml还需两个方法,一个是rowCount方法,用来获取列表的长度,一个是addItem方法用来添加数据,这两个方法实现如下:
最后在qml中我们这样绑定(removeItem是一个删除数据的方法,实现和addItem类似,就不赘述了):
最终显示效果: