diff --git a/example/T_TreeView.qml b/example/T_TreeView.qml index db7ff27..5ec7ec7 100644 --- a/example/T_TreeView.qml +++ b/example/T_TreeView.qml @@ -12,181 +12,44 @@ Item { fontStyle: FluText.TitleLarge } - ListModel { - id: tree_model - ListElement { - text: "Root" - expanded:true - items: [ - ListElement { - text: "Node 1" - expanded:false - items: [ - ListElement { - text: "Node 1.1" - expanded:true - items:[ - ListElement{ - text:"Node 1.1.1" - expanded:true - items:[ - ListElement{ - text:"Node 1.1.1.1" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.2" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.3" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.4" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.5" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.6" - expanded:false - items:[] - } - ] - } - ] - }, - ListElement { - text: "Node 1.2" - expanded:false - items:[] - } - ] - }, - ListElement { - text: "Node 2" - expanded:false - items:[] - }, - ListElement { - text: "Node 3" - expanded:true - items: [ - ListElement { - text: "Node 3.1" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.2" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.3" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.4" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.5" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.6" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.7" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.8" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.9" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.10" - expanded:true - items:[ - ListElement{ - text:"Node 3.10.1" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.2" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.3" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.4" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.5" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.6" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.7" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.8" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.9" - expanded:false - items:[] - } - ] - }, - ListElement { - text: "Node 3.11" - expanded:false - items:[] - } - ] - } - ] - } + 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)) + } FluTreeView{ @@ -197,7 +60,17 @@ Item { left:parent.left bottom:parent.bottom } - model:tree_model + onItemClicked: + (model)=>{ + showSuccess(model.text) + } + + Component.onCompleted: { + var org = createOrg(10, 3, 5) + updateData(org) + + } + } @@ -207,11 +80,62 @@ Item { right: parent.right top: parent.top } - FluButton{ - text:"test" - onClicked: { + + FluText{ + text:{ + if(tree_view.selectionMode === FluTreeView.None){ + return "FluTreeView.None" + } + if(tree_view.selectionMode === FluTreeView.Single){ + return "FluTreeView.Single" + } + if(tree_view.selectionMode === FluTreeView.Multiple){ + return "FluTreeView.Multiple" + } } } - } + FluButton{ + text:"None" + onClicked: { + tree_view.selectionMode = FluTreeView.None + } + } + + FluButton{ + text:"Single" + onClicked: { + tree_view.selectionMode = FluTreeView.Single + } + } + + FluButton{ + text:"Multiple" + onClicked: { + tree_view.selectionMode = FluTreeView.Multiple + } + } + + FluFilledButton{ + text:"获取选中的数据" + onClicked: { + if(tree_view.selectionMode === FluTreeView.None){ + showError("当前非选择模式,没有选中的数据") + } + if(tree_view.selectionMode === FluTreeView.Single){ + showSuccess(tree_view.signleData().text) + } + if(tree_view.selectionMode === FluTreeView.Multiple){ + if(tree_view.multipData().length===0){ + showError("没有选中数据") + return + } + var info = [] + tree_view.multipData().map((value)=>info.push(value.text)) + showSuccess(info.join(",")) + } + } + } + + } } diff --git a/src/controls/FluCheckBox.qml b/src/controls/FluCheckBox.qml index 9712b19..62d0f7b 100644 --- a/src/controls/FluCheckBox.qml +++ b/src/controls/FluCheckBox.qml @@ -7,6 +7,7 @@ Item { id:root property bool checked: false property string text: "Check Box" + property var checkClicked width: childrenRect.width height: childrenRect.height @@ -78,6 +79,10 @@ Item { anchors.fill: parent hoverEnabled: true onClicked: { + if(checkClicked){ + checkClicked() + return + } checked = !checked } } diff --git a/src/controls/FluTreeView.qml b/src/controls/FluTreeView.qml index a9c4764..5043e22 100644 --- a/src/controls/FluTreeView.qml +++ b/src/controls/FluTreeView.qml @@ -9,263 +9,247 @@ Rectangle { id:root color: FluTheme.isDark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(253/255,253/255,253/255,1) - property alias model: list_root.model + enum TreeViewSelectionMode { + None, + Single, + Multiple + } - ListModel { - id: tree_model - ListElement { - text: "Root" + property int selectionMode: FluTreeView.None + + property var currentElement + property var currentParentElement + + property var multipElement: [] + + property var rootModel: tree_model.get(0).items + + signal itemClicked(var item) + + ListModel{ + id:tree_model + ListElement{ + text: "根节点" expanded:true - items: [ - ListElement { - text: "Node 1" - expanded:false - items: [ - ListElement { - text: "Node 1.1" - expanded:true - items:[ - ListElement{ - text:"Node 1.1.1" - expanded:true - items:[ - ListElement{ - text:"Node 1.1.1.1" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.2" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.3" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.4" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.5" - expanded:false - items:[] - }, - ListElement{ - text:"Node 1.1.1.6" - expanded:false - items:[] - } - ] - } - ] - }, - ListElement { - text: "Node 1.2" - expanded:false - items:[] - } - ] - }, - ListElement { - text: "Node 2" - expanded:false - items:[] - }, - ListElement { - text: "Node 3" - expanded:true - items: [ - ListElement { - text: "Node 3.1" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.2" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.3" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.4" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.5" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.6" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.7" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.8" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.9" - expanded:false - items:[] - }, - ListElement { - text: "Node 3.10" - expanded:true - items:[ - ListElement{ - text:"Node 3.10.1" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.2" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.3" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.4" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.5" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.6" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.7" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.8" - expanded:false - items:[] - }, - ListElement{ - text:"Node 3.10.9" - expanded:false - items:[] - } - ] - }, - ListElement { - text: "Node 3.11" - expanded:false - items:[] - } - ] - } - ] + items:[] } } - + Component{ + id: delegate_root + Column{ + width: calculateWidth() + property var itemModel: model + Repeater{ + id: repeater_first_level + model: items + delegate: delegate_items + } + 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; + } + } + return w; + } + } + } Component{ - id:comp_delegate + id:delegate_items - ColumnLayout{ - id:layout_column - spacing: 0 + 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 isItems : (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 - property int level: mapToItem(list_root,0,0).x/0.001 - width: list_root.width + + 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; + } Item{ - Layout.preferredHeight: childrenRect.height - Layout.preferredWidth: childrenRect.width + id:item_layout_rect + width: list_root.contentWidth + height: item_layout_row.implicitHeight + Rectangle{ - height: parent.height - width: list_root.width + anchors.fill: parent anchors.margins: 2 - radius: 4 color:{ if(FluTheme.isDark){ + if(item_layout.singleSelected && selectionMode === FluTreeView.Single){ + return Qt.rgba(62/255,62/255,62/255,1) + } return (item_layout_mouse.containsMouse || item_layout_expanded.hovered)?Qt.rgba(62/255,62/255,62/255,1):Qt.rgba(50/255,50/255,50/255,1) }else{ + if(item_layout.singleSelected && selectionMode === FluTreeView.Single){ + return Qt.rgba(244/255,244/255,244/255,1) + } return (item_layout_mouse.containsMouse || item_layout_expanded.hovered)?Qt.rgba(244/255,244/255,244/255,1):Qt.rgba(253/255,253/255,253/255,1) } } + Rectangle{ + width: 3 + color:FluTheme.primaryColor.dark + visible: item_layout.singleSelected && (selectionMode === FluTreeView.Single) + radius: 3 + height: 20 + anchors{ + left: parent.left + verticalCenter: parent.verticalCenter + } + } + MouseArea{ id:item_layout_mouse anchors.fill: parent hoverEnabled: true onClicked: { - console.debug("---------") + item_layout_rect.onClickItem() } } } + + function onClickItem(){ + if(selectionMode === FluTreeView.None){ + itemClicked(model) + } + if(selectionMode === FluTreeView.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 + } + } + } + if(selectionMode === FluTreeView.Multiple){ + + } + } + RowLayout{ - spacing: 0 + id:item_layout_row + anchors.verticalCenter: item_layout_rect.verticalCenter + Item{ width: 15*level Layout.alignment: Qt.AlignVCenter } + + FluCheckBox{ + text:"" + checked: multipElement.includes(itemModel) + visible: selectionMode === FluTreeView.Multiple + checkClicked:function(){ + if(checked){ + multipElement = multipElement.filter((value) => value !== itemModel) + }else{ + multipElement = [...multipElement,itemModel] + } + } + } + FluIconButton{ id:item_layout_expanded color:"#00000000" - icon:model.expanded?FluentIcons.FA_angle_down:FluentIcons.FA_angle_right + icon:item_layout.expanded?FluentIcons.FA_angle_down:FluentIcons.FA_angle_right + opacity: item_layout.isItems onClicked: { + if(!item_layout.isItems){ + item_layout_rect.onClickItem() + return + } model.expanded = !model.expanded } } - FluText{ - text:model.text + + FluText { + text: item_layout.text Layout.alignment: Qt.AlignVCenter + topPadding: 10 + bottomPadding: 10 } } } + Item{ - Layout.preferredWidth: layout_column.width - Layout.preferredHeight:childrenRect.height - visible: model.expanded - ListView{ - x:0.001 - width: parent.width - height: childrenRect.height - model:itemModel.items - delegate:comp_delegate - boundsBehavior: ListView.StopAtBounds + id:item_sub + visible: { + if(!isItems){ + return false + } + return item_layout.expanded??false } + + width: item_sub_layout.implicitWidth + height: item_sub_layout.implicitHeight + x:0.001 + Column{ + id: item_sub_layout + Repeater{ + id:repeater_items + model: item_layout.items + delegate: delegate_items + } + } + } } } - ListView{ - id:list_root + ListView { + id: list_root anchors.fill: parent - delegate:comp_delegate + delegate: delegate_root + boundsBehavior: ListView.StopAtBounds + contentWidth: contentItem.childrenRect.width + model: tree_model + flickableDirection: Flickable.HorizontalAndVerticalFlick clip: true + ScrollBar.vertical: ScrollBar { } + ScrollBar.horizontal: ScrollBar { } + } + + + function updateData(items){ + rootModel.clear() + rootModel.append(items) + } + + function signleData(){ + return currentElement + } + + function multipData(){ + return multipElement + } + + function createItem(text="Title",expanded=true,items=[]){ + return {text:text,expanded:expanded,items:items}; }