QML学习笔记(三十)QML的布局器(Layouts)

前言

上一节中,我们介绍了QML中的定位器(Row,Column,Grid),它们可以用来定位多个组件,让组件按照特定规则进行排列和定位,然而这种方式有一个问题,这些组件必须要被事先设定了尺寸大小,才可以被排列和定位。它们的尺寸通常会被写死,难以实现自适应尺寸的效果。

本节中介绍的Layouts则能够实现这种自适应尺寸的布局,它和QWidget中的QLayout类也有功能上的类似。让我们开始学习吧。

一、了解Layouts

Layouts布局器是一个总称,它通常被分为了RowLayout、ColunmLayout、GridLayout。

我们在帮助文档搜索GridLayout:

翻译一下描述:

如果调整了GridLayout的大小,布局中的所有项目都将被重新排列。它类似于基于小部件的QGridLayout。GridLayout元素的所有可见子元素都将属于布局。如果你想要一个只有一行或一列的布局,你可以使用RowLayout或ColumnLayout。这些提供了更方便的API,并提高了可读性。

默认情况下,项目将根据流属性进行排列。流属性的默认值是GridLayout。从左到右。

如果指定了columns属性,则在自动定位返回到下一行的开头之前,它将被视为布局可以包含的最大列数限制。columns属性仅在流为GridLayout时使用。从左到右。

似乎说的有些云里雾里,我再总结一下:
GridLayout 是 Qt Quick Layouts 模块里的"二维表格"布局器,用来把子项按行 & 列网格摆放,自动计算大小、支持拉伸、对齐、跨行/跨列,几行代码就能做出响应式窗体。

如果你希望构建响应式用户界面------在小屏幕上缩小、在大屏幕上扩展------这将非常有用。比如,如果你在移动设备上运行程序屏幕会缩小,所有内容也会跟着自动缩小,仍能良好显示。而如果是在桌面端运行,界面会扩展并充分利用可用空间。

说的有点啰嗦了,我们直接代码学习。

二、GridLayout代码测试

直接把初始代码放上来:

cpp 复制代码
import QtQuick 2.14
import QtQuick.Window 2.14

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("QmlLayouts")

    Grid{
        id: mGridLayoutId
        anchors.fill: parent
        columns: 3

        Rectangle{
            id: topLeftRectId
            width: 100
            height: width
            color: "magenta"
            Text {
                anchors.centerIn: parent
                text: "1"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: topCenterRectId
            width: 100
            height: width
            color: "yellowgreen"
            Text {
                anchors.centerIn: parent
                text: "2"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: topRightRectId
            width: 100
            height: width
            color: "dodgerblue"
            Text {
                anchors.centerIn: parent
                text: "3"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: centerLeftRectId
            width: 100
            height: width
            color: "red"
            Text {
                anchors.centerIn: parent
                text: "4"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: centerCenterRectId
            width: 100
            height: width
            color: "green"
            Text {
                anchors.centerIn: parent
                text: "5"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: centerRightRectId
            width: 100
            height: width
            color: "blue"
            Text {
                anchors.centerIn: parent
                text: "6"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: bottomLeftRectId
            width: 100
            height: width
            color: "royalblue"
            Text {
                anchors.centerIn: parent
                text: "7"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: bottomCenterRectId
            width: 100
            height: width
            color: "yellow"
            Text {
                anchors.centerIn: parent
                text: "8"
                font.pointSize: 20
            }
        }

        Rectangle{
            id: bottomRightRectId
            width: 100
            height: width
            color: "pink"
            Text {
                anchors.centerIn: parent
                text: "9"
                font.pointSize: 20
            }
        }
    }
}

这里使用了定位器中的Grid来实现九宫格,可以看到我们即便设置了anchors.fill: parent,九宫格也并未如我们所想充满整个屏幕。

第一,这九个矩形全部都被写死了尺寸;第二,组件之间是没有间距的;第三,Grid只会从左上角开始显示组件------所以它们表现出了密集堆积在左上角的样式。

如果我们希望它们能够自适应窗口大小,甚至我们手动拖拽窗口的时候,组件也可以跟着变化大小,我们可以使用GridLayout:

首先,我们需要添加Layout模块,不然你可找不到GridLayout。

cpp 复制代码
import QtQuick.Layouts 1.12

然后,我们直接将Grid修改为GridLayout,编译运行:

可以看到,整个透明的GridLayout明显是平铺了窗口。我们拖拽窗口改变尺寸看看。

最小缩放到这种程度:

可以得出结论:如果没有进行特殊设置,Layouts的间距默认不是0,源代码里写的是5px。

我们再稍微放大一下窗口:

我添加了几条辅助线,我想要得出的结论是:如果组件被限制了尺寸,而布局器给它分配的空间更大时,该组件会默认按照靠左、垂直居中的方式进行显示。所以如果我们期望组件水平居中、垂直居中,我们需要留意额外的设置实现。

比如,我们往第一个矩形内添加这行代码:

cpp 复制代码
Layout.alignment: Qt.AlignHCenter

一号矩形此时已经在分配给它的空间里,实现了水平居中,尽管这肉眼上看不太直观。

现在,我们尝试注释掉全部矩形的宽高设置,看会发生怎样的效果?

本以为会九宫格平铺整个窗口,结果缩成了左上角那个小黑点了。

那是因为我们还没给组件们设置尺寸上的伸缩策略。

我们在第一个矩形上添加代码:

cpp 复制代码
            Layout.fillWidth: true
            Layout.fillHeight: true

这两句说明了矩形的自适应填充宽高的使能被开启了。此时观察现象:

一号矩形抢占了全部空间,当然,其他矩形还在左上角那个小点上。

我们给全部矩形设置这两句话。

终于,我们想要的效果出来了!

此时拖拽窗口大小也没有问题。

最后,我们继续关注组件的尺寸问题。现在这种0~Max的尺寸虽然看上去很完美,但在某些场合下依旧有局限性。我们可以在保留一定自伸缩性的情况下,再设置组件的最大尺寸和最小尺寸。

cpp 复制代码
            Layout.maximumWidth: 150
            Layout.maximumHeight: 150

我们还可以让矩形2占据两列的空间,当然前提是先把矩形3的代码注释掉。

然后,我们对矩形2设置:

cpp 复制代码
Layout.columnSpan: 2

此时矩形2将在列数上有2个组件的跨度值,效果如下:

同理,我们也可以让矩形4实现行数上的跨度,让4和7合在一起,前提是先把7的代码注释掉。

最后,再介绍一个水平翻转的属性。我们给GridLayout设置:

cpp 复制代码
layoutDirection: Qt.RightToLeft

可以看到所有组件的排布全部都水平翻转了。

三、总结

不得不说,上述的一系列测试多少有些繁琐了,但我的描述中基本已经包含了Layouts最为核心的常用功能,而这些功能在QWidget中基本上都有对应的实现,属于是Qt框架中用于实现UI布局的非常重要的内容。我甚至认为,只有掌握了这种布局方式,你才能在实际工作中得以很好地实现和还原UI原型图。今后还会继续多加练习和巩固的。

最后,我担心本节的布局器和上一节的定位器会有混淆,所以这里让kimi做了个小表格,希望对理解有帮助:

维度 定位器 (Row/Column/Grid) 布局器 (RowLayout/ColumnLayout/GridLayout)
模块 Qt Quick Basic Qt Quick Layouts
子项尺寸 固定写死(width/height) 自动计算(约束 + stretch)
对齐 无,只能自己算 x/y Layout.alignment: Qt.AlignCenter
拉伸 Layout.fillWidth: true
间距 spacing: 10 spacing: 10
换行/换列 Grid 支持 GridLayout 支持 + 自动 flowed
性能 超高(只 setPos) 稍低(要解线性方程)
使用场景 子项大小固定、列表、工具栏 需要响应式、拉伸、对齐的窗体
相关推荐
feiyangqingyun3 小时前
Qt编写上下界面切换效果/前进到下一个界面/后退到上一个页面/零件工艺及管理设计系统
qt·零件工艺
筱砚.3 小时前
【C++——面向对象编程综合案例】
c++
ajassi20003 小时前
开源 C++ QT QML 开发(十五)通讯--http下载
c++·qt·开源
不会kao代码的小王3 小时前
突破机房围墙:openEuler设备的公网管理实战指南
开发语言·数据库·笔记
He BianGu4 小时前
【笔记】WPF中如何的动态设置DataGridTextColumn是否显示
笔记·wpf
我梦之64 小时前
libevent输出缓存区的数据
服务器·网络·c++·缓存
磨十三4 小时前
C++ 单例模式(Singleton)详解
c++·单例模式
Nuyoah11klay5 小时前
华清远见25072班C++学习day7
c++
bkspiderx5 小时前
C++设计模式之行为型模式:迭代器模式(Iterator)
c++·设计模式·迭代器模式