背景
感觉QML自带的TreeView不是很好用,用在文件路径树形结构比较多,但是想用在自己数据里,就不太方便了,所以自己做一个。
用‘ListView里迭代ListView’的方法,制作树形结构,成果图:
代码
新建一个MyTreeView.qml用来写主要代码,再在main.qml中调用MyTreeView,并为它填充数据。
这里数据是在qml中用JSON.parse构建的json数据,也可以在cpp中用QJsonArray和QJsonObject来构建数据。
// MyTreeView.qml
import QtQuick 2.0
Item {
id: root
property alias model: list_view.model
ListView {
id: list_view
width: contentWidth
anchors.fill: parent
anchors.margins: 10
delegate: list_delegate
}
Component {
id: list_delegate
Item{
id: list_itemgroup
width: leftLine.width + centre.width + rightLine.width + listView.width
height: Math.max(centre.height, listView.height)
property int lineY: leftLine.y
Rectangle {
id: leftLine
width: 20
height: 1
color: "#d3dee4"
visible: modelData.id >= 0
anchors.verticalCenter: centre.verticalCenter
}
Rectangle {
id: centre
width: 150
height: 50
color: "#d3dee4"
radius: 5
anchors.left: leftLine.right
anchors.verticalCenter: parent.verticalCenter
Text {
text: qsTr(modelData.name)
font.pixelSize: 20
font.bold: true
anchors.centerIn: parent
}
}
Rectangle {
id: rightLine
width: 20
height: 1
color: "#d3dee4"
visible: modelData.subnodes.length > 0
anchors.verticalCenter: centre.verticalCenter
anchors.left: centre.right
}
Rectangle {
id: verticalLine
width: 1
color: "#d3dee4"
x: parent.width + 1
visible: modelData.subnodes.length > 1
anchors.top: parent.top
anchors.bottom: parent.bottom
}
ListView {
id: listView
delegate: list_delegate
height: contentHeight
width: contentWidth
anchors.right: parent.right
model: modelData.subnodes
spacing: 10
onModelChanged: {
}
}
Component.onCompleted: {
listView.forceLayout() // 要先确保listView加载子项完成
// 画一下verticalLine的y坐标起点和终点
for (var i = 0; i < modelData.subnodes.length; i++) {
var item = listView.itemAtIndex(i)
if (i === 0) {
verticalLine.anchors.topMargin = item.lineY
} else if (i === modelData.subnodes.length-1) {
verticalLine.anchors.bottomMargin = item.lineY
}
}
}
}
}
}
// main.qml
import QtQuick 2.15
import QtQml.Models 2.15
import QtQuick.Window 2.12
import QtQuick.Controls 1.4
Window {
id: window_
width: 940
height: 680
visible: true
title: qsTr("Hello World")
color: "#103e6f"
Item {
id: home
anchors.fill: parent
MyTreeView {
id: treeView
anchors.fill: parent
}
}
Component.onCompleted: {
var data = JSON.parse('[{
"id": -1,
"name": "目录",
"subnodes": [{
"id": 0,
"name": "第一本书",
"subnodes": [{
"id": 1,
"name": "第一章",
"subnodes": [{
"id": 2,
"name": "第一节",
"subnodes": []
}, {
"id": 3,
"name": "第二节",
"subnodes": []
}]
}, {
"id": 4,
"name": "第二章",
"subnodes": [{
"id": 5,
"name": "第一节",
"subnodes": []
}, {
"id": 6,
"name": "第二节",
"subnodes": []
}, {
"id": 7,
"name": "第三节",
"subnodes": []
}]
}]
}, {
"id": 8,
"name": "第二本书",
"subnodes": [{
"id": 9,
"name": "第一章",
"subnodes": [{
"id": 10,
"name": "第一节",
"subnodes": []
}, {
"id": 11,
"name": "第二节",
"subnodes": []
}]
}, {
"id": 12,
"name": "第二章",
"subnodes": [{
"id": 13,
"name": "第一节",
"subnodes": []
}]
}]
}]
}]')
treeView.model = data
}
}