一个 SplitView 只能把区域分成两栏,遇到三分栏这种结构,就得在 SplitView 上再套一个 SplitView。
另外,用户把分隔条布局弄乱了,想临时一键恢复成上次保存好的样子。
本文用2个例子解决上述问题。
嵌套布局
外层水平分两栏,右侧再垂直分上下两栏,三层面板自由拖拽。如图所示:

演示代码
qml
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
FadeInAnimation {
id: root
property color mainColor: Theme.listColors[Theme.demo3]
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// ... 省略标题组件 TitleSeparator ...
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 45
color: Theme.demoStyle.frameBg
radius: 6
border.color: Theme.demoStyle.frameBorder
border.width: 1
RowLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 10
Text {
text: "布局结构:"
font.pointSize: 10
color: Theme.demoStyle.frameText
}
Text {
text: "左侧面板 + 右侧(上下面板)"
font.pointSize: 10
color: root.mainColor
font.bold: true
}
Item { Layout.fillWidth: true }
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: Theme.demoStyle.frameBg
border.color: Theme.demoStyle.frameBorder
border.width: 1
radius: 6
SplitView {
id: horizontalSplit
anchors.fill: parent
anchors.margins: 10
orientation: Qt.Horizontal
handle: Rectangle {
implicitWidth: 6
implicitHeight: 6
color: root.mainColor
opacity: SplitHandle.pressed ? 1.0 : 0.7
}
// 面板1
CustomRect {
SplitView.minimumWidth: 60
SplitView.minimumHeight: 60
rectColor: Qt.color(root.mainColor).darker(1.0)
rectNum: "1"
}
SplitView {
id: verticalSplit
SplitView.fillWidth: true
SplitView.fillHeight: true
SplitView.minimumWidth: 80
SplitView.minimumHeight: 80
orientation: Qt.Vertical
handle: Rectangle {
implicitWidth: 6
implicitHeight: 6
color: root.mainColor
opacity: SplitHandle.pressed ? 1.0 : 0.7
}
// 面板2
CustomRect {
SplitView.minimumWidth: 80
SplitView.minimumHeight: 80
rectColor: Qt.color(root.mainColor).darker(1.2)
rectNum: "2"
}
// 面板3
CustomRect {
SplitView.minimumWidth: 80
SplitView.minimumHeight: 80
rectColor: Qt.color(root.mainColor).darker(1.4)
rectNum: "3"
}
}
}
}
}
}
嵌套的写法就是把一个 SplitView 当成普通子项,写进另一个 SplitView 里。
这里有两个新手容易踩的坑
内层 SplitView 作为子项,一定要给自己配 SplitView.fillWidth / SplitView.fillHeight(或者至少给个 SplitView.minimumWidth),否则外层不会给它分配空间,右边的区域会塌掉;每个面板和每个嵌套层最好也都写上最小尺寸,拖拽时才不会把某一栏拖没。
拖拽是联动的,拖外层分隔条,整个右侧区域一起变宽变窄;拖内层分隔条,只影响右栏上下两部分。嵌套的层级就是布局的层级,逐层理解就不会乱。
适用场景:IDE 式多面板界面、复杂工作区、编辑器类布局。
状态持久化
把拖好的面板比例保存起来,下次一键恢复。如图所示:

演示代码
qml
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
FadeInAnimation {
id: root
property color mainColor: Theme.listColors[Theme.demo4]
property var savedState: null
property bool hasSavedState: false
property bool splitChanged: false
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// ... 省略标题组件 TitleSeparator ...
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 50
color: Theme.demoStyle.frameBg
radius: 6
border.color: Theme.demoStyle.frameBorder
border.width: 1
RowLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 10
Text {
text: "状态:"
font.pointSize: 10
color: Theme.demoStyle.frameText
}
// 显示保存状态
Text {
text: root.hasSavedState ? "已保存" : "未保存"
font.pointSize: 10
font.bold: true
color: root.mainColor
}
Item {
Layout.fillWidth: true
}
// 在移动splitview时,状态闪烁
Text {
text: "Resizing"
font.pointSize: 10
font.bold: true
color: root.mainColor
visible: splitView.resizing
SequentialAnimation on opacity {
loops: Animation.Infinite
running: splitView.resizing
NumberAnimation { to: 0.3; duration: 500 }
NumberAnimation { to: 1.0; duration: 500 }
}
}
CustomButton {
text: "保存状态"
// 解决第一次保存失效的问题,必须先移动splitview
enabled: root.splitChanged
bgNormal: root.mainColor
bgPressed: Qt.color(root.mainColor).darker(1.2)
onClicked: {
root.savedState = splitView.saveState()
root.hasSavedState = true
console.log("SplitView状态已保存")
}
}
CustomButton {
text: "恢复状态"
enabled: root.hasSavedState
bgNormal: root.mainColor
bgPressed: Qt.color(root.mainColor).darker(1.2)
onClicked: {
if (root.savedState) {
splitView.restoreState(root.savedState)
console.log("SplitView状态已恢复")
}
}
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: Theme.demoStyle.frameBg
border.color: Theme.demoStyle.frameBorder
border.width: 1
radius: 6
SplitView {
id: splitView
anchors.fill: parent
anchors.margins: 10
orientation: Qt.Horizontal
handle: Rectangle {
implicitWidth: 6
implicitHeight: 6
color: root.mainColor
opacity: SplitHandle.pressed ? 1.0 : 0.7
}
onResizingChanged: {
root.splitChanged = true
}
// 面板1
CustomRect {
SplitView.minimumWidth: 60
rectColor: Qt.color(root.mainColor).darker(0.9)
rectNum: "1"
}
// 面板2
CustomRect {
SplitView.fillWidth: true
SplitView.minimumWidth: 60
rectColor: Qt.color(root.mainColor).darker(1.1)
rectNum: "2"
}
// 面板3
CustomRect {
SplitView.minimumWidth: 60
rectColor: Qt.color(root.mainColor).darker(1.3)
rectNum: "3"
}
}
}
}
}
SplitView 自带两个方法:saveState() 把当前所有分隔条的位置打包成一个对象,restoreState() 按这个对象恢复布局。
demo 里"保存状态"按钮把结果存进 savedState,"恢复状态"按钮再把它交还给 restoreState(),拖好的比例就回来了。
demo演示的是临时处理,把记住布局真正落地,还要把 savedState 序列化存到本地(比如转成 JSON 写进设置文件),程序启动时读出来调 restoreState(),用户上次拖好的布局就自动回来了。
适用场景:编辑器布局记忆、窗口布局偏好、多面板工具的个性化设置。
已验证环境:
- Qt 版本:Qt 6.8.2、Qt 6.11.1
- 操作系统:Windows 11
- GitHub:QML-Minimal-Demos/qml_splitview