文章详情 学习记录

Qt布局管理

发布时间:2026-07-02 12:26 浏览次数:35 最后更新:2026-07-02 14:54

Qt布局管理详解

正文内容

Qt Widgets布局管理

所有的QWidget的子类的实例都可以使用布局管理器管理位于它们之中的子部件,QWidget::setLayout()函数可以在一个部件上应用布局管理器。一旦一个部件上设置了布局管理器,那么它会完成以下几种任务:

  • 定位子部件
  • 感知窗口默认大小
  • 感知窗口最小大小
  • 窗口大小变化时进行处理
  • 当内容改变时自动更新:
    • 字体大小、文本或子部件的其他内容随之改变
    • 隐藏或显示子部件
    • 移除一个子部件

布局管理器简介

QLayout类是布局管理器的基类,它是一个抽象基类,继承自QObjectQLayoutItem类,其中QLayoutItem类提供了一个供QLayout操作的抽象项目。

QLayoutQLayoutItem都是在设计自己的布局管理器时才使用的,一般只需要使用QLayout的几个子类即可:

  • QBoxLayout(基本布局管理器)
  • QGridLayout(栅格布局管理器)
  • QFormLayout(窗体布局管理器)
  • QStackedLayout(栈布局管理器)


基本布局管理器

基本布局管理器QBoxLayout类可以使子部件在水平方向或者垂直方向排成一列,将所有的空间分成一行盒子,然后将每个部件放入对应盒子中。属于抽象类,不能直接实例化,它有两个子类:

  • QHBoxLayout:水平布局管理器
  • QVBoxLayout:垂直布局管理器

例如:可以使用addWidget()函数向布局管理器的末尾添加部件,还有一个insertWidget()函数可以实现向指定位置添加部件,它比前者更灵活。

QHBoxLayout *layout = new QHBoxLayout;       
layout->addWidget(ui->fontComboBox);         
layout->addWidget(ui->textEdit);
layout->setSpacing(50);                       
layout->setContentsMargins(0, 0, 50, 100);  setLayout(layout);

常用属性:

属性 说明
layoutName 现在所使用的布局管理器的名称
layoutLeftMargin 设置布局管理器到界面左边界的距离
layoutTopMargin 设置布局管理器到界面上边界的距离
layoutRightMargin 设置布局管理器到界面右边界的距离
layoutBottomMargin 设置布局管理器到界面下边界的距离
layoutSpacing 布局管理器中各个子部件间的距离
layoutStretch 伸缩因子,设置部件的大小比例
layoutSizeConstraint 设置大小约束条件,例如QLayout::SetFixedSize设置窗口无法改变大小


栅格布局管理器

栅格布局管理器QGridLayout类使部件在网格中进行布局,它将所有的空间分隔成一些行和列,行和列的交叉处就形成了单元格,然后将部件放入一个确定的单元格中。

这里主要是设置部件在栅格布局管理器中的位置,将fontComboBox部件设置为占据1行2列,而pushButton部件占据1行1列,这主要是为了将fontComboBox部件和pushButton部件的长度设置为2:1。这样一来,textEdit部件要想占满剩下的空间,就要使它的跨度为3列。

QGridLayout *layout = new QGridLayout;
// 添加部件,从第0行0列开始,占据1行2列
layout->addWidget(ui->fontComboBox, 0, 0, 1, 2);
// 添加部件,从第0行2列开始,占据1行1列
layout->addWidget(ui->pushButton, 0, 2, 1, 1);
// 添加部件,从第1行0列开始,占据1行3列
layout->addWidget(ui->textEdit, 1, 0, 1, 3);
setLayout(layout);  

窗体布局管理器

窗体布局管理器QFormLayout类用来管理表单的输入部件以及与它们相关的标签。窗体布局管理器将它的子部件分为两列,左边是一些标签,右边是一些输入部件,比如行编辑器或者数字选择框等。

  1. 在设计模式从部件列表窗口中找到Form Layout,将其拖入到界面上,然后双击或者在它上面右击并在弹出的级联菜单中选择“添加窗体布局行”。
  2. 在弹出的“添加表单布局行”对话框中填入标签文字“姓名(&N):”,这样下面便自动填写了“标签名称”、“字段类型”和“字段名称”等,并且设置了伙伴关系。
  3. 这里使用了QLineEdit行编辑器,当然也可以选择其他部件。填写的标签文字中的“(&N)”必须是英语半角的括号,表明它的快捷键是Alt+N。
  4. 设置伙伴关系表示当按下Alt+N时,光标会自动跳转到标签后面对应的行编辑器中。
  5. 单击“确定”键,则会在布局管理器中添加一个标签和一个行编辑器。

综合使用布局管理器

前面讲到了3种布局管理器,真正使用时一般是将它们综合起来应用。

例如:

  • 按下Ctrl键的同时选中界面上的字体选择框fontComboBox和按钮pushButton,然后按下Ctrl+H快捷键将它们放入一个水平布局管理器中(其实也可以从部件列表窗口中拖入一个Horizontal Layout,然后再将这两个部件放进去,效果是一样的)。
  • 然后再从部件列表窗口中拖入一个Vertical Spacer垂直分隔符,用来在部件间产生间隔,将它放在窗体布局管理器与水平布局管理器之间。
  • 最后单击主界面并按下Ctrl+L快捷键,让整个界面处于一个垂直布局管理器中。这时可以在右上角的对象查看器中选择MyWidget对象,然后在属性编辑器的最后将layoutStretch设置为“4,1,1,10”。

image-20260702142913835

设置部件大小

这里再来解两个概念:大小提示(sizeHint)和最小大小提示(minimumSizeHint)。凡是继承自QWidget的类都有这两个属性。

  • sizeHint属性保存了部件的建议大小,对于不同的部件,默认拥有不同的sizeHint。
  • minimumSizeHint保存了一个建议的最小大小提示。
  • 可以使用sizeHint()函数来获取sizeHint的值,使用minimumSizeHint()函数获取minimumSizeHint的值。

Note

如果使用setMinimumSize()函数设置了部件的最小大小,那么最小大小提示将会被忽略。

下面再来看一下大小策略(sizePolicy)属性,它也是QWidget类的属性。这个属性保存了部件的默认布局行为,在水平和垂直两个方向分别起作用,控制着部件在布局管理器中的大小变化行为。

常量 描述
QSizePolicy::Fixed 只能使用 sizeHint () 提供的值,无法伸缩
QSizePolicy::Minimum sizeHint () 提供的大小是最小的,部件可以被拉伸
QSizePolicy::Maximum sizeHint () 提供的是最大大小,部件可以被压缩
QSizePolicy::Preferred sizeHint () 提供的大小是最佳大小,部件可以被压缩或拉伸
QSizePolicy::Expanding sizeHint () 提供的是合适的大小,部件可以被压缩,不过它更倾向于被拉伸来获得更多的空间
QSizePolicy::MinimumExpanding sizeHint () 提供的大小是最小的,部件倾向于被拉伸来获取更多的空间
QSizePolicy::Ignored sizeHint () 的值被忽略,部件将尽可能的被拉伸来获取更多的空间


可扩展窗口

一个窗口可能很多选项是扩充的,只有在必要的时候才显示出来,这时就可以使用一个按钮,用来隐藏或者显示多余的内容,就是所谓的可扩展窗口。要实现可扩展窗口,就要得力于布局管理器的特性,那就是当子部件隐藏时,布局管理器自动缩小,当子部件重新显示时,布局管理器再次放大。

void MyWidget::on_pushButton_toggled(bool checked)
{
    ui->textEdit->setVisible(checked);
    if(checked) {
        setFixedHeight(270);
        ui->pushButton->setText(tr("隐藏可扩展窗口"));
    } else {
        setFixedHeight(170);
        ui->pushButton->setText(tr("显示可扩展窗口"));
    }
} 

image-20260702143510651

image-20260702143515249



Qt Quick布局管理

Qt Quick中提供了多种布局方式,比如可以通过属性绑定来设置位置或者大小;还有基于锚 anchors的布局;另外,还提供了定位器,可以用来为多个项目进行常规的布局;如果需要同时管理项目的位置和大小,可以使用布局管理器

定位器

定位器是一个容器,可以管理其中子项目的布局,包括Column、Row、Grid和Flow。如果它们的子项目不可见(visible为false)、宽度或者高度为0,那么该子项目不会显示也不会被布局。

Column和Row

Column项目可以将其子项目垂直排成一列。下面的例子使用了Column定位了几个形状不同的Rectangle。Column的spacing属性用来为这几个Rectangle添加间距,padding属性用来设置Column子项目和边界之间的距离,也可以通过topPadding、bottomPadding、leftPadding、rightPadding分别进行设置。

Column {
    spacing: 2; padding: 5

    Rectangle { color: "white"; border.width: 1; width: 50; height: 50 }
    Rectangle { color: "green"; width: 20; height: 50 }
    Rectangle { color: "lightgrey"; width: 50; height: 20 }
}  

image-20260702143749909



Grid

Grid项目可以将其子项目排列在一个网格中。Grid会计算一个足够大的矩形网格来容纳所有的子项目。向网格中添加项目,会按照从左向右、从上向下的顺序进行排列。每一个项目都会被放置在网格左上角(0, 0)的位置。一个Grid默认有四列,可以有无限多的行容纳所有的子项目。行数和列数也可以通过rows和columns属性指定。另外,Grid也可以通过spacing属性设置子项目之间的间距,此时,水平方向和垂直方向会使用相同的间距,如果需要分别设置,可以使用rowSpacing和columnSpacing属性。

Grid {
    columns: 3; spacing: 2; padding: 5
    Rectangle { color: "white"; border.width: 1; width: 50; height: 50 }
    Rectangle { color: "green"; width: 20; height: 50 }
    Rectangle { color: "lightgrey"; width: 50; height: 20 }
    Rectangle { color: "cyan"; width: 50; height: 50 }
    Rectangle { color: "magenta"; width: 10; height: 10 }
}     

image-20260702143930753



Flow

Flow项目可以从前向后,像流一样布局其子项目,如同单词放置在页面上一样,通过换行,使这些子项目排列成多行或列。Flow排列项目的规则与Grid相似,它们的主要区别是,Flow的子项目会在超出边界后自动换行,每行的子项目数不一定相同。Flow有一个flow属性,包含两个值:Flow.LeftToRight(默认)和Flow.TopToBottom。前者是按照从左向右的顺序排列子项目,直到超出Flow的宽度,然后换到下一行;后者则按照从上到下的顺序排列其子项目,直到超出Flow的高度,然后换到下一列。

Rectangle {
    color: "lightblue"; width: 300; height: 200
    Flow {
        anchors.fill: parent; 
        anchors.margins: 4; spacing: 10

        Text { text: "Text"; font.pixelSize: 40 }
        Text { text: "items"; font.pixelSize: 40 }
        Text { text: "flowing"; font.pixelSize: 40 }
        Text { text: "inside"; font.pixelSize: 40 }
        Text { text: "a"; font.pixelSize: 40 }
        Text { text: "Flow"; font.pixelSize: 40 }
        Text { text: "item"; font.pixelSize: 40 }
    }
}    

image-20260702144009702



使用过渡

定位器添加或删除一个子项目时,可以使用一个过渡(Transition),使这些操作具有动画效果。四个定位器都有add、move和populate属性,它们需要分配一个Transition对象。

  • add过渡应用在定位器创建完毕后,向定位器中添加一个子项目,或者将子项目通过更换父对象的方式变为定位器的孩子时
  • move过渡应用在删除定位器中的一个子项目,或者通过更换父对象方式从定位器中移除对象时
  • populate过渡应用在定位器第一次创建时,只会运行一次。此外,将项目的透明度更改为0时,会使用move过渡隐藏项目
  • 当项目的透明度为非0时,会使用add过渡显示项目。定位器过渡只会影响项目的位置(x, y)
Column {
    spacing: 2
    Rectangle { color: "red"; width: 50; height: 50 }
    Rectangle { id: greenRect; color: "green"; width: 20; height: 50 }
    Rectangle { color: "blue"; width: 50; height: 20 }

    move: Transition {
        NumberAnimation { properties: "x,y"; duration: 1000 }
	}
    focus: true
    Keys.onSpacePressed: greenRect.visible = !greenRect.visible
}

Positioner

在Column、Row、Grid和Flow中会附加一个Positioner类型的对象作为顶层子项目,它可以为定位器中的子项目提供索引等信息。例如,Grid通过Repeater创建了16个子矩形,每一个子矩形都使用Positioner.index显示了它在Grid中的索引,而第一个矩形使用了不同颜色进行绘制。

Grid {
    padding: 5

    Repeater {
        model: 16
        Rectangle {
            id: rect; width: 40; height: 40; border.width: 1
            color: Positioner.isFirstItem ? "yellow" : "lightsteelblue"

            Text { 
                text: rect.Positioner.index; 
                anchors.centerIn: parent 
            }
        }
    }
}

image-20260702144433989

Repeater

Repeater类型用来创建大量相似的项目。一个Repeater包含一个模型model属性和一个委托delegate属性。委托用来将模型中的每一个条目进行可视化显示。一个Repeater通常会包含在一个定位器中,用于直观地对Repeater产生的众多委托项目进行布局。

Rectangle {
    width: 400; height: 240; color: "black"
    Grid {
        x: 5; y: 5; rows: 5; columns: 5; spacing: 10
        Repeater { 
            model: 12
            Rectangle { 
                width: 70; height: 70; color: "lightgreen"
                Text { 
                    text: index; font.pointSize: 30
                    anchors.centerIn: parent 
                } 
            }
        }
    }
}

image-20260702144535085



基于锚(anchors)的布局

除了前面讲解的定位器外,Qt Quick还提供了一种基于锚的概念来进行项目布局的方法。每一个项目都可以认为有一组无形的“锚线”:left、horizontalCenter、right、top、verticalCenter、baseline和bottom,如图所示。图中没有显示baseline,它是一条假想的线,文本坐落在这条线上,对于没有文本的项目,它与top相同。

image-20260702144626280

7条锚线分别对应了Item项目中的anchors属性组的相关属性。因为Qt Quick中所有可视项目都继承自Item,所以所有可视项目都可以使用锚进行布局。Qt Quick的锚定系统允许不同项目的锚线之间建立关系

示例:

Item {
    width: 250; height: 300

    Rectangle{
        id: rect1; x:10; y:20
        width: 100; height: 100; color: "lightgrey"
        Text { text: "rect1"; anchors.centerIn: parent }
    }
    Rectangle{
        id: rect2
        width: 100; height: 100; color: "black"
        anchors.left: rect1.right
        Text { text: "rect2"; color: "white"; anchors.centerIn: parent }
    }
}

image-20260702144716005

锚边距和偏移

锚定系统也允许为一个项目的锚指定边距(margin)和偏移(offset)。边距指定了项目锚到外边界的空间量,而偏移则允许使用中心锚线进行定位。一个项目可以通过leftMargin、rightMargin、topMargin和bottomMargin独立指定锚边距,如图所示。也可以使用anchor.margins同时为4个边指定相同的边距。锚偏移可以使用horizontalCenterOffset、verticalCenterOffset和baselineOffset来指定。

Rectangle { id: rect1; ... }
Rectangle {
id: rect2;
anchors.left: rect1.right; anchors.leftMargin: 5; 
anchors.top: rect1.top
...
}   

image-20260702144748276

布局管理器

Qt Quick布局管理器是一组用于在用户界面中排列项目的类型。与前面讲到的定位器不同,布局管理器不仅进行布局,而且会改变项目的大小,所以更适用于需要改变用户界面大小的应用。因为布局管理器也是继承自Item,所以它们可以嵌套。Qt Quick布局管理器与Qt Widgets应用中的布局管理器很相似。

Note

Qt Quick Layouts模块在Qt 5.1中引入,使用时需要进行导入:import QtQuick.Layouts

Qt Quick布局管理器主要包括:

  • RowLayout
  • ColumnLayout
  • GridLayout
  • StackLayout

Qt Quick Layouts拥有下面几个主要特色:

  • 项目的对齐方式可以使用Layout.alignment属性指定,主要有:QtAlignLeft、QtAlignHCenter、QtAlignRight、QtAlignTop、QtAlignVCenter、QtAlignBottom、Qt::AlignBaseline。
  • 可变大小的项目可以使用Layout.fillWidth和Layout.fillHeight属性指定,当将其值设置为true时会根据约束条件变宽或变高。
  • 大小约束可以通过Layout.minimumWidth、Layout.preferredWidth和Layout.maximumWidth属性(另外还有相对height的类似属性)指定。
  • 间距可以通过spacing、rowSpacing和columnSpacing属性指定。

除了上面所述的这些特色,在GridLayout中还添加了如下特色:

  • 网格中的坐标可以通过Layout.row和Layout.column指定。
  • 自动网格坐标同时使用了flow、rows、column属性。
  • 行或列的跨度可以通过Layout.rowSpan和Layout.columnSpan属性来指定。

大小约束

要想使一个项目可以通过布局管理器调整大小,需要指定其最小宽高(minimumWidth和minimumHeight)、最佳宽高(preferredWidth和preferredHeight)和最大宽高(maximumWidth和maximumHeight),并将对应的Layout.fillWidth或Layout.fillHeight设置为true。

RowLayout {
    id: layout; anchors.fill: parent; spacing: 6
    Rectangle {
        color: 'lightgrey'
        Layout.fillWidth: true; Layout.minimumWidth: 50
        Layout.preferredWidth: 100; Layout.maximumWidth: 300
        Layout.minimumHeight: 150
        Text {
            anchors.centerIn: parent
            text: parent.width + 'x' + parent.height
        }
    }

    Rectangle {
        color: 'black'
        Layout.fillWidth: true; Layout.minimumWidth: 100
        Layout.preferredWidth: 200; Layout.preferredHeight: 100
        Text {
            anchors.centerIn: parent; color: "white"
            text: parent.width + 'x' + parent.height
        }
    }
}

image-20260702145157256

有效的最佳(preferred)属性的值,可能来自几个候选属性。要决定有效的最佳属性,会对这些候选属性以下面的顺序进行查询,使用第一个有效的值。

  • Layout.preferredWidth或Layout.preferredHeight
  • implicitWidth或implicitHeight
  • width或height

一个项目可以仅指定Layout.preferredWidth而不指定Layout.preferredHeight,此时,有效的最佳高度会从implicitHeight或最终的height中选取。

为了将布局管理器与窗口进行关联,可以为布局管理器添加锚anchors.fill,确保布局管理器能够跟随窗口一起改变大小。

布局管理器的大小约束可以用来确保窗口大小不会超过约束条件,还可以将布局管理器的约束设置到窗口项目的minimumWidth、minimumHeight、maxmumWidth和maximumHeight等属性。



StackLayout

StackLayout栈布局管理器可以管理多个项目,但只能显示一个项目。可以通过currentIndex属性来设置当前显示的项目,索引号对应布局管理器中子项目的顺序,从0开始。另外,StackLayout还包含index和isCurrentItem等附加属性。

Window {
    width: 640; height: 480; visible: true
    StackLayout {
        id: layout; anchors.fill: parent; currentIndex: 1

        Rectangle {
            color: 'teal'; implicitWidth: 200; implicitHeight: 200
        }
        Rectangle {
            color: 'plum'; implicitWidth: 300; implicitHeight: 200
        }
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            if (layout.currentIndex === 1)
                layout.currentIndex = 0;
            else
                layout.currentIndex = 1
        }
    }
}

image-20260702145333285

正文内容已启用复制保护,代码块与行内代码仍支持复制。

评论区

欢迎参与讨论,评论提交与展示状态会在下方同步更新。

发表评论

提交后将进入人工审核,审核通过后才会展示。

邮箱仅用于必要的联系与基础风控,不会在页面中公开展示。

请文明发言,避免发布广告、链接或敏感内容;短时间内频繁提交会被限制。

隐私提示:提交评论即表示你同意站点为评论展示、审核、防刷与安全风控目的处理你填写的昵称、邮箱和评论内容。

其中邮箱不会公开展示,也不会用于与评论无关的公开用途。

读者留言

还没有评论,来发表第一条评论吧。

共 0 条评论 已展示 0 / 0 条评论
当前还没有评论,来发表第一条评论吧。若评论需要审核,通过后会展示在这里。