From e6d9de34ea3098475412b380ca09d1f0e4e83c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E5=AD=90=E6=A5=9A=5Czhuzi?= Date: Fri, 15 Sep 2023 01:28:03 +0800 Subject: [PATCH] update --- example/qml-Qt6/App.qml | 1 - example/qml-Qt6/global/ItemsOriginal.qml | 2 +- example/qml-Qt6/page/T_TreeView.qml | 130 +----- example/qml/App.qml | 1 - example/qml/global/ItemsOriginal.qml | 2 +- example/qml/page/T_TreeView.qml | 134 ++----- src/FluentUI.cpp | 1 + .../imports/FluentUI/Controls/FluTreeItem.qml | 21 + .../imports/FluentUI/Controls/FluTreeView.qml | 362 +++++------------ src/Qt5/imports/FluentUI/qmldir | 1 + src/Qt5/imports/fluentui.qrc | 1 + .../FluentUI/Controls/FluScrollBar.qml | 1 + .../imports/FluentUI/Controls/FluTreeItem.qml | 11 + .../imports/FluentUI/Controls/FluTreeView.qml | 373 ++++++------------ .../FluentUI/Controls/FluTreeView2.qml | 144 ------- 15 files changed, 295 insertions(+), 890 deletions(-) create mode 100644 src/Qt5/imports/FluentUI/Controls/FluTreeItem.qml delete mode 100644 src/Qt6/imports/FluentUI/Controls/FluTreeView2.qml diff --git a/example/qml-Qt6/App.qml b/example/qml-Qt6/App.qml index 5430b133..70bc1c7a 100644 --- a/example/qml-Qt6/App.qml +++ b/example/qml-Qt6/App.qml @@ -28,7 +28,6 @@ Window { FluApp.init(app) FluTheme.darkMode = FluThemeType.System FluTheme.enableAnimation = true - FluTheme.nativeText = true FluApp.routes = { "/":"qrc:/example/qml/window/MainWindow.qml", "/about":"qrc:/example/qml/window/AboutWindow.qml", diff --git a/example/qml-Qt6/global/ItemsOriginal.qml b/example/qml-Qt6/global/ItemsOriginal.qml index f19c7bef..92f5ee53 100644 --- a/example/qml-Qt6/global/ItemsOriginal.qml +++ b/example/qml-Qt6/global/ItemsOriginal.qml @@ -302,7 +302,7 @@ FluObject{ onTap:{ navigationView.push(url) } } FluPaneItem{ - title:"TreeView" + title:"TreeView(Todo)" url:"qrc:/example/qml/page/T_TreeView.qml" onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) } onTap:{ navigationView.push(url) } diff --git a/example/qml-Qt6/page/T_TreeView.qml b/example/qml-Qt6/page/T_TreeView.qml index f839a8f1..bf940b19 100644 --- a/example/qml-Qt6/page/T_TreeView.qml +++ b/example/qml-Qt6/page/T_TreeView.qml @@ -9,49 +9,10 @@ FluScrollablePage { title:"TreeView" - function randomName() { - var names = ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十"] - return names[Math.floor(Math.random() * names.length)] - } - - function randomCompany() { - var companies = ["阿里巴巴", "腾讯", "百度", "京东", "华为", "小米", "字节跳动", "美团", "滴滴"] - return companies[Math.floor(Math.random() * companies.length)] - } - - function randomDepartment() { - var departments = ["技术部", "销售部", "市场部", "人事部", "财务部", "客服部", "产品部", "设计部", "运营部"] - return departments[Math.floor(Math.random() * departments.length)] - } - - function createEmployee() { - var name = randomName() - return tree_view.createItem(name, false) - } - - function createSubtree(numEmployees) { - var employees = [] - for (var i = 0; i < numEmployees; i++) { - employees.push(createEmployee()) - } - return tree_view.createItem(randomDepartment(), true, employees) - } - - function createOrg(numLevels, numSubtrees, numEmployees) { - if (numLevels === 0) { - return [] - } - var subtrees = [] - for (var i = 0; i < numSubtrees; i++) { - subtrees.push(createSubtree(numEmployees)) - } - return [tree_view.createItem(randomCompany(), true, subtrees)].concat(createOrg(numLevels - 1, numSubtrees, numEmployees)) - } - function treeData(){ const dig = (path = '0', level = 4) => { const list = []; - for (let i = 0; i < 10; i += 1) { + for (let i = 0; i < 6; i += 1) { const key = `${path}-${i}`; const treeNode = { title: key, @@ -68,65 +29,16 @@ FluScrollablePage { } FluArea{ - id:layout_actions Layout.fillWidth: true - Layout.topMargin: 20 - height: 50 + Layout.topMargin: 10 paddings: 10 - RowLayout{ - spacing: 14 - FluDropDownButton{ - id:btn_selection_model - Layout.preferredWidth: 140 - text:"None" - FluMenuItem{ - text:"None" - onClicked: { - btn_selection_model.text = text - tree_view.selectionMode = FluTabViewType.Equal - } - } - FluMenuItem{ - text:"Single" - onClicked: { - btn_selection_model.text = text - tree_view.selectionMode = FluTabViewType.SizeToContent - } - } - FluMenuItem{ - text:"Muiltple" - onClicked: { - btn_selection_model.text = text - tree_view.selectionMode = FluTabViewType.Compact - } - } - } - FluFilledButton{ - text:"获取选中的数据" - onClicked: { - if(tree_view.selectionMode === FluTreeViewType.None){ - showError("当前非选择模式,没有选中的数据") - } - if(tree_view.selectionMode === FluTreeViewType.Single){ - if(!tree_view.signleData()){ - showError("没有选中数据") - return - } - showSuccess(tree_view.signleData().text) - } - if(tree_view.selectionMode === FluTreeViewType.Multiple){ - if(tree_view.multipData().length===0){ - showError("没有选中数据") - return - } - var info = [] - tree_view.multipData().map((value)=>info.push(value.text)) - showSuccess(info.join(",")) - } - } - } + height: 60 + FluText{ + text:"共计:%1条数据".arg(tree_view.count()) + anchors.verticalCenter: parent.verticalCenter } } + FluArea{ Layout.fillWidth: true Layout.topMargin: 10 @@ -140,25 +52,6 @@ FluScrollablePage { left:parent.left bottom:parent.bottom } - onItemClicked: - (model)=>{ - showSuccess(model.text) - } - - Component.onCompleted: { - var org = createOrg(3, 3, 3) - createItem() - updateData(org) - } - } - FluTreeView2{ - id:tree_view_2 - width:240 - anchors{ - top:parent.top - bottom:parent.bottom - } - x:260 Component.onCompleted: { var data = treeData() dataSource = data @@ -174,15 +67,10 @@ FluScrollablePage { width:240 height:600 Component.onCompleted: { - var datas = [] - datas.push(createItem("Node1",false)) - datas.push(createItem("Node2",false)) - datas.push(createItem("Node2",true,[createItem("Node2-1",false),createItem("Node2-2",false)])) - updateData(datas) + var data = treeData() + dataSource = data } } ' } - - } diff --git a/example/qml/App.qml b/example/qml/App.qml index 72dadab8..0060ec77 100644 --- a/example/qml/App.qml +++ b/example/qml/App.qml @@ -28,7 +28,6 @@ Window { FluApp.init(app) FluTheme.darkMode = FluThemeType.System FluTheme.enableAnimation = true - FluTheme.nativeText = true FluApp.routes = { "/":"qrc:/example/qml/window/MainWindow.qml", "/about":"qrc:/example/qml/window/AboutWindow.qml", diff --git a/example/qml/global/ItemsOriginal.qml b/example/qml/global/ItemsOriginal.qml index 138a4cac..f5e6d534 100644 --- a/example/qml/global/ItemsOriginal.qml +++ b/example/qml/global/ItemsOriginal.qml @@ -302,7 +302,7 @@ FluObject{ onTap:{ navigationView.push(url) } } FluPaneItem{ - title:"TreeView" + title:"TreeView(Todo)" url:"qrc:/example/qml/page/T_TreeView.qml" onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) } onTap:{ navigationView.push(url) } diff --git a/example/qml/page/T_TreeView.qml b/example/qml/page/T_TreeView.qml index 5f507fef..2db8f164 100644 --- a/example/qml/page/T_TreeView.qml +++ b/example/qml/page/T_TreeView.qml @@ -10,105 +10,36 @@ FluScrollablePage { title:"TreeView" - function randomName() { - var names = ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十"] - return names[Math.floor(Math.random() * names.length)] - } - - function randomCompany() { - var companies = ["阿里巴巴", "腾讯", "百度", "京东", "华为", "小米", "字节跳动", "美团", "滴滴"] - return companies[Math.floor(Math.random() * companies.length)] - } - - function randomDepartment() { - var departments = ["技术部", "销售部", "市场部", "人事部", "财务部", "客服部", "产品部", "设计部", "运营部"] - return departments[Math.floor(Math.random() * departments.length)] - } - - function createEmployee() { - var name = randomName() - return tree_view.createItem(name, false) - } - - function createSubtree(numEmployees) { - var employees = [] - for (var i = 0; i < numEmployees; i++) { - employees.push(createEmployee()) - } - return tree_view.createItem(randomDepartment(), true, employees) - } - - function createOrg(numLevels, numSubtrees, numEmployees) { - if (numLevels === 0) { - return [] - } - var subtrees = [] - for (var i = 0; i < numSubtrees; i++) { - subtrees.push(createSubtree(numEmployees)) - } - return [tree_view.createItem(randomCompany(), true, subtrees)].concat(createOrg(numLevels - 1, numSubtrees, numEmployees)) + function treeData(){ + const dig = (path = '0', level = 4) => { + const list = []; + for (let i = 0; i < 6; i += 1) { + const key = `${path}-${i}`; + const treeNode = { + title: key, + key, + }; + if (level > 0) { + treeNode.children = dig(key, level - 1); + } + list.push(treeNode); + } + return list; + }; + return dig(); } FluArea{ - id:layout_actions Layout.fillWidth: true - Layout.topMargin: 20 - height: 50 + Layout.topMargin: 10 paddings: 10 - RowLayout{ - spacing: 14 - FluDropDownButton{ - id:btn_selection_model - Layout.preferredWidth: 140 - text:"None" - FluMenuItem{ - text:"None" - onClicked: { - btn_selection_model.text = text - tree_view.selectionMode = FluTabViewType.Equal - } - } - FluMenuItem{ - text:"Single" - onClicked: { - btn_selection_model.text = text - tree_view.selectionMode = FluTabViewType.SizeToContent - } - } - FluMenuItem{ - text:"Muiltple" - onClicked: { - btn_selection_model.text = text - tree_view.selectionMode = FluTabViewType.Compact - } - } - } - FluFilledButton{ - text:"获取选中的数据" - onClicked: { - if(tree_view.selectionMode === FluTreeViewType.None){ - showError("当前非选择模式,没有选中的数据") - } - if(tree_view.selectionMode === FluTreeViewType.Single){ - if(!tree_view.signleData()){ - showError("没有选中数据") - return - } - showSuccess(tree_view.signleData().text) - } - if(tree_view.selectionMode === FluTreeViewType.Multiple){ - if(tree_view.multipData().length===0){ - showError("没有选中数据") - return - } - var info = [] - tree_view.multipData().map((value)=>info.push(value.text)) - showSuccess(info.join(",")) - } - } - } + height: 60 + FluText{ + text:"共计:%1条数据".arg(tree_view.count()) + anchors.verticalCenter: parent.verticalCenter } } + FluArea{ Layout.fillWidth: true Layout.topMargin: 10 @@ -122,15 +53,9 @@ FluScrollablePage { left:parent.left bottom:parent.bottom } - onItemClicked: - (model)=>{ - showSuccess(model.text) - } - Component.onCompleted: { - var org = createOrg(3, 3, 3) - createItem() - updateData(org) + var data = treeData() + dataSource = data } } } @@ -143,15 +68,10 @@ FluScrollablePage { width:240 height:600 Component.onCompleted: { - var datas = [] - datas.push(createItem("Node1",false)) - datas.push(createItem("Node2",false)) - datas.push(createItem("Node2",true,[createItem("Node2-1",false),createItem("Node2-2",false)])) - updateData(datas) + var data = treeData() + dataSource = data } } ' } - - } diff --git a/src/FluentUI.cpp b/src/FluentUI.cpp index 898b1159..58969b75 100644 --- a/src/FluentUI.cpp +++ b/src/FluentUI.cpp @@ -148,6 +148,7 @@ void FluentUI::registerTypes(const char *uri){ qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluStaggeredView.qml"),uri,major,minor,"FluStaggeredView"); qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluProgressButton.qml"),uri,major,minor,"FluProgressButton"); qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluLoadingButton.qml"),uri,major,minor,"FluLoadingButton"); + qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluTreeItem.qml"),uri,major,minor,"FluTreeItem"); qmlRegisterUncreatableMetaObject(Fluent_Awesome::staticMetaObject, uri,major,minor,"FluentIcons", "Access to enums & flags only"); qmlRegisterUncreatableMetaObject(FluHttpType::staticMetaObject, uri,major,minor,"FluHttpType", "Access to enums & flags only"); diff --git a/src/Qt5/imports/FluentUI/Controls/FluTreeItem.qml b/src/Qt5/imports/FluentUI/Controls/FluTreeItem.qml new file mode 100644 index 00000000..48b8b10f --- /dev/null +++ b/src/Qt5/imports/FluentUI/Controls/FluTreeItem.qml @@ -0,0 +1,21 @@ +import QtQuick 2.15 + +QtObject { + property string key + property string title + property var children: [] + property int depth: 0 + property bool isExpanded: true + property var __parent + property bool __expanded:{ + var p = __parent; + while (p) { + if(!p.isExpanded){ + return false + } + p = p.__parent; + } + return true + } + property int index: 0 +} diff --git a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml index da39d4b0..e0bd081e 100644 --- a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml +++ b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml @@ -2,291 +2,143 @@ import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 +import Qt.labs.qmlmodels 1.0 import FluentUI 1.0 Item { - property int selectionMode: FluTreeViewType.None - property var currentElement - property var currentParentElement - property var rootModel: tree_model.get(0).items - signal itemClicked(var item) - id:root - ListModel{ - id:tree_model - ListElement{ - text: "根节点" - expanded:true - items:[] - key:"123456" - multipSelected:false - multipIndex:0 - multipParentKey:"" + property var dataSource + id:control + QtObject { + id:d + signal refreshLayout() + onRefreshLayout: { + table_view.forceLayout() } - } - Component{ - id: delegate_root - Column{ - width: calculateWidth() - property var itemModel: model - Repeater{ - id: repeater_first_level - model: items - delegate: delegate_items + function handleTree(treeData) { + var comItem = Qt.createComponent("FluTreeItem.qml"); + if (comItem.status !== Component.Ready) { + return } - function calculateWidth(){ - var w = 0; - for(var i = 0; i < repeater_first_level.count; i++) { - var child = repeater_first_level.itemAt(i) - if(w < child.width_hint){ - w = child.width_hint; + var stack = [] + var rawData = [] + for (var item of treeData) { + stack.push({node:item,depth:0,isExpanded:true,__parent:undefined}) + } + stack = stack.reverse() + var index =0 + while (stack.length > 0) { + const { node, depth,isExpanded,__parent} = stack.pop(); + node.depth = depth; + node.isExpanded = isExpanded; + node.__parent = __parent; + var objItem = comItem.createObject(table_view); + objItem.title = node.title + objItem.key = node.key + objItem.depth = node.depth + objItem.isExpanded = node.isExpanded + objItem.__parent = node.__parent + objItem.children = node.children + objItem.index = index + index = index + 1; + rawData.push({display:objItem}) + if (node.children && node.children.length > 0) { + const children = node.children.reverse(); + for (const child of children) { + stack.push({ node: child, depth: depth + 1,isExpanded:true,__parent:objItem}); } } - return w; } + return rawData } } - Component{ - id:delegate_items - Column{ - id:item_layout - property real level: (mapToItem(list_root,0,0).x+list_root.contentX)/0.001 - property var text: model.text??"Item" - property bool hasChild : (model.items !== undefined) && (model.items.count !== 0) - property var items: model.items??[] - property var expanded: model.expanded??true - property int width_hint: calculateWidth() - property bool singleSelected: currentElement === model - property var itemModel: model - function calculateWidth(){ - var w = Math.max(list_root.width, item_layout_row.implicitWidth + 10); - if(expanded){ - for(var i = 0; i < repeater_items.count; i++) { - var child = repeater_items.itemAt(i) - if(w < child.width_hint){ - w = child.width_hint; - } - } - } - return w; + onDataSourceChanged: { + table_model.clear() + var data = d.handleTree(dataSource) + table_model.rows = data + table_view.forceLayout() + console.debug("共计:%1条数据".arg(table_model.rowCount)) + } + TableModel { + id:table_model + TableModelColumn { display: "display" } + } + TableView{ + id:table_view + ScrollBar.horizontal: FluScrollBar{} + ScrollBar.vertical: FluScrollBar{} + boundsBehavior: Flickable.StopAtBounds + model: table_model + clip: true + anchors.fill: parent + rowHeightProvider: function(row) { + if(table_model.getRow(row).display.__expanded){ + return 38 } - Item{ - id:item_layout_rect - width: list_root.contentWidth - height: item_layout_row.implicitHeight - Rectangle{ - anchors.fill: parent - anchors.margins: 2 - color:{ - if(FluTheme.dark){ - if(item_layout.singleSelected && selectionMode === FluTreeViewType.Single){ - return Qt.rgba(62/255,62/255,62/255,1) - } - return (item_layout_mouse.containsMouse || item_layout_expanded.hovered || item_layout_checkbox.hovered)?Qt.rgba(62/255,62/255,62/255,1):Qt.rgba(0,0,0,0) - }else{ - if(item_layout.singleSelected && selectionMode === FluTreeViewType.Single){ - return Qt.rgba(0,0,0,0.06) - } - return (item_layout_mouse.containsMouse || item_layout_expanded.hovered || item_layout_checkbox.hovered)?Qt.rgba(0,0,0,0.03):Qt.rgba(0,0,0,0) - } - } - Rectangle{ - width: 3 - color:FluTheme.primaryColor.dark - visible: item_layout.singleSelected && (selectionMode === FluTreeViewType.Single) - radius: 3 - height: 20 - anchors{ - left: parent.left - verticalCenter: parent.verticalCenter + return 0 + } + delegate: Item { + implicitWidth: 46 + item_layout_text.width + 30*display.depth + RowLayout{ + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 14 + 30*display.depth + FluIcon{ + rotation: display.isExpanded?0:-90 + iconSource:FluentIcons.ChevronDown + iconSize: 15 + Layout.alignment: Qt.AlignVCenter + opacity: { + if(display.children){ + return true } + return false } MouseArea{ - id:item_layout_mouse anchors.fill: parent - hoverEnabled: true onClicked: { - item_layout_rect.onClickItem() + display.isExpanded = !display.isExpanded + d.refreshLayout() } } } - function onClickItem(){ - if(selectionMode === FluTreeViewType.None){ - itemClicked(model) + Rectangle{ + id:item_layout_text + radius: 4 + Layout.preferredWidth: item_text.implicitWidth+14 + Layout.preferredHeight:item_text.implicitHeight+14 + Layout.alignment: Qt.AlignVCenter + HoverHandler{ + id:item_hover_text } - if(selectionMode === FluTreeViewType.Single){ - currentElement = model - if(item_layout.parent.parent.parent.itemModel){ - currentParentElement = item_layout.parent.parent.parent.itemModel + color: { + if(FluTheme.dark){ + if(item_hover_text.hovered){ + return Qt.rgba(1,1,1,0.03) + } + return Qt.rgba(0,0,0,0) }else{ - if(item_layout.parent.itemModel){ - currentParentElement = item_layout.parent.itemModel - } - } - itemClicked(model) - } - if(selectionMode === FluTreeViewType.Multiple){ - - } - } - RowLayout{ - id:item_layout_row - anchors.verticalCenter: item_layout_rect.verticalCenter - Item{ - width: 15*level - Layout.alignment: Qt.AlignVCenter - } - FluCheckBox{ - id:item_layout_checkbox - text:"" - checked: itemModel.multipSelected - visible: selectionMode === FluTreeViewType.Multiple - Layout.leftMargin: 5 - function refreshCheckBox(){ - const stack = [tree_model.get(0)]; - const result = []; - while (stack.length > 0) { - const curr = stack.pop(); - result.unshift(curr); - if (curr.items) { - for(var i=0 ; i 0) { - const curr = stack.pop(); - if (curr.items) { - for(var i=0 ; i 0) { - const curr = stack.pop(); - if(curr.multipSelected){ - result.push(curr) - } - - for(var i=0 ; iFluentUI/Controls/ColorPicker/Content/PanelBorder.qml FluentUI/Controls/ColorPicker/Content/SBPicker.qml FluentUI/Controls/FluLoadingButton.qml + FluentUI/Controls/FluTreeItem.qml diff --git a/src/Qt6/imports/FluentUI/Controls/FluScrollBar.qml b/src/Qt6/imports/FluentUI/Controls/FluScrollBar.qml index 066f7d56..0d66e6a8 100644 --- a/src/Qt6/imports/FluentUI/Controls/FluScrollBar.qml +++ b/src/Qt6/imports/FluentUI/Controls/FluScrollBar.qml @@ -21,6 +21,7 @@ T.ScrollBar { property int minLine : 2 property int maxLine : 6 } + z: horizontal? 10 : 20 verticalPadding : vertical ? 15 : 3 horizontalPadding : horizontal ? 15 : 3 background: Rectangle{ diff --git a/src/Qt6/imports/FluentUI/Controls/FluTreeItem.qml b/src/Qt6/imports/FluentUI/Controls/FluTreeItem.qml index e974facc..2a95022a 100644 --- a/src/Qt6/imports/FluentUI/Controls/FluTreeItem.qml +++ b/src/Qt6/imports/FluentUI/Controls/FluTreeItem.qml @@ -7,4 +7,15 @@ QtObject { property int depth: 0 property bool isExpanded: true property var __parent + property bool __expanded:{ + var p = __parent; + while (p) { + if(!p.isExpanded){ + return false + } + p = p.__parent; + } + return true + } + property int index: 0 } diff --git a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml index 0d027493..2a9220a5 100644 --- a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml +++ b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml @@ -2,291 +2,146 @@ import QtQuick import QtQuick.Window import QtQuick.Layouts import QtQuick.Controls +import Qt.labs.qmlmodels import FluentUI Item { - property int selectionMode: FluTreeViewType.None - property var currentElement - property var currentParentElement - property var rootModel: tree_model.get(0).items - signal itemClicked(var item) - id:root - ListModel{ - id:tree_model - ListElement{ - text: "根节点" - expanded:true - items:[] - key:"123456" - multipSelected:false - multipIndex:0 - multipParentKey:"" + property var dataSource + id:control + QtObject { + id:d + signal refreshLayout() + onRefreshLayout: { + table_view.forceLayout() } - } - Component{ - id: delegate_root - Column{ - width: calculateWidth() - property var itemModel: model - Repeater{ - id: repeater_first_level - model: items - delegate: delegate_items + function handleTree(treeData) { + var comItem = Qt.createComponent("FluTreeItem.qml"); + if (comItem.status !== Component.Ready) { + return } - function calculateWidth(){ - var w = 0; - for(var i = 0; i < repeater_first_level.count; i++) { - var child = repeater_first_level.itemAt(i) - if(w < child.width_hint){ - w = child.width_hint; + var stack = [] + var rawData = [] + for (var item of treeData) { + stack.push({node:item,depth:0,isExpanded:true,__parent:undefined}) + } + stack = stack.reverse() + var index =0 + while (stack.length > 0) { + const { node, depth,isExpanded,__parent} = stack.pop(); + node.depth = depth; + node.isExpanded = isExpanded; + node.__parent = __parent; + var objItem = comItem.createObject(table_view); + objItem.title = node.title + objItem.key = node.key + objItem.depth = node.depth + objItem.isExpanded = node.isExpanded + objItem.__parent = node.__parent + objItem.children = node.children + objItem.index = index + index = index + 1; + rawData.push({display:objItem}) + if (node.children && node.children.length > 0) { + const children = node.children.reverse(); + for (const child of children) { + stack.push({ node: child, depth: depth + 1,isExpanded:true,__parent:objItem}); } } - return w; } + return rawData } } - Component{ - id:delegate_items - Column{ - id:item_layout - property real level: (mapToItem(list_root,0,0).x+list_root.contentX)/0.001 - property var text: model.text??"Item" - property bool hasChild : (model.items !== undefined) && (model.items.count !== 0) - property var items: model.items??[] - property var expanded: model.expanded??true - property int width_hint: calculateWidth() - property bool singleSelected: currentElement === model - property var itemModel: model - function calculateWidth(){ - var w = Math.max(list_root.width, item_layout_row.implicitWidth + 10); - if(expanded){ - for(var i = 0; i < repeater_items.count; i++) { - var child = repeater_items.itemAt(i) - if(w < child.width_hint){ - w = child.width_hint; + onDataSourceChanged: { + table_model.clear() + var data = d.handleTree(dataSource) + table_model.rows = data + table_view.forceLayout() + console.debug("共计:%1条数据".arg(table_model.rowCount)) + } + TableModel { + id:table_model + TableModelColumn { display: "display" } + } + ListView{ + anchors.fill: parent + TableView{ + id:table_view + ScrollBar.horizontal: FluScrollBar{} + ScrollBar.vertical: FluScrollBar{} + boundsBehavior: Flickable.StopAtBounds + model: table_model + clip: true + anchors.fill: parent + rowHeightProvider: function(row) { + if(table_model.getRow(row).display.__expanded){ + return 38 + } + return 0 + } + delegate: Item { + implicitWidth: 46 + item_layout_text.width + 30*display.depth + RowLayout{ + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 14 + 30*display.depth + FluIcon{ + rotation: display.isExpanded?0:-90 + iconSource:FluentIcons.ChevronDown + iconSize: 15 + Layout.alignment: Qt.AlignVCenter + opacity: { + if(display.children){ + return true + } + return false } - } - } - return w; - } - Item{ - id:item_layout_rect - width: list_root.contentWidth - height: item_layout_row.implicitHeight - Rectangle{ - anchors.fill: parent - anchors.margins: 2 - color:{ - if(FluTheme.dark){ - if(item_layout.singleSelected && selectionMode === FluTreeViewType.Single){ - return Qt.rgba(62/255,62/255,62/255,1) + MouseArea{ + anchors.fill: parent + onClicked: { + display.isExpanded = !display.isExpanded + d.refreshLayout() } - return (item_layout_mouse.containsMouse || item_layout_expanded.hovered || item_layout_checkbox.hovered)?Qt.rgba(62/255,62/255,62/255,1):Qt.rgba(0,0,0,0) - }else{ - if(item_layout.singleSelected && selectionMode === FluTreeViewType.Single){ - return Qt.rgba(0,0,0,0.06) - } - return (item_layout_mouse.containsMouse || item_layout_expanded.hovered || item_layout_checkbox.hovered)?Qt.rgba(0,0,0,0.03):Qt.rgba(0,0,0,0) } } Rectangle{ - width: 3 - color:FluTheme.primaryColor.dark - visible: item_layout.singleSelected && (selectionMode === FluTreeViewType.Single) - radius: 3 - height: 20 - anchors{ - left: parent.left - verticalCenter: parent.verticalCenter - } - } - MouseArea{ - id:item_layout_mouse - anchors.fill: parent - hoverEnabled: true - onClicked: { - item_layout_rect.onClickItem() - } - } - } - function onClickItem(){ - if(selectionMode === FluTreeViewType.None){ - itemClicked(model) - } - if(selectionMode === FluTreeViewType.Single){ - currentElement = model - if(item_layout.parent.parent.parent.itemModel){ - currentParentElement = item_layout.parent.parent.parent.itemModel - }else{ - if(item_layout.parent.itemModel){ - currentParentElement = item_layout.parent.itemModel - } - } - itemClicked(model) - } - if(selectionMode === FluTreeViewType.Multiple){ - - } - } - RowLayout{ - id:item_layout_row - anchors.verticalCenter: item_layout_rect.verticalCenter - Item{ - width: 15*level + id:item_layout_text + radius: 4 + Layout.preferredWidth: item_text.implicitWidth+14 + Layout.preferredHeight:item_text.implicitHeight+14 Layout.alignment: Qt.AlignVCenter - } - FluCheckBox{ - id:item_layout_checkbox - text:"" - checked: itemModel.multipSelected - visible: selectionMode === FluTreeViewType.Multiple - Layout.leftMargin: 5 - function refreshCheckBox(){ - const stack = [tree_model.get(0)]; - const result = []; - while (stack.length > 0) { - const curr = stack.pop(); - result.unshift(curr); - if (curr.items) { - for(var i=0 ; i 0) { - const curr = stack.pop(); - if (curr.items) { - for(var i=0 ; i 0) { - const curr = stack.pop(); - if(curr.multipSelected){ - result.push(curr) - } - - for(var i=0 ; i 0) { - const { node, depth,isExpanded,__parent} = stack.pop(); - node.depth = depth; - node.isExpanded = isExpanded; - node.__parent = __parent; - var objItem = comItem.createObject(table_view); - objItem.title = node.title - objItem.key = node.key - objItem.depth = node.depth - objItem.isExpanded = node.isExpanded - objItem.__parent = node.__parent - objItem.children = node.children - table_model.appendRow({itemData:objItem}) - if (node.children && node.children.length > 0) { - const children = node.children.reverse(); - for (const child of children) { - stack.push({ node: child, depth: depth + 1,isExpanded:true,__parent:objItem}); - } - } - } - - console.debug("共计:%1条数据".arg(table_model.rowCount)) - } - - - - onDataSourceChanged: { - table_model.clear() - - iterateTree(dataSource) - } - - TableModel { - id:table_model - TableModelColumn { display: "itemData" } - } - - Component{ - id:com_item - - Rectangle { - implicitWidth: 120 + 50*itemData.depth - implicitHeight: 38 - RowLayout{ - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin:14+50*itemData.depth - FluIcon{ - rotation: itemData.isExpanded?0:-90 - iconSource:FluentIcons.ChevronDown - iconSize: 15 - Layout.alignment: Qt.AlignVCenter - Behavior on rotation { - enabled: FluTheme.enableAnimation - NumberAnimation{ - duration: 167 - easing.type: Easing.OutCubic - } - } - opacity: { - if(itemData.children){ - return true - } - return false - } - MouseArea{ - anchors.fill: parent - onClicked: { - itemData.isExpanded = !itemData.isExpanded - } - } - } - - Rectangle{ - radius: 4 - Layout.preferredWidth: item_text.width+14 - Layout.preferredHeight:item_text.height+14 - Layout.alignment: Qt.AlignVCenter - HoverHandler{ - id:item_hover_text - } - color: { - if(FluTheme.dark){ - if(item_hover_text.hovered){ - return Qt.rgba(1,1,1,0.03) - } - return Qt.rgba(0,0,0,0) - }else{ - if(item_hover_text.hovered){ - return Qt.rgba(0,0,0,0.03) - } - return Qt.rgba(0,0,0,0) - } - } - Text { - id:item_text - text: itemData.title - anchors.centerIn: parent - } - } - } - } - } - - TableView{ - id:table_view - anchors.fill: parent - ScrollBar.horizontal: FluScrollBar{} - ScrollBar.vertical: FluScrollBar{} - boundsBehavior: Flickable.StopAtBounds - model: table_model - delegate: Loader{ - property var itemData: display - sourceComponent: { - if(!itemData.__parent){ - return com_item - } - if(itemData.__parent.isExpanded){ - return com_item - } - return undefined - } - } - } - -}