QT Quick-定位组件和布局

前言

QT Quick中布局一般有如下四种方式,

  1. 绝对定位:x、y、z、width、height
  2. 锚定位(anchors、相对定位)
  3. 定位器(Row、Column、Grid、Flow)
  4. 布局管理器(RowLayout、ColumnLayout、GridLayout、StackLayout)

绝对布局很好理解,给值就显示,但是不灵活;

anchors 实际上是 Item 的一个属性集

Row 则是一个单独的 Item ,专门用来管理其它 Item 的,后面介绍的几种布局,也是类似的。

锚(anchors) 布局的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//左上右下对齐
anchors.left : AnchorLine
anchors.top : AnchorLine
anchors.right : AnchorLine
anchors.bottom : AnchorLine

//Margin
anchors.leftMargin : real
anchors.topMargin : real
anchors.rightMargin : real
anchors.bottomMargin : real
anchors.margins : real

//基线对齐及偏移
anchors.baseline : AnchorLine
anchors.baselineOffset : real


anchors.mirrored : bool
anchors.fill : Item

//居中与偏移
anchors.centerIn : Item
anchors.horizontalCenter : AnchorLine
anchors.verticalCenter : AnchorLine
anchors.horizontalCenterOffset : real
anchors.verticalCenterOffset : real

其中

  • real 具体的数值
  • Item是组建的ID或者parent
  • bool是true或false
  • AnchorLine 示例anchors.horizontalCenter: parent.horizontalCenter

注意

不要在Row或RowLayout相关的组件中使用anchors,会导致组件本身的特性不生效。

使用场景

  • ItemRectangle中的组件我们可以使用绝对定位锚定位
  • 定位器布局管理器中自动定位的方向不要使用绝对定位锚定位,比如Column的子组件就不要设置y
  • 定位器中没有类似margin和padding的功能,我们可以使用spacing来调整间距,如果间距不固定,可以使用Item组件占位。
  • 布局管理器相当于flex布局,子组件使用Layout.xxx来调整位置

定位组件和布局管理器

image-20211103002943491

定位器(Row、Column、Grid、Flow)

布局管理器(RowLayout、ColumnLayout、GridLayout、StackLayout)

Layout

要使用layout布局的属性 需要引用

1
import QtQuick.Layouts 1.15

简单示例

横向分布,最后一个填充剩余空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15

Window {
width: 640
height: 480
visible: true
color: "#f3f3f3"
title: qsTr("主页面")

RowLayout {
id: row
height: 200
spacing: 0
anchors.left:parent.left
anchors.right:parent.right

Rectangle {
id: rectangle
width: 200
height: parent.height
color: "red"
}
Rectangle {
id: rectangle2
width: 200
height: parent.height
color: "green"
}
Rectangle {
id: rectangle3
height: parent.height
color: "blue"
Layout.fillWidth: true
}

}
}

显示效果

image-20211102233725218

其中

1
2
3
4
5
6
7
RowLayout {
id: row
height: 200
spacing: 0
anchors.left:parent.left
anchors.right:parent.right
}

1
2
3
4
5
6
RowLayout {
id: row
height: 200
width:parent.width
spacing: 0
}

是等效的,前者就用了锚(anchors) 布局

只有在Layout相关的控件中才能使用Layout.fillWidth: true相关的属性。

所以RowLayout可以实现元素填充剩余空间,而Row是不可以的,除非我们复制宽度是通过计算的值。

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15

Window {
width: 640
height: 480
visible: true
color: "#f3f3f3"
title: qsTr("主页面")

Row {
id: row
height: 200
spacing: 0
anchors.left:parent.left
anchors.right:parent.right

Rectangle {
id: rectangle
width: 200
height: parent.height
color: "red"
}
Rectangle {
id: rectangle2
width: 200
height: parent.height
color: "green"
}
Rectangle {
id: rectangle3
height: parent.height
width: parent.width-rectangle.width-rectangle2.width
color: "blue"
}

}
}

属性设置

注意

Layout中不要用anchors来设置了,是无效的。

Margin

1
2
3
4
5
6
7
8
9
Image {
Layout.leftMargin: 10
Layout.rightMargin: 10
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.preferredWidth: 20
Layout.preferredHeight: 20
source: "qrc:/imgs/logo01.png"
}

或者

1
2
3
4
5
6
Image {
Layout.margins: 10
Layout.preferredWidth: 20
Layout.preferredHeight: 20
source: "qrc:/imgs/logo01.png"
}

宽高

在RowLayout和ColumnLayout中,子组件的宽高就无效了

宽高由Layout.preferredWidthLayout.preferredHeightLayout.fillWidthLayout.fillHeight决定

1
2
3
4
5
6
7
8
9
Image {
id: m_image
Layout.fillWidth: false
Layout.fillHeight: true
Layout.preferredWidth: 100
Layout.preferredHeight: 100
fillMode:Image.PreserveAspectFit
source: "qrc:/imgs/logo.png"
}

对齐

Layout.alignment 属性允许你指定子项在布局中的对齐方式。

你可以使用 Qt.AlignLeftQt.AlignRightQt.AlignTopQt.AlignBottomQt.AlignHCenterQt.AlignVCenter 等常量来设置对齐方式。

Layout.fillWidth 是一个属性,用于控制子项是否应该扩展以填充其父布局的宽度。

具体来说,当你在使用 GridLayoutRowLayoutColumnLayout 等布局时,可以为子项设置 Layout.fillWidth 属性,以决定子项是否应该水平拉伸以填充可用空间。

  • Layout.fillWidth: true:这会使子项的宽度扩展以匹配父布局的宽度。也就是说,子项会尽可能地变宽,以填满父布局中分配给它的空间。
  • Layout.fillWidth: false:这是默认值,子项将保持其自然宽度,不会扩展以填充父布局的宽度。

Column和ColumnLayout

在 Qt Quick 中,ColumnColumnLayout 都是用来将子项垂直排列的容器类型,但它们在实现方式和使用场景上有一些区别。

对比

Column

  • 基本用法Column 是一个简单的垂直布局容器,它会按照子项的默认大小将它们垂直排列。
  • 子项大小:子项的大小不受 Column 的影响,子项会保持它们的默认大小或设置的显式大小。
  • 隐式大小Column 的隐式高度是所有子项总高度的和,隐式宽度是所有子项中最大宽度的值。
  • 布局调整Column 不会自动调整子项的大小,子项的大小由它们自己控制。

ColumnLayout

  • 基本用法ColumnLayout 是一个更强大的垂直布局容器,它提供了一些布局管理功能,可以自动调整子项的大小。

  • 子项大小:子项可以使用布局属性(如 Layout.preferredHeightLayout.preferredWidth)来指定它们的首选大小。

    ColumnLayout 会根据需要调整子项的大小,以适应容器的大小。

  • 隐式大小ColumnLayout 的隐式高度和宽度取决于子项的布局属性和内容。

  • 布局调整ColumnLayout 可以自动调整子项的大小,以适应容器的大小,提供了更多的布局灵活性。

简单来说

ColumnLayout等Layout组件和css中的flex类似,子组件会自动适应宽高。

Column等定位组件的子组件则完全取决于自己的属性。

在Row和Column中,子组件的宽高是由自己的宽高决定

1
2
3
4
5
6
Image {
width: 64
height: 64
fillMode:Image.PreserveAspectFit
source: "qrc:/imgs/logo.png"
}

在RowLayout和ColumnLayout中,子组件的宽高就无效了

宽高由Layout.preferredWidthLayout.preferredHeightLayout.fillWidthLayout.fillHeight决定

1
2
3
4
5
6
7
8
9
Image {
id: m_image
Layout.fillWidth: false
Layout.fillHeight: true
Layout.preferredWidth: 100
Layout.preferredHeight: 100
fillMode:Image.PreserveAspectFit
source: "qrc:/imgs/logo.png"
}

示例

Column 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import QtQuick 2.15
import QtQuick.Controls 2.15

Column {
spacing: 10
Rectangle {
width: 100
height: 50
color: "red"
}
Rectangle {
width: 100
height: 70
color: "green"
}
Rectangle {
width: 100
height: 30
color: "blue"
}
}

ColumnLayout 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import QtQuick 2.15
import QtQuick.Layouts 1.15

ColumnLayout {
spacing: 10
Rectangle {
Layout.preferredWidth: 100
Layout.preferredHeight: 50
color: "red"
}
Rectangle {
Layout.preferredWidth: 100
Layout.preferredHeight: 70
color: "green"
}
Rectangle {
Layout.preferredWidth: 100
Layout.preferredHeight: 30
color: "blue"
}
}

居中示例

Row

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Row {
Image {
anchors.verticalCenter: parent.verticalCenter
width: 32
height: 32
fillMode:Image.PreserveAspectFit
source: "qrc:/imgs/logo.png"
}

Image {
anchors.verticalCenter: parent.verticalCenter
width: 64
height: 64
fillMode:Image.PreserveAspectFit
source: "qrc:/imgs/logo.png"
}
}

RowLayout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
RowLayout {
height:64
Image {
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 32
Layout.preferredHeight: 32
fillMode:Image.PreserveAspectFit
source: "qrc:/imgs/logo.png"
}

Image {
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 64
Layout.preferredHeight: 64
fillMode:Image.PreserveAspectFit
source: "qrc:/imgs/logo.png"
}
}

总结

  • Column 适用于简单的垂直排列场景,子项大小由它们自己控制。
  • ColumnLayout 适用于需要更复杂布局管理的场景,可以自动调整子项的大小。

上下重叠

Item 中的子组件默认不会自动填充整个 Item 的空间,它们的尺寸和位置由自身的属性决定。

如果希望子组件自动填充Item,可以使用以下方法:

  • 使用 anchors.fill: parent 让子组件填充整个 Item
  • 直接设置子组件的 widthheight 为父 Item 的尺寸。

这两种方法都可以让子组件自动填充父 Item 的区域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Item {
width: parent.width
height: parent.height

Image {
id: bg
anchors.fill: parent
source: "qrc:/imgs/bg01.png"
}

ColumnLayout {
anchors.fill: parent
}
}

可滚动容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ScrollView {
anchors.fill: parent
width: 600
height: 800
contentWidth: 600
clip: true

Rectangle {
width: parent.width
height: 1200
color: "lightgray"
Text {
anchors.centerIn: parent
text: "This is a large content area."
font.pixelSize: 30
}
}
}

Item和Rectangle的区别

  • Item:它是 QML 中所有可视元素的基类,是最基础的可视元素,具备位置、大小、变换等基础属性,但没有默认的外观表现。

    也就是说,单纯创建一个Item实例时,在界面上是看不到它的。

  • Rectangle:继承自Item,这意味着它拥有Item的所有属性,

    同时还有自身特有的属性,比如color(填充颜色)、border(边框)、radius(圆角)、clip(内部剪裁)等,默认会以矩形的形状显示在界面上。

比如

1
2
3
4
5
6
7
8
9
Rectangle {
x: 100
y: 100
width: 100
height: 50
color: "lightblue"
border.color: "black"
border.width: 2
}