简单实例教程----(Qt Quick 教程三)_Text

 

Rectangle

Rectangle 用来绘制一个填充矩形,可以带边框,也可以不带,可以使用纯色填充,也可以使用渐变色填充,甚至还可以不填充而只提供边框……

    Rectangle 有很多属性。

    width 用来指定宽, height 用来指定高,我们已经见识过了。 

    color 属性可以指定填充颜色,而 gradient 属性则用来设置渐变色供填充使用,如果你同时指定了 color 和 gradient ,那么 gradient 生效;如果你设置 color 属性为 transparent ,那么就可以达到只绘制边框不填充的效果。

    border.width 指定边框的宽度, border.color 指定边框颜色。

    Rectangle 还可以绘制圆角矩形,你只要设置 radius 属性就行了。
 

Rectangle {
width: 320;
height: 480;
color: "blue";
border.color: "#808080";
border.width: 2;
radius: 12;
}

简单实例教程----(Qt Quick 教程三)_Qt_02

渐变色

    QML 中渐变色的类型是 Gradient ,渐变色通过两个或多个颜色值来指定, QML 会自动在你指定的颜色之间插值,进行无缝填充。Gradient 使用 GradientStop 来指定一个颜色值和它的位置(取值在 0.0 与 1.0 之间)。

Rectangle {
width: 100;
height: 100;
gradient: Gradient {
GradientStop { position: 0.0; color: "#202020"; }
GradientStop { position: 0.33; color: "blue"; }
GradientStop { position: 1.0; color: "#FFFFFF"; }
}
}

简单实例教程----(Qt Quick 教程三)_sed_03

 

 Gradient 只能用来创建垂直方向的渐变,不过其它方向的,可以通过给 Rectangle 指定 rotation 属性来实现。下面是示例:

import QtQuick 2.0

Rectangle {
width: 500;
height: 500;
rotation: 90;
gradient: Gradient {
GradientStop { position: 0.0; color: "#000000"; }
GradientStop { position: 1.0; color: "#A0A0A0"; }
}
}

简单实例教程----(Qt Quick 教程三)_Text_04

 

Item
    Item 是 Qt Quick 中所有可视元素的基类,虽然它自己什么也不绘制,但是它定义了绘制图元所需要的大部分通用属性,比如 x 、 y 、 width 、 height 、 锚定( anchoring )和按键处理。

    Item 的属性特别多,除了前面提到的,还有 scale / smooth / anchors / antialiasing / enabled / visible / state / states / children 等等,详情参考 Qt 帮助文档。

    你可以使用 Item 来分组其它的可视图元。如:

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;
Item {
id: gradientGroup;
Rectangle {
x: 20;
y: 20;
width: 120;
height: 120;
gradient: Gradient {
GradientStop { position: 0.0; color: "#202020"; }
GradientStop { position: 1.0; color: "#A0A0A0"; }
}
}

Rectangle {
x: 160;
y: 20;
width: 120;
height: 120;
rotation: 90;
gradient: Gradient {
GradientStop { position: 0.0; color: "#202020"; }
GradientStop { position: 1.0; color: "#A0A0A0"; }
}
}
}

Component.onCompleted: {
console.log("visible children: " ,gradientGroup.visibleChildren.length);
console.log("visible children: " ,gradientGroup.children.length);
for(var i = 0; i < gradientGroup.children.length; i++){
console.log("child " , i, " x = ", gradientGroup.children[i].x);
}
}
}

简单实例教程----(Qt Quick 教程三)_Qt_05

另外你可能注意到了, x 、 y 、 width 、 height 四个属性结合起来,可以完成 Qt Quick 应用的界面布局,不过这种采用绝对坐标的方式来布局,不太容易适应多种多样的移动设备分辨率。

 

使用 anchors 进行界面布局

 anchors 提供了一种方式,让你可以通过指定一个元素与其它元素的关系来确定元素在界面中的位置。

    你可以想象一下,每个 item 都有 7 条不可见的锚线:左(left)、水平中心(horizontalCenter)、上(top)、下(bottom)、右(right)、垂直中心(verticalCenter)、基线(baseline)。看下图就明白了:

简单实例教程----(Qt Quick 教程三)_sed_06

    在上图中,没有标注基线,基线是用于定位文本的,你可以想象一行文字端坐基线的情景。对于没有文本的图元,baseline 和 top 一致。

    使用 anchors 布局时,除了对齐锚线,还可以在指定上(topMargin)、下(bottomMargin)、左(leftMargin)、右(rightMargin)四个边的留白。看个图就明白了:

简单实例教程----(Qt Quick 教程三)_sed_07

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;

Rectangle {
id: rect1;
anchors.left: parent.left;
anchors.leftMargin: 20;
anchors.top: parent.top;
anchors.topMargin: 20;
width: 120;
height: 120;
gradient: Gradient {
GradientStop { position: 0.0; color: "#202020"; }
GradientStop { position: 1.0; color: "#A0A0A0"; }
}
}

Rectangle {
anchors.left: rect1.right;
anchors.leftMargin: 20;
anchors.top: rect1.top;
width: 120;
height: 120;
rotation: 90;
gradient: Gradient {
GradientStop { position: 0.0; color: "#202020"; }
GradientStop { position: 1.0; color: "#A0A0A0"; }
}
}
}

简单实例教程----(Qt Quick 教程三)_Qt_08

   Item 的 anchors 属性,除了上面介绍的,还有一些,如 centerIn 表示将一个 item 居中放置到另一个 item 内; fill 表示充满某个 item ……更多请参考 Item 类的文档。这里再举个使用 centerIn 和 fill 的示例:

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;

Rectangle {
color: "blue";
anchors.fill: parent;
border.width: 6;
border.color: "#888888";

Rectangle {
anchors.centerIn: parent;
width: 120;
height: 120;
radius: 8;
border.width: 2;
border.color: "black";
antialiasing: true;
color: "red";
}
}
}

简单实例教程----(Qt Quick 教程三)_Text_09

Z 序 与 透明度

 

  Item 除了 x 、 y 属性,其实还有一个 z 属性,用来指定图元在场景中的 Z 序。 z 属性的类型是 real ,数值越小,图元就越垫底(远离我们),数值越大,图元就越靠近我们。

    Item 的属性 opacity 可以指定一个图元的透明度,取值在 0.0 到 1.0 之间。

    结合 Z 序和透明度,有时可以达到不错的效果。下面是一个简单的示例:
------

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;

Rectangle {
x: 20;
y: 20;
width: 150;
height: 100;
color: "#606080";
z: 0.5;
}

Rectangle {
width: 100;
height: 100;
anchors.centerIn: parent;
color: "#a0c080";
z: 1;
opacity: 0.6;
}
}

简单实例教程----(Qt Quick 教程三)_Qt_10

 

按键处理

前面提到 Item 可以处理案件,所有从 Item 继承的元素都可以处理按键,比如 Rectangle ,比如 Button 。这点我们在《Qt on Android:QML 语言基础》一文中介绍附加属性时已经提到。

    Item 通过附加属性 Keys 来处理按键。Keys 对象是 Qt Quick 提供的,专门供 Item 处理按键事件的对象。它定义了很多针对特定按键的信号,比如 onReturnPressed ,还定义了更为普通的 onPressed 和 onReleased 信号,一般地,你可以使用这两个信号来处理按键(请对照 Qt C++ 中的 keyPressEvent 和 keyReleaseEvent 来理解)。它们有一个名字是 event 的 KeyEvent 参数,包含了按键的详细信息。如果一个按键被处理, event.accepted 应该被设置为 true 以免它被继续传递。

    这里举一个简单的例子,检测到 Escape 和 Back 键时退出应用,检测到数字键,就通过 Text 来显示对应的数字。代码如下:
 

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;
color: "#c0c0c0";
focus: true;
Keys.enabled: true;
Keys.onEscapePressed: Qt.quit();
Keys.onBackPressed: Qt.quit();
Keys.onPressed: {
switch(event.key){
case Qt.Key_0:
case Qt.Key_1:
case Qt.Key_2:
case Qt.Key_3:
case Qt.Key_4:
case Qt.Key_5:
case Qt.Key_6:
case Qt.Key_7:
case Qt.Key_8:
case Qt.Key_9:
keyView.text = event.key - Qt.Key_0;
break;
}
}

Text {
id: keyView;
font.bold: true;
font.pixelSize: 24;
text: qsTr("text");
anchors.centerIn: parent;
}
}

简单实例教程----(Qt Quick 教程三)_sed_11

简单实例教程----(Qt Quick 教程三)_Text_12

示例中用到了 onPressed / onEscapePressed / onBackPressed 三个附加信号处理器,其中 onPressed 信号的参数是 event ,包含了按键信息,程序中使用 switch 语句与 Qt 对象的枚举值比较来过滤我们关注的按键。

 

Text

    Text 元素可以显示纯文本或者富文本(使用 HTML 标记修饰的文本)。它有 font / text / color / elide / textFormat / wrapMode / horizontalAlignment / verticalAlignment 等等属性,你可以通过这些属性来决定 Text 元素如何显示文本。

    当不指定 textFormat 属性时, Text 元素默认使用 Text.AutoText ,它会自动检测文本是纯文本还是富文本,如果你明确知道要显示的是富文本,可以显式指定 textFormat 属性。

    下面是一个简单示例,显示蓝色的问题,在单词分界处断行:
 

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;
Text {
width: 150;
height: 100;
wrapMode: Text.WordWrap;
font.bold: true;
font.pixelSize: 24;
font.underline: true;
text: "Hello Blue Text";
anchors.centerIn: parent;
color: "blue";
}
}

简单实例教程----(Qt Quick 教程三)_Text_13

简单实例教程----(Qt Quick 教程三)_Text_14

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;
Text {
width: 150;
height: 100;
wrapMode: Text.WordWrap;
font.bold: true;
font.pixelSize: 24;
font.underline: true;
text: "Hello Blue <font color=\"blue\">Text</font>";
anchors.centerIn: parent;
}
}

 Text 元素的 style 属性提供了几种文字风格,Text.Outline 、 Text.Raised 、 Text.Sunken ,可以使文字有点儿特别的效果。而 styleColor 属性可以和 style 配合使用(如果没有指定 style ,则 styleColor 不生效),比如 style 为 Text.Outline 时,styleColor 就是文字轮廓的颜色。看个简单的示例:

import QtQuick 2.0

Rectangle {
width: 300;
height: 200;
Text {
id: normal;
anchors.left: parent.left;
anchors.leftMargin: 20;
anchors.top: parent.top;
anchors.topMargin: 20;
font.pointSize: 24;
text: "Normal Text";
}
Text {
id: raised;
anchors.left: normal.left;
anchors.top: normal.bottom;
anchors.topMargin: 4;
font.pointSize: 24;
text: "Raised Text";
style: Text.Raised;
styleColor: "#AAAAAA" ;
}
Text {
id: outline;
anchors.left: normal.left;
anchors.top: raised.bottom;
anchors.topMargin: 4;
font.pointSize: 24;
text: "Outline Text";
style: Text.Outline;
styleColor: "red";
}
Text {
anchors.left: normal.left;
anchors.top: outline.bottom;
anchors.topMargin: 4;
font.pointSize: 24;
text: "Sunken Text";
style: Text.Sunken;
styleColor: "#A00000";
}
}

简单实例教程----(Qt Quick 教程三)_sed_15

 

Button

    按钮可能是 GUI 应用中最常用的控件了。 QML 中的 Button 和 QPushButton 类似,用户点击按钮会触发一个 clicked() 信号,在 QML 文档中可以为 clicked() 指定信号处理器,响应用户操作。

    要使用 Button ,需要引入 import QtQuick.Controls 1.1 。

    先看一个简单的示例,点击按钮,退出应用。代码如下:

import QtQuick 2.0
import QtQuick.Controls 1.1

Rectangle {
width: 300;
height: 200;
Button {
anchors.centerIn: parent;
text: "Quit";
onClicked: Qt.quit();
}
}

简单实例教程----(Qt Quick 教程三)_Text_16

现在我们再来看 Button 都有哪些属性。

    text 属性指定按钮文字,见过了。

    checkable 属性设置 Button 是否可选。如果 Button 可选 checked 属性则保存 Button 选中状态。其实我一直没用过这个属性……

    iconName 属性指定图标的名字,如果平台的图标主题中存在该名字对应的资源, Button 就可以加载并显示它。iconSource 则通过 URL 的方式来指定 icon 的位置。iconName 属性的优先级高于 iconSource 。

    isDefault 属性指定按钮是否为默认按钮,如果是默认的,用户按 Enter 键就会触发按钮的 clicked() 信号。

    pressed 属性保存了按钮的按下状态。

    menu 属性,允许你给按钮设置一个菜单(此时按钮可能会出现一个小小的下拉箭头),用户点击按钮时会弹出菜单。默认是 null 。

    action 属性,允许设定按钮的 action ,action 可以定义按钮的 checked , text ,tooltip 等属性。默认是 null 。

    activeFocusOnPress ,指定当用户按下按钮时是否获取焦点,默认是 false 。

    style 属性用来定制按钮的风格,与它配套的有一个 ButtonStyle 类,允许你定制按钮的背景。

    其实 Button 比较简单好用,我不准备再啰嗦下去了,咱再看下 style 的使用就结束对 Button 的介绍。

ButtonStyle
    要使用 ButtonStyle 需要引入 QtQuick.Controls.Styles 1.1 。

    ButtonStyle 类有 background 、 control 、 label 三个属性。我们通过重写 background 来定制一个按钮。 control 属性指向应用 ButtonStyle 的按钮对象,你可以用它访问按钮的各种状态。 label 属性代表按钮的文本,如果你看它不顺眼,也可以替换它。

    background 实际是一个 Component 对象, Component(组件) 的概念我们回头讲。这里我们简单的使用 Rectangle 来定制按钮的背景。看下面的示例:
 

import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1

Rectangle {
width: 300;
height: 200;
Button {
text: "Quit";
anchors.centerIn: parent;
style: ButtonStyle {
background: Rectangle {
implicitWidth: 70;
implicitHeight: 25;
border.width: control.pressed ? 2 : 1;
border.color: (control.hovered || control.pressed) ? "green" : "#888888";
}
}
}
}

简单实例教程----(Qt Quick 教程三)_Text_17

通过给 style 对象指定一个 ButtonStyle 对象来定制 Button 的风格。这个就地实现的 ButtonStyle 对象,重写了 background 属性,通过 Rectangle 对象来定义按钮背景。我定义了背景的建议宽度和高度,根据按钮的 pressed 属性( control 是实际按钮的引用 )来设置背景矩形的边框粗细,而边框颜色则随着按钮的 hovered 和 pressed 属性来变化。
    最终的效果是这样的:当鼠标悬停在按钮上时,边框颜色为绿色;当鼠标按下时,边框变粗且颜色为绿色。
    对于 ButtonStyle ,如果有多个按钮同时用到,上面的方式就有点繁琐了,可以像下面这样使用:

import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1

Rectangle {
width: 300;
height: 200;

Component{
id: btnStyle;
ButtonStyle {
background: Rectangle {
implicitWidth: 70;
implicitHeight: 25;
color: "#DDDDDD";
border.width: control.pressed ? 2 : 1;
border.color: (control.hovered || control.pressed) ? "green" : "#888888";
}
}
}

Button {
id: openButton;
text: "Open";
anchors.left: parent.left;
anchors.leftMargin: 10;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 10;
style: btnStyle;
}

Button {
text: "Quit";
anchors.left: openButton.right;
anchors.leftMargin: 6;
anchors.bottom: openButton.bottom;
style: btnStyle;
}
}

简单实例教程----(Qt Quick 教程三)_Text_18

Image 

  Image 可以显示一个图片,只要是 Qt 支持的,比如 JPG 、 PNG 、 BMP 、 GIF 、 SVG 等都可以显示。它只能显示静态图片,对于 GIF 等格式,只会把第一帧显示出来。如果你要显示动画,可以使用 AnimateSprite 或者 AnimateImage 。

    Image 的 width 和 height 属性用来设定图元的大小,如果你没有设置它们,那么 Image 会使用图片本身的尺寸。如果你设置了 width 和 height ,那么图片就可能会拉伸来适应这个尺寸。此时 fillMode 属性可以设置图片的填充模式,它支持 Image.Stretch(拉伸) 、 Image.PreserveAspectFit(等比缩放) 、 Image.PreserveAspectCrop(等比缩放,最大化填充 Image ,必要时裁剪图片) 、 Image.Tile(在水平和垂直两个方向平铺,就像贴瓷砖那样) 、 Image.TileVertically(垂直平铺) 、 Image.TileHorizontally(水平平铺) 、 Image.Pad(保持图片原样不作变换) 等模式。

    Image 默认会阻塞式的加载图片,如果要显示的图片很小,没什么问题,如果分辨率很高,麻烦就来了。此时你可以设置 asynchronous 属性为 true 来开启异步加载模式,这种模式下 Image 使用一个线程来加载图片,而你可以在界面上显示一个等待图标之类的小玩意儿来告诉用户它需要等会儿。然后当 status(枚举值) 的值为 Image.Ready 时再隐藏加载等候界面。

    比较强悍的是, Image 支持从网络加载图片。它的 source 属性类型是 url ,可以接受 Qt 支持的任意一种网络协议,比如 http 、 ftp 等。而当 Image 识别到你提供的 source 是网络资源时,会自动启用异步加载模式。此时呢,Image 的 progress(取值范围 0.0 至 1.0 ),status(枚举值)都会适时更新,你可以根据它们判断何时结束你的加载等候提示界面。

    算,先到这儿,看看怎么用吧。下面是最简的示例:
 

import QtQuick 2.0

Image {
source: "images/yourimage.png"
}

source 替换为一个实际存在的图片路径就可以看到效果。

显示网络图片

 下面是一个稍微复杂点儿的示例,显示网络上的图片,在下载和加载前显示一个转圈圈的 Loading 图标,图片加载成功后隐藏 Loading 图标,如果加载出错,则显示一个简单的错误消息。看代码:

import QtQuick 2.0
import QtQuick.Controls 1.1

Rectangle {
width: 480;
height: 320;
color: "#121212";

BusyIndicator {
id: busy;
running: true;
anchors.centerIn: parent;
z: 2;
}

Label {
id: stateLabel;
visible: false;
anchors.centerIn: parent;
z: 3;
}

Image {
id: imageViewer;
asynchronous: true;
cache: false;
anchors.fill: parent;
fillMode: Image.PreserveAspectFit;
onStatusChanged: {
if (imageViewer.status === Image.Loading) {
busy.running = true;
stateLabel.visible = false;
}
else if(imageViewer.status === Image.Ready){
busy.running = false;
}
else if(imageViewer.status === Image.Error){
busy.running = false;
stateLabel.visible = true;
stateLabel.text = "ERROR";
}
}
}

Component.onCompleted: {
imageViewer.source = "http://image.cuncunle.com/Images/EditorImages/2013/01/01/19/20130001194920468.JPG";
}
}

Image 对象,设置了 asynchronous 属性为 true,不过对于网络资源 Image 默认异步加载,这个属性不起作用,只有你想异步加载本地资源时才需要设置它。 cache 属性设置为 false ,告诉 Image 不用缓存图片。 fillMode 属性我设置了等比缩放模式。

    onStatusChanged 是信号处理器,Image 的 status 属性变化时会发射 statusChanged() 信号。之前在《QML 语言基础》中介绍信号处理器时我们知道,信号处理器遵循 on{Signal} 语法,所以我们这里的名字是 onStatusChanged 。在信号处理器的代码块中,我通过 Image 对象的 id 访问它的 status 属性,根据不同的状态来更新界面。

    可能你会奇怪,在 Qt 帮助中, Image 类的参考手册里没有明确提到 statusChanged 信号。其实呢,还有很多的信号, Qt 的文档里都没有提到,呜呜,怎么办呢?教你个诀窍,去 SDK 头文件中找,比如 Image 的头文件是 Qt5.2.0\5.2.0\mingw48_32\include\QtQuick\5.2.0\QtQuick\private\qquickimage_p.h ,阅读这个头文件你会看到 QML 中的 Image 对应的 Qt C++ 中的 QQuickImage 类,而 QQuickImage 的父类是 QQuickImageBase ,QQuickImageBase 的类声明在文件 Qt5.2.0\5.2.0\mingw48_32\include\QtQuick\5.2.0\QtQuick\private\qquickimagebase_p.h 中,找到这里就找到 status 属性的真身了,看下面的代码:

Q_PROPERTY(Status status READ status NOTIFY statusChanged)
    Q_PROPERTY 宏用来定义 QObject 及其派生类的属性,这样定义的属性可以在 QML 中访问。上面的语句定义了只读的 status 属性并且指明当属性变化时发送 statusChanged 信号。

简单实例教程----(Qt Quick 教程三)_Qt_19

 

BusyIndicator

  BusyIndicator 用来显示一个等待图元,在进行一些耗时操作时你可以使用它来缓解用户的焦躁情绪。

    BusyIndicator 的 running 属性是个布尔值, 为 true 时显示。 style 属性允许你定制 BusyIndicator 。默认的效果就是前面图示的那种,一个转圈圈的动画。

    至于 BusyIndicator 的使用,下面是显示网络图片示例的代码,再温习下:
 

BusyIndicator {
id: busy;
running: true;
anchors.centerIn: parent;
z: 2;
}

简单实例教程----(Qt Quick 教程三)_Qt_20

简单实例教程----(Qt Quick 教程三)_sed_21