【目的】1.了解QML组件创建的环境
2.了解QML组件,QML上下文,QML引擎之间的关系。
3.总结QML引擎提供的开发效率
【QML引擎】
继承关系:
QQmlEngine是继承自QJSEngine,正是由于QJSEngine提供了一个可以评估JavaScript代码的环境,因此我们在qml编写的过程中可以使用JavaScript代码。目前由于JavaScript的流行,因此在QML原生中支持使用JavaScript也是QML一个明显的优势。
在QML开发的过程中,每个QML组件都在QQmlContext中实例化,而上下文的定义便依赖QQmlEngine,因此QQmlEngine提供了用于实例化QML组件的环境。在创建任何QML组件之前,应用程序必须已创建QQmlEngine才能访问QML上下文。
对于上下文来讲,QQmlContext用于将数据传递到QML组件中。在QML中,上下文按层次结构排列,并且此层次结构由QQmlEngine管理。上下文是一个层次架构,这个层次结构的根是QML引擎的根上下文;子上下文会继承父母的上下文属性;如果子上下文设置了在父亲中已经有的上下文属性,那么新的上下文属性将会覆盖父亲的上下文属性。
【引擎即是生产力】
QML相较于C++ 开发GUI的优势
1.组件封装灵活与复用方便,样式设置直接。相比较于QSS来调整样式(QSS编写容易出错,错误校验也较为费时;QSS使用资源不够系统;某些样式实现起来较为复杂),QML的方便在于两点。首先QtCreator会自动匹配很多样式的设置,以及在使用矩形框,字体等组件是会自动弹出相应的编辑工具提高开发效率,还有相较于C++原有生产UI的方式,QML不仅依然有相应的布局元素,还增加了定位元素,锚点属性等,再加上QML特有的编写方式,组件的封装与使用比较高效。
例如:QML封装一个圆角,并带有阴影,有图片Icon,支持4中状态的一个按钮并使用;
//封装 ImageBtn.qml
Rectangle {
id: testRect
width: 60
height: 60
radius: 10 //圆角
color: "steelblue"
property url normalUrl //normal url path
property url hoveredUrl
property url pressedUrl
property url disabledUrl
property alias imageItem: img
property alias imageUrl: img.source
property alias containsMouse: area.containsMouse
property alias containsPress: area.containsPress
signal clicked();
//阴影设置
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
horizontalOffset: 8
verticalOffset: 8
}
//支持4种状态按钮状态
Image {
id: img
anchors.fill: parent
source: root.enabled ? (containsPress ? pressedUrl : (containsMouse ? hoveredUrl : normalUrl)) : disabledUrl
}
//鼠标事件
MouseArea {
id: area
anchors.fill: parent;
hoverEnabled: parent.enabled;
onClicked: root.clicked();
cursorShape: Qt.PointingHandCursor
preventStealing: true
}
}
//使用
ImageBtn{
id:testBtn
width: 16
height: 16
normalUrl: "./test_normal.png"
hoveredUrl: "./test_hover.png"
pressedUrl: "./test_press.png"
disabledUrl:"./test_press.png"
onClicked: {
//TODO
}
}
2.动画实现方便,很多View已经自带很多动画,无需二次开发。Qt Quick针对不同的应用场景,提供了一些基本的动画对象,在现有的产品研发过程中,基本的页面切换过滤动画,属性动画,序列帧动画等在开发中十分常见。首先在很多组件中可以直接使用动画完成相应开发,而且QML中封装好的View组件例如GridView,ListView,SwipeView等都自带一些动画效果。
例如:1.实现序列帧动画
Rectangle{
id: imageAnimation
Image {
property int index:1
id: image
x: 0
y: 0
source: "Test_"+index+".png"
NumberAnimation on index{
from: 1
to: 20
duration: 500
}
}
}
2.SwipView相比较Widget的StackWidget而言自带过度动画
Rectangle{
SwipeView {
id: testView
currentIndex: 1
anchors.fill: parent
Item {
id: firstPage
}
Item {
id: secondPage
}
}
function changePage(index) {
//异常校验
swipeView.currentIndex = index;
}
}
3.降低维护成本。Model-View-Delegate编程框架的使用,当界面进行修改时,我们完全复用Model层,只需要对View,Delegate进行适配即可
详情请看另一篇:Model-View-Delegate编程框架
总结:Qt目前支持两种主要的编写GUI应用程序的方式。一种是使用Widget模块,另一种是使用Quick模块。Widget是使用C++编写GUI应用程序,这个较旧的一种开发方式。Quick模块是使用QML语言的新的开发方式,并推荐使用这种方式。QML是一种声明性语言,是专门用于创建图形用户界面,并且支持JavaScript。因此基于QML引擎所提供能力,我们可以使用QML来构建流畅而高效的用户界面。
参考资料
【1】Qt Assistant QJSEngine
【2】Qt Assistant QQmlEngine
【3】Qt Assistant QQmlContext
【4】Why you should use Qt/QML for your next cross-platform application — part 1 — desktop(https://pkoretic.medium.com/why-you-should-use-qt-qml-for-you-next-cross-platform-application-part-1-desktop-5e6d8856b7b4)