QML详解

前言

Qt Declarative UI 传得沸沸扬扬,却很少有中文资料介绍这是一个什么样的技术,以及如何使用它。偶尔能搜到几篇也是掐头去尾的,让人摸不着头脑。 CuteQt 网友英狐奉献的三篇文章很有参考价值,把我带入了门。我翻译的这个入门教程来自于 Qt 官方文档,更多的是语法性的介绍。

 

QML 是什么?

QML 是一种描诉性的脚本语言,文件格式以 .qml 结尾。语法格式非常像 CSS( 参考后文具体例子 ) ,但又支持 javacript 形式的编程控制。我个人认为它结合了 QtDesigner UI QtScript 的有点。 QtDesigner 可以设计出 .ui 界面文件 , 但是不支持和 Qt 原生 C++ 代码的交互。 QtScript 可以和 Qt 原生代码进行交互,但是有一个缺点,如果要在脚本中创建一个继承于 QObject 的图形对象非常不方便,只能在 Qt 代码中创建图形对象,然后从 QtScript 中进行访问。而 QML 可以在脚本里创建图形对象,并且支持各种图形特效,以及状态机等,同时又能跟 Qt 写的 C++ 代码进行方便的交互,使用起来非常方便。

 

如何使用?

Qt /C ++文件中通过 QDeclarativeView 加载,就像使用 UiLoader 加载 .ui 文件一样。不过本文不会去介绍如何在 Qt C ++中使用 QML ,而是把重点放在 QML 的语法上,不过别担心看不到 .qml 文件的效果。 Qt 提供了一个工具 QML Viewer 可以查看 .qml 文件生成的效果,该程序在 Qt bin 目录下,应用名字叫 qml(Windows 下叫 qml.exe) 。所以你在看到别人提供的 .qml 文件时,你可以用下面命令 qml filename.qml 查看 .qml 的执行结果,咱们的第一个 Hello,World 生成界面如下

开始 QML

上面的 Hello,World 源代码如下

 

1 import Qt 4.7

2

3 Rectangle {

4     id: page

5     width: 500; height: 200

6     color: “lightgray”

7

8     Text {

9         id: helloText

10         text: “Hello world!”

11         font.pointSize: 24; font.bold: true

12         y: 30; anchors.horizontalCenter: page.horizontalCenter

13     }

14 }

< 分行解释 >

1 行是 Qt QML 的统一用法,指明当前 QML 会使用 Qt-4.7 里已经定义好的类型,比如第 3 行的 Rectangle 和第 8 行的 Text

3 行开始至文章结束处则定义了一个矩形的图形区域对象,第 4 行则申明了该矩形区域对象的 id 为” page ”可以被其它对象识别并通过该 id 访问其成员属性,另外几个属性 width/height/color 则很好理解,语法跟 CSS 类似,可以写在一行中用分号” ; ”隔开。

8 行至第 12 行则是一个文本对象,看它代码的嵌套结构可以知道它是内嵌于 Rectangle 的。 Text 的属性除了 anchors 其它几个都能顾名思义。 anchors 描诉的是当前对象的位置和其它对象的相对关系,这里看到其水平中心位置在“ page “的水平中心位置。如果相对 anchors 了解更多,请参考锚的解释。

以上就是 Hello,World 的全部代码,将其存为 hellowordl.qml ,那么只要执行 qml hellowrold.qml 就能看到文章前头的界面了。

 

更多对象

在上面的代码中我们用到了 Rectangle Text ,那么我还有哪些对象以及这些对象有哪些属性呢。那么请访问 QML-Item ,Item 类是 QML 最基础的类,通过查看它的继承类以及这些继承类可用的属性,你可以添加更多你感兴趣的内容。

好吧 , Happy QML

 

在上一篇文章里我们使用了最基础的 QML 类型实现了文字 Hello,World 的显示。这篇文章中将会增加颜色选项面板,用户可以给 Hello,World 设置不同的颜色, 选项面板由 6 个颜色小块组成,它们唯一的区别就是颜色不一样。那么我们就可以用组件 (Component) 来实现一个颜色块,然后在需要的时候使用这个组件就可以了。组件其实和其它编程语言中的宏,函数,类,结构体等功能差不多,就是代码复用。组件由一个单独的 QML 文件名组成,文件名总是以大写字母开头,要使用该组件的时候直接使用该文件名就可以了。关于如何定义自己的组件,请访问 Defining new Components 。我们为一个颜色块定义了一个 Cell.qml 文件,然后使用 Cell 作为一个去访问它。

Cell.qml 的内容

import Qt 4.7

Item {

    id: container

    property alias cellColor: rectangle.color

    signal clicked(color cellColor)

    width: 40; height: 25

    Rectangle {

        id: rectangle

        border.color: "white"

        anchors.fill: parent

    }

    MouseArea {

        anchors.fill: parent

        onClicked: container.clicked(container.cellColor)

    }

}

 

< 代码详解 >

Item {

id: container

property alias cellColor: rectangle.color

signal clicked(color cellColor)

width: 40; height: 25

Item 是最常使用的 QML 类型,一般用作其它类型的容器,可以理解成最顶级的父类,功能类似于 QtGui 中的 QWidget 。用一个属性别名访问其内嵌对象 rectangle color 属性。在其它文件中可以用 Cell 对象的 cellColor 获得 rectangle color 值。

signal clicked(color cellColor) 则为对象定义了一个信号,在代码的其它部分可以发出这个信号。

Rectangle {

id: rectangle

border.color: “white”

anchors.fill: parent

}

这一部分没有特别好说的,在 Item 中内嵌了一个 id rectangle 白边框的矩形区域,大小占满整个 Item

MouseArea {

anchors.fill: parent

onClicked: container.clicked(container.cellColor)

}

MouseArea 则为 Item 增加了一块鼠标响应区,看它的 anchors 知道,在整个 Item 区域内都是鼠标活动区,都能侦听到鼠标事件。 onClicked 那一行则相当于为鼠标单击事件增加了一个处理行为,这里是发出了一个 clicked() 的信号。这个信号正是我们在 Item 里定义的那个 signal

Cell.qml 写完了,再来看看程序的主文件。

main.qml 的内容

import Qt 4.7

Rectangle {

     id: page

     width: 500; height: 200

     color: "lightgray"

     Text {

         id: helloText

         text: "Hello world!"

         y: 30

         anchors.horizontalCenter: page.horizontalCenter

         font.pointSize: 24; font.bold: true

     }

    Grid {

         id: colorPicker

         x: 4; anchors.bottom: page.bottom; anchors.bottomMargin: 4

         rows: 2; columns: 3; spacing: 3

         Cell { cellColor: "red"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "green"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "blue"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "yellow"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "steelblue"; onClicked: helloText.color = cellColor }

          Cell { cellColor: "black"; onClicked: helloText.color = cellColor }

     }

  }

 

这里在原来的基础上增加了一个 Grid 网格。 x 坐标是 4 ,底部挨着 page 的底部,所以我们看到的是在左下角。

新增的 6 Cell ,名字和 Cell.qml 是一样的。通过 cellColor 属性将颜色传给了每个颜色块。

Cell 接收到 onClicked 事件的时候 , 关联的代码回去修改 Hello,World 上的颜色。细心的朋友可能会注意到 Cell 只是定义了 clicked() 的信号,并没有定义 onClicked() 啊,是的这就是 Component 的语法规则了。如果你在 Cell.qml 里定义的是 plicked(), 那么你在 main.qml 中引用的时候就该用 onPlicked() 了。

 

经过前面两个教程,文字也能显示,也能处理鼠标事件了,接着来点动画。

这个教程实现了当鼠标按住的时候, Hello,World 从顶部到底部的一个旋转过程,并带有颜色渐变的效果。

完整的源代码 main.qml

import Qt 4.7

  Rectangle {

     id: page

     width: 500; height: 200

     color: "lightgray"

     Text {

         id: helloText

         text: "Hello World!"

         y: 30

         anchors.horizontalCenter: page.horizontalCenter

         font.pointSize: 24; font.bold: true

         MouseArea { id: mouseArea; anchors.fill: parent }

         states: State {

             name: "down"; when: mouseArea.pressed == true

             PropertyChanges { target: helloText; y: 160; rotation: 180; color: "red" }

         }

         transitions: Transition {

             from: ""; to: "down"; reversible: true

             ParallelAnimation {

                 NumberAnimation { properties: "y,rotation"; duration: 500; easing.type: Easing.InOutQuad }

                 ColorAnimation { duration: 500 }

             }

         }

     }

     Grid {

         id: colorPicker

         x: 4; anchors.bottom: page.bottom; anchors.bottomMargin: 4

         rows: 2; columns: 3; spacing: 3

         Cell { cellColor: "red"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "green"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "blue"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "yellow"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "steelblue"; onClicked: helloText.color = cellColor }

         Cell { cellColor: "black"; onClicked: helloText.color = cellColor }

     }

  }

除了这个 main.qml 之外,还有一个 Cell.qml 也是需要的。下面来看一看比起上面的代码增加出来的内容。

    Text{

         ...

         states: State {

             name: "down"; when: mouseArea.pressed == true

             PropertyChanges { target: helloText; y: 160; rotation: 180; color: "red" }

         }

         transitions: Transition {

             from: ""; to: "down"; reversible: true

             ParallelAnimation {

                 NumberAnimation { properties: "y,rotation"; duration: 500; easing.type: Easing.InOutQuad }

                 ColorAnimation { duration: 500 }

             }

         }

        ...

     }

states 内嵌于 Text 之中,可以为 Text 元素添加多个状态,现在的这个例子只增加了一个状态。该状态的名” down , 然后由“ when ”指定了什么时候触发这个状态。 PropertyChanges 则指定了哪个元素的哪些属性会发生什么样的变化。例子中 PropertyChanges 利用 target ”指定了 id 为” helloText ”的元素会发生变化,包括其 y,rotation,color 等属性。

transitions 是用于增加动画效果的(如果把 transitions 这一段代码删去, Hello,World 的文字也会发生变化 , 但是看不到中间动画渐变效果 ) 。同样可以看到 transitions 是复数形式,意味着可以添加多个动画过程。“ from ”和” to ”指明了当前的动画作用于哪两个状态变化之间。 from ”和” to ”的参数名来自于 State 中的” name ”属性。

ParalleAnimation 则指定了有多个 有多个动画并行发生。 NumberAnimation 用于 qreal 类型的属性变化 ,ColorAnimation 则用于颜色变化。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值