QML 基础容器三件套:Pane、Frame 与 GroupBox

0 阅读5分钟

在 Qt Quick Controls 里,容器组件负责把界面元素组织成有视觉边界的块。容器的主要作用是让界面层级更加清晰,这篇先介绍较为基础的三个容器:Pane、Frame、GroupBox。它们看起来都是“一个框”,但默认样式和语义各不相同。

Pane 是基础容器,只提供默认背景和内边距,视觉效果最弱;Frame 继承自 Pane,默认带边框,适合需要明确边界的分组;GroupBox 是带标题的分组框,适合表单、设置项这类需要标题说明的场景。

这三个组件都不强制内部布局,需要自己套 ColumnLayoutRowLayoutGridLayout。了解它们的差异后,可以少写很多自定义 Rectangle

Pane 容器

Pane 是 Qt Quick Controls 里最轻量的容器。它本身不带边框、不带标题,只提供背景色和内边距。默认背景会跟随应用主题变化,所以它在浅色和深色主题下都能自动适配。

它的样式比较朴素,适合作为内容衬底:比如设置页面里的单块区域、卡片式布局的底层、或者任何需要统一内边距但不需要强调边界的场景。如果你只是想给一段内容“垫个底”,Pane 是最合适的选择。

1.png

演示代码

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        ColumnLayout {
            Layout.fillWidth: true
            Layout.leftMargin: 20
            Layout.rightMargin: 20
            spacing: 15

            Pane {
                Layout.fillWidth: true
                Layout.preferredHeight: 120
                padding: 15

                Label {
                    anchors.fill: parent
                    text: "- 默认背景色与应用主题匹配\n- 不提供布局,需自行创建\n- 支持自定义背景\n- 适合作为内容容器"
                    font.pointSize: 10
                    textFormat: Text.MarkdownText
                    wrapMode: Text.WordWrap
                }
            }
        }

        Item { Layout.fillHeight: true }
    }
}

关键逻辑解析

代码里的 Pane 只做了两件事:设置尺寸、设置 padding。它没有定义内部布局,所以内部套了一个 ColumnLayout 来放 Label。

Pane 的几个特点:

  • 不提供布局:Pane 本身不会帮你排布子元素,必须自己套 Layout
  • 默认背景跟随主题:背景色由当前控件风格决定,换主题时会自动变
  • 内边距可控:通过 paddingleftPaddingrightPadding 等属性控制
  • 可完全自定义背景:重写 background 属性就能换成圆角、阴影、渐变等任意样式

什么时候用 Pane?当你只是想把一段内容包起来、给个内边距和背景,但又不想让它看起来太“重”的时候。

Frame 容器

Frame 和 Pane 几乎一样,但默认多了边框。它继承自 Pane,所以 Pane 有的属性它都有。如果你需要给内容块加一条清晰的边界,Frame 是最省事的方案:不需要手动写 Rectangle 画边框,也不需要调阴影。

Frame 的边框样式同样由当前控件风格决定。在 Basic 风格下,它是一条简洁的细线;在 Fusion 或 Universal 风格下,会有不同的立体或扁平效果。如果你想快速得到一个“有边界的内容块”,直接用 Frame 比自定义 Rectangle 更快。

2.png

演示代码

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        ColumnLayout {
            Layout.fillWidth: true
            Layout.leftMargin: 20
            Layout.rightMargin: 20
            spacing: 15

            Frame {
                Layout.fillWidth: true
                Layout.preferredHeight: 120
                padding: 15

                Label {
                    anchors.fill: parent
                    text: "- 自带边框样式\n- 适合分组显示内容\n- 支持自定义背景\n- 适合作为内容容器"
                    font.pointSize: 10
                    textFormat: Text.MarkdownText
                    wrapMode: Text.WordWrap
                }
            }
        }

        Item { Layout.fillHeight: true }
    }
}

关键逻辑解析

Frame 与 Pane 的核心差异只有一点:默认视觉层级。

特性PaneFrame
默认背景
默认边框
继承关系Control继承 Pane
适用场景衬底、卡片分组、带边界的内容块

因为 Frame 继承自 Pane,你也可以重写 background 把边框改成虚线、圆角或渐变。但如果只是想快速分组,默认样式已经够用。

GroupBox 容器

GroupBox 是这三个里相对复杂的一个。它不仅有边框,还有标题栏。在表单页面里,它是最常见的分组方式:把“账号信息”、“网络设置”、“通知偏好”各自放进一个 GroupBox,用户一眼就能看懂字段之间的逻辑关系。

GroupBox 的标题通过 title 属性设置,标题栏会显示在内容上方。内容区域的内边距由 padding 系列属性控制。和 Frame 一样,它也继承自 Pane,所以自定义背景的方式相同。

3.png

演示代码

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        ColumnLayout {
            Layout.fillWidth: true
            Layout.leftMargin: 20
            Layout.rightMargin: 20
            spacing: 15

            GroupBox {
                title: "GroupBox容器"
                Layout.fillWidth: true
                Layout.preferredHeight: 120

                Label {
                    anchors.fill: parent
                    text: "- 带有标题的分组框\n- 适合组织相关控件"
                    font.pointSize: 10
                    textFormat: Text.MarkdownText
                    wrapMode: Text.WordWrap
                }
            }
        }

        Item { Layout.fillHeight: true }
    }
}

关键逻辑解析

  • title 属性同时控制标题文字和标题栏的显示。如果为空字符串,标题栏会隐藏
  • 内容区域在标题下方,默认有合理的内边距
  • 适合包裹一组语义相关的控件,比如账号设置、网络配置、外观选项

一个常见误区是:GroupBox 本身不限制内部只能放一种控件。你可以放 ColumnLayoutGridLayoutRepeater,甚至是另一个 GroupBox。只要逻辑上属于同一组,就可以放进去。

对比表格

容器默认边框标题视觉权重最适合的场景
Pane内容卡片、衬底、需要主题适配的背景
Frame分组显示、带边框的内容块
GroupBox表单分组、设置项集合、需要标题说明的区域

选型建议:先试试 Pane,如果边界不够清晰就换 Frame,如果还需要标题说明就换 GroupBox。

运行验证

  1. Qt Creator 打开 qml_container/CMakeLists.txt
  2. Ctrl+R 运行
  3. 左侧导航切换 “Pane”、“Frame”、“GroupBox” 查看效果
  4. 尝试修改 padding 或重写 background,观察容器外观变化

扩展复用方向

  • 把 Pane 的背景改成圆角矩形,做成可复用的 Card 组件
  • 用 Frame 包裹一组 RadioButtonCheckBox,形成单选/多选分组
  • GroupBox 里加 GridLayout 做两列表单布局
  • 给 Frame/GroupBox 换背景色,匹配深色主题或品牌色
  • 把常用的 GroupBox 样式抽成一个自定义组件,避免每个页面都重写 background

已验证环境