除前面介绍的Row、Column和Grid等外,QML还提供了一种使用Anchor(锚)来进行元素布局的方法。每个元素都可被认为有一组无形的“锚线”:left、horizontalCenter、right、top、verticalCenter和bottom,如下图所示。Text元素还有一个baseline锚线(对于没有文本的元素,它与top相同)。
这些锚线分别对应元素中的anchors.left、anchors.horizontalCenter等属性,所有的可视元素都可以使用锚来布局。锚系统还允许为一个元素的锚指定边距(margin)和偏移(offset)。边距指定了元素锚到外边界的空间量,而偏移允许使用中心锚线来定位。一个元素可以通过leftMargin、rightMargin、topMargin和bottomMargin来独立地指定错边距,如下图所示,也可以使用anchor.margins来为所有的4个铺指定相同的边距。
锚偏移使用horizontalCenterOffset、verticalCenterOffset和baselineOffset来指定。编程中还经常用anchors.fill将一个元素充满另一个元素,这等价于使用了4个直接的锚。但要注意,只能在父子或兄弟元素之间使用锚,而且基于锚的布局不能与绝对的位置定义(如直接设置x和y属性值)混合使用,否则会出现不确定的结果。
使用Anchor布局一组矩形元素,并测试锚的特性,布局运行效果如图所示。
具体实现步骤如下。
(1) 新建QML应用程序,项目名称为“Anchor”。
(2) 本文实例需要复用之前己开发的组件。
将前面文章实例中的源文件“Button.qml”、“RedRectangle.qml”、“GreenRectangle.qml”及“BlueRectangle.qml”复制到本项目目录下。右击项目视图“Resources” 一 “qml.qrc”下的“/’节点,选择“Add Existing Files...”项,弹出“Add Existing Files”对话框,选中上述几个.qml文件,单击“打开”按钮将它们添加到当前项目中。
(3) 打开“main.qml”文件,编写代码如下:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
width: 320
height: 240
visible: true
title: qsTr("Anchor")
Rectangle {
id: windowRect
/*定义属性别名*/ // (a)
property alias chgRect1: changingRect1 //矩形changingRect1属性别名
property alias chgRect2: changingRect2 //矩形changingRect2属性别名
property alias rRect: redRect //红矩形redRect属性别名
width: 360
height: 360
anchors.fill: parent
/* 使用Anchor对三个矩形元素进行横向布局 */ //(b)
BlueRectangle { //蓝矩形
id : blueRect
anchors.left: parent.left //与窗口左锚线锚定
anchors.top: parent.top //与窗口顶锚线锚定
anchors.leftMargin: 25 //左锚边距(与窗口左边距)
anchors.topMargin: 25 //顶锚边距(与窗口顶边距)
}
GreenRectangle { //绿矩形
id:greenRect
anchors.left: blueRect.right //绿矩形左锚线与蓝矩形的右锚线锚定
anchors.top: blueRect.top //绿矩形顶锚线与蓝矩形的顶锚线锚定
anchors.leftMargin: 40 //左锚边距(与蓝矩形的间距)
}
RedRectangle { //红矩形
id:redRect
anchors.left: greenRect.right //红矩形左锚线与绿矩形的右锚线锚定
anchors.top: greenRect.top //红矩形顶锚线与绿矩形的顶锚线锚定
anchors.leftMargin: 40 //左锚边距(与绿矩形的间距)
}
/*对比测试Anchor的性质*/ //(c)
RedRectangle {
id:changingRect1
anchors.left: parent.left //矩形 changingRect1 初始与窗体左锚线锚定
anchors.top: blueRect.bottom
anchors.leftMargin: 25
anchors.topMargin: 25
}
RedRectangle {
id:changingRect2
anchors.left: parent.left //changingRect2与 changingRect1 左对齐
anchors.top: changingRect1.bottom
anchors.leftMargin: 25
anchors.topMargin: 20
}
/*复用按钮*/
Button {
width:95
height:35 //(d)
anchors.right: redRect.right
anchors.top: changingRect2.bottom
anchors.topMargin: 10
}
}
}
其中,
- (a) /*定义属性别名*/:这里定义矩形changingRect1、changingRect2及redRect的别名,目的是在按钮组件的源文件(外部QML文档)中能访问这几个元素,以便测试它们的锚定特性。
- (b) /* 使用Anchor对三个矩形元素进行横向布局 */:这段代码使用己定义的三个现成矩形元素,通过分别设置anchors.left、anchors.top、anchors.leftMargin、anchors.topMargin等锚属性,对它们进行从左到右的布局,这与之前介绍的Row的布局作用一样。读者还可以修改其他锚属性以尝试更多的布局效果。
- (c) /*对比测试Anchor的性质*/:锚属性还可以在程序运行中通过代码设置来动态地改变,为了对比,本例设计使用两个相同的红矩形,初始它们都与窗体左锚线锚定(对齐),然后改变右锚属性来观察它们的行为。
- (d) width:95; height:35:按钮组件原定义尺寸为“width: 100; height:62”,复用时可以重新定义它的尺寸属性以使程序界面更美观。新属性值会“覆盖”原来的属性值,就像面向对象的“继承”一样提高了灵活性。
(4)打开“Button.qml”文件,修改代码如下:
import QtQuick 2.0
Rectangle { //将Rectangle自定义成按钮
id:btn
width:100;height:62 //按钮的尺寸
color: "teal" //按钮颜色
border.color: "aqua" //按钮边界色
border.width: 3 //按钮边界宽度
Text { //Text元素作为按钮文本
id: label
anchors.centerIn: parent
font.pointSize: 16
text: "开始"
}
MouseArea { //MouseArea对象作为按钮单击事件响应区
anchors.fill: parent
onClicked: {//响应单击事件代码
label.text = "按钮已按下!"
label.font.pointSize = 11 //改变按钮文本和字号
btn.color = "aqua" //改变按钮颜色
btn.border.color = "teal" //改变按钮边界色
/* 改变changingRect1的右锚属性 */ //(a)
windowRect.chgRect1.anchors.left = undefined;
windowRect.chgRect1.anchors.right = windowRect.rRect.right;
/* 改变 changingRect2 的右锚属性 */ // (b)
windowRect.chgRect2.anchors.right = windowRect.rRect.right;
windowRect.chgRect2.anchors.left = undefined;
}
}
}
其中,
- (a) /* 改变changingRect1的右锚属性 */:这里用“windowRect.chgRect1.anchors.left = undefined”先解除其左锚属性的定义,然后再定义右锚属性,执行后,该矩形便会移动到与redRect(第一行最右边的红矩形)右对齐。
- (b) /* 改变 changingRect2 的右锚属性 */:这里先用“windowRect.chgRect2.anchors.right = windowRect.rRect.right”指定右锚属性,由于此时元素的左描属性尚未解除,执行后,矩形位置并不会移动,而是宽度自动“拉长”到与redRect右对齐,之后即使再解除左锚属性也无济于事,故用户在编程改变布局时,一定要先将元素的旧锚解除,新设置的锚才能生效!
鼠标点击按钮后如下图所示。
————————————————
觉得有用的话请关注点赞,谢谢您的支持!
对于本系列文章相关示例完整代码有需要的朋友,可关注并在评论区留言!