您的位置:首页 > 其它

QML范例详解

2015-10-19 20:44 197 查看
研究了一段时间QML,现在对Qt中的一个计算器范例的代码进行分析,并总结一下前面学习的内容.Qt这种语言大多数还是被用于嵌入式设备上,而QML则是专为嵌入式设备而生的.Qt在桌面开发上占据的比例很小,而且已被Nokia出售,未来的前景如何谁也不好说.但Qt确实很棒,祝福一下吧,如果以后Qt支持android和苹果的开发了,在继续深入研究.



上图是运行效果图,界面风格确实很漂亮.鼠标点击按钮后还有一个变灰的反应,整体来说界面简洁大气.而且实现了计算器的基本功能,这里要说明的是,所有功能都是由QML独立完成的,没有任何qt插件参与.而且调整界面的尺寸后,还会使界面发生旋转.这样的功能这样的界面效果要是使用Qt或Delphi,VC来实现的话,相信还是有一点的工作量的.正如前面翻译的文章中所说的那样,QML适合于界面上有大量简单动态元素的情形.像这种计算器程序或时钟程序使用QML实现就太方便了.

在总结一下以前翻译的几篇文章中的要点:QML中的核心是属性绑定,对象的属性发生了变化不一定就一定有函数在给属性赋值.可能是其他的属性与其有绑定关系,当这些属性发生变化时,QML引擎会自动为属性重新计算值.动画效果的实现依靠State和Transition.闲话少说,直接分析代码吧.

计算器程序的组织结构

在core目录中,定义了按钮组件Button和显示计算器输入信息及计算结果的Display组件.core/images目录中是按钮的图片和Display组件的背景图片.



还有一个qmldir文件,这个文件没有后缀.其中存储了目录中组件的名称和位置.

按钮组件

先来看看Button.qml文件的定义.这个文件定义了按钮组件,为了分析方便,我将原码直接拷贝过来,每行代码后面加上注释.

import QtQuick 1.0 //导入QML基本元素 版本号为1.0

BorderImage { //声明一个BorderImage元素 BorderImage一般用来作为边界图像.这里直接用来显示按钮图像

id: button //设置其唯一标识

property alias operation: buttonText.text //定义一个属性别名供外部使用,当给operation赋值或读取operation时,实际上在操作buttonText.text的值 buttonText元素在后面定义

property string color: "" //定义字符串属性color,默认值为""

signal clicked //定义一个信号,这里的信号和Qt中的信号概念上相同,用法上也一致

//source属性指定其图片的地址,注意这里使用了属性绑定,最终的值与color有关,

//如果color的值发生了变化,source的值自动变化.最终计算的source值正好是上图中几个按钮的背景图片的名称

source: "images/button-" + color + ".png"; clip: true

border { left: 10; top: 10; right: 10; bottom: 10 } //设置边界 定义了图像距离外边框的距离 这里上下左右都空闲10个像素

Rectangle { //声明了一个矩形,这个矩形在鼠标点击的时候设置opacity为0.4,使按钮变灰.但不会影响按钮上显示的文字,因为文字是在其下方声明的.

id: shade //设置唯一标示

anchors.fill: button; /*完全平铺到button上*/radius: 10;/*定义圆角半径*/ color: "black"; opacity: 0/*定义了透明度,0为完全透明,1为完全不透明*/

}

Text { //声明按钮上的文本

id: buttonText //设置唯一标识 上面定义属性property alias operation: buttonText.text就引用了这个标识.Text上显示的文本就是text属性的值

anchors.centerIn: parent;/*居中显示*/ anchors.verticalCenterOffset: -1/*垂直居中偏移-1像素*/

font.pixelSize: parent.width > parent.height ? parent.height * .5 : parent.width * .5 //计算字体大小,为按钮宽高最小值的一半

style: Text.Sunken;/*设置文本风格*/ color: "white"; styleColor: "black"; smooth: true

}

MouseArea { //设置鼠标响应区域

id: mouseArea

anchors.fill: parent //整个按钮区域都可响应鼠标

onClicked: {

doOp(operation) //定义doOp函数,注意doOp在calculator.qml中定义,这个qml引用了Button.qml,由于qml是声明式的,因此可先引用后声明(定义).

button.clicked() //触发button的click信号

}

}

states: State { //定义State实现动画效果 这个State实现当mouseArea是鼠标按下状态时,修改shade的属性opacity的值为0.4,也就是当按钮被按下时看到一层淡淡的灰色.

name: "pressed"; when: mouseArea.pressed == true //when关键字定义状态触发的条件

PropertyChanges { target: shade; opacity: .4 } //改变shade的opacity属性

}

}

Display组件

import QtQuick 1.0 //导入1.0版本的QtQuick模块

BorderImage { //定义显示背景图片元素

id: image //唯一标识

property alias text : displayText.text //属性别名 设置text就是给displayText.text赋值

property alias currentOperation : operationText //属性别名 这是一个Text元素类型的属性

source: "images/display.png" //设备背景图片

border { left: 10; top: 10; right: 10; bottom: 10 } //设置图片与边框的距离

Text {

id: displayText

anchors { //定位

right: parent.right;/*右侧与父对象的右侧对齐*/ verticalCenter: parent.verticalCenter;/*垂直居中*/ verticalCenterOffset: -1/*垂直偏移量-1 显示稍偏下*/

rightMargin: 6; /*右边界间隔6个像素*/left: operationText.right/*左侧与operationText的右侧对齐*/

}

font.pixelSize: parent.height * .6; text: "0"; horizontalAlignment: Text.AlignRight; elide: Text.ElideRight

color: "#343434"; smooth: true; font.bold: true

}

Text {

id: operationText

font.bold: true;/*粗体*/ font.pixelSize: parent.height * .7

color: "#343434"; smooth: true

anchors { left: parent.left;/*靠左显示*/ leftMargin: 6;/*左侧边距6像素*/ verticalCenterOffset: -3; verticalCenter: parent.verticalCenter }

}

}

Display组件定义了一个背景图,上面有两个Text,这两个Text一个靠左,一个靠右,平铺在Display组件上,而且两个Text直接具有描点关系:anchors{displayText.left: operationText.right}.displayText的左侧总与operationText的右侧相连.说明在改变大小时operationText不变,而displayText是可伸展的.

calculator定义

两个共用组件介绍完了,现在看看calculator.qml.这是计时器的定义文件.

import QtQuick 1.0

import "Core" //导入Core目录中定义的组件 引擎查找目录中的qmldir文件(无后缀),根据其中的内容导入定义的组件.

import "Core/calculator.js" as CalcEngine //导入javaScript文件内容 也可作为一个组件来看,并定义了组件别名,下面使用文件中定义的函数时可用:别名.方法名

Rectangle {

id: window

width: 360; height: 480 //定义窗口尺寸

color: "#282828"

property string rotateLeft: "\u2939"

property string rotateRight: "\u2935"

property string leftArrow: "\u2190"

property string division : "\u00f7"

property string multiplication : "\u00d7"

property string squareRoot : "\u221a"

property string plusminus : "\u00b1"

function doOp(operation) { CalcEngine.doOperation(operation) } //定义了个函数,供下面调用.这个函数又调用了js文件中的doOperation函数,注意参数operation是按钮上的文字内容.

Item {

id: main

state: "orientation " + runtime.orientation //runtime.orienttation返回界面的显示方向. 如果方向改变,就会重新设置state的值,其属性也会按state定义的相应更改.

property bool landscapeWindow: window.width > window.height

property real baseWidth: landscapeWindow ? window.height : window.width //取宽高中最小的那个值

property real baseHeight: landscapeWindow ? window.width : window.height //取宽高中最大的那个值

property real rotationDelta: landscapeWindow ? -90 : 0

rotation: rotationDelta //根据窗口宽与高的大小来调整旋转角度,只用一行代码搞定界面旋转

width: main.baseWidth

height: main.baseHeight

anchors.centerIn: parent

//定义一个Column元素,单列排布其中的子元素.上面是Display 下面是多个按钮的区域

Column {

id: box; spacing: 8

anchors { fill: parent; topMargin: 6; bottomMargin: 6; leftMargin: 6; rightMargin: 6 }

//显示Display组件

Display {

id: display

width: box.width-3

height: 64

}

//定义按钮区域 应使用Column元素声明 其中的子元素垂直分布 共分三个区域按钮 界面中紫色,绿色,及下面的其他按钮三个部分

Column {

id: column; spacing: 6

property real h: ((box.height - 72) / 6) - ((spacing * (6 - 1)) / 6)//计算出每个按钮的高度

property real w: (box.width / 4) - ((spacing * (4 - 1)) / 4) //计算出每个按钮的宽度

//定义紫色按钮区域 按钮之所以显示为紫色,因为Button的color属性设置为purple,在Button按钮组件定义中,其背景图片的source属性与color绑定,确定了显示哪个图片

Row { //Row元素定义一行,其中包含的元素水平布局

spacing: 6

Button { width: column.w; height: column.h; color: 'purple'; operation: "Off" }

Button { width: column.w; height: column.h; color: 'purple'; operation: leftArrow }

Button { width: column.w; height: column.h; color: 'purple'; operation: "C" }

Button { width: column.w; height: column.h; color: 'purple'; operation: "AC" }

}

//定义绿色按钮区域

Row {

spacing: 6

property real w: (box.width / 4) - ((spacing * (4 - 1)) / 4)

Button { width: column.w; height: column.h; color: 'green'; operation: "mc" }

Button { width: column.w; height: column.h; color: 'green'; operation: "m+" }

Button { width: column.w; height: column.h; color: 'green'; operation: "m-" }

Button { width: column.w; height: column.h; color: 'green'; operation: "mr" }

}

//定义其他按钮

Grid { //Grid元素定义一个网格,其中的元素都占据一个小格

id: grid; rows: 5;/*指定网格的行数*/ columns: 5;/*指定网格的列数*/ spacing: 6

property real w: (box.width / columns) - ((spacing * (columns - 1)) / columns)

Button { width: grid.w; height: column.h; operation: "7"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "8"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "9"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: division }

Button { width: grid.w; height: column.h; operation: squareRoot }

Button { width: grid.w; height: column.h; operation: "4"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "5"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "6"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: multiplication }

Button { width: grid.w; height: column.h; operation: "x^2" }

Button { width: grid.w; height: column.h; operation: "1"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "2"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "3"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "-" }

Button { width: grid.w; height: column.h; operation: "1/x" }

Button { width: grid.w; height: column.h; operation: "0"; color: 'blue' }

Button { width: grid.w; height: column.h; operation: "." }

Button { width: grid.w; height: column.h; operation: plusminus }

Button { width: grid.w; height: column.h; operation: "+" }

Button { width: grid.w; height: column.h; operation: "="; color: 'red' }

}

}

}

//定义状态,main元素的state属性指定为如下状态名称时,其属性值就会发生改变 通常为了具有动画效果,states要与transitions配合使用

states: [

State {

name: "orientation " + Orientation.Landscape

PropertyChanges { target: main; rotation: 90 + rotationDelta; width: main.baseHeight; height: main.baseWidth }

},

State {

name: "orientation " + Orientation.PortraitInverted

PropertyChanges { target: main; rotation: 180 + rotationDelta; }

},

State {

name: "orientation " + Orientation.LandscapeInverted

PropertyChanges { target: main; rotation: 270 + rotationDelta; width: main.baseHeight; height: main.baseWidth }

}

]

//定义动画效果

transitions: Transition {

SequentialAnimation { //定义一个顺序执行的动画

RotationAnimation { direction: RotationAnimation.Shortest; duration: 300; easing.type: Easing.InOutQuint } //旋转动画效果属性

NumberAnimation { properties: "x,y,width,height"; duration: 300; easing.type: Easing.InOutQuint } //在x,y,width,height属性发生变化时的动画属性

}

}

}

}

算法

计时器的算法定义在一个单独的JavaScript文件中.

var curVal = 0

var memory = 0

var lastOp = ""

var timer = 0

function disabled(op) {

if (op == "." && display.text.toString().search(/\./) != -1) {

return true

} else if (op == squareRoot && display.text.toString().search(/-/) != -1) {

return true

} else {

return false

}

}

function doOperation(op) {

if (disabled(op)) {

return

}

if (op.toString().length==1 && ((op >= "0" && op <= "9") || op==".") ) {

if (display.text.toString().length >= 14)

return; // No arbitrary length numbers

if (lastOp.toString().length == 1 && ((lastOp >= "0" && lastOp <= "9") || lastOp == ".") ) {

display.text = display.text + op.toString()

} else {

display.text = op

}

lastOp = op

return

}

lastOp = op

if (display.currentOperation.text == "+") { //已经按下了+号

display.text = Number(display.text.valueOf()) + Number(curVal.valueOf())

} else if (display.currentOperation.text == "-") {

display.text = Number(curVal) - Number(display.text.valueOf())

} else if (display.currentOperation.text == multiplication) {

display.text = Number(curVal) * Number(display.text.valueOf())

} else if (display.currentOperation.text == division) {

display.text = Number(Number(curVal) / Number(display.text.valueOf())).toString()//开始计算

} else if (display.currentOperation.text == "=") {

}

if (op == "+" || op == "-" || op == multiplication || op == division) {

display.currentOperation.text = op

curVal = display.text.valueOf()

return

}

curVal = 0

display.currentOperation.text = ""

if (op == "1/x") {

display.text = (1 / display.text.valueOf()).toString()

} else if (op == "x^2") {

display.text = (display.text.valueOf() * display.text.valueOf()).toString()

} else if (op == "Abs") {

display.text = (Math.abs(display.text.valueOf())).toString()

} else if (op == "Int") {

display.text = (Math.floor(display.text.valueOf())).toString()

} else if (op == plusminus) {

display.text = (display.text.valueOf() * -1).toString()

} else if (op == squareRoot) {

display.text = (Math.sqrt(display.text.valueOf())).toString()

} else if (op == "mc") {

memory = 0;

} else if (op == "m+") {

memory += display.text.valueOf()

} else if (op == "mr") {

display.text = memory.toString()

} else if (op == "m-") {

memory = display.text.valueOf()

} else if (op == leftArrow) {

display.text = display.text.toString().slice(0, -1)

if (display.text.length == 0) {

display.text = "0"

}

} else if (op == "Off") {

Qt.quit();

} else if (op == "C") {

display.text = "0"

} else if (op == "AC") {

curVal = 0

memory = 0

lastOp = ""

display.text ="0"

}

}

FROM: http://blog.csdn.net/henreash/article/details/7952175
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: