mirror of
https://github.com/zhuzichu520/FluentUI.git
synced 2024-11-23 11:17:15 +08:00
update
This commit is contained in:
parent
c47fa5ebc7
commit
e6d9de34ea
@ -28,7 +28,6 @@ Window {
|
|||||||
FluApp.init(app)
|
FluApp.init(app)
|
||||||
FluTheme.darkMode = FluThemeType.System
|
FluTheme.darkMode = FluThemeType.System
|
||||||
FluTheme.enableAnimation = true
|
FluTheme.enableAnimation = true
|
||||||
FluTheme.nativeText = true
|
|
||||||
FluApp.routes = {
|
FluApp.routes = {
|
||||||
"/":"qrc:/example/qml/window/MainWindow.qml",
|
"/":"qrc:/example/qml/window/MainWindow.qml",
|
||||||
"/about":"qrc:/example/qml/window/AboutWindow.qml",
|
"/about":"qrc:/example/qml/window/AboutWindow.qml",
|
||||||
|
@ -302,7 +302,7 @@ FluObject{
|
|||||||
onTap:{ navigationView.push(url) }
|
onTap:{ navigationView.push(url) }
|
||||||
}
|
}
|
||||||
FluPaneItem{
|
FluPaneItem{
|
||||||
title:"TreeView"
|
title:"TreeView(Todo)"
|
||||||
url:"qrc:/example/qml/page/T_TreeView.qml"
|
url:"qrc:/example/qml/page/T_TreeView.qml"
|
||||||
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
|
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
|
||||||
onTap:{ navigationView.push(url) }
|
onTap:{ navigationView.push(url) }
|
||||||
|
@ -9,49 +9,10 @@ FluScrollablePage {
|
|||||||
|
|
||||||
title:"TreeView"
|
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(){
|
function treeData(){
|
||||||
const dig = (path = '0', level = 4) => {
|
const dig = (path = '0', level = 4) => {
|
||||||
const list = [];
|
const list = [];
|
||||||
for (let i = 0; i < 10; i += 1) {
|
for (let i = 0; i < 6; i += 1) {
|
||||||
const key = `${path}-${i}`;
|
const key = `${path}-${i}`;
|
||||||
const treeNode = {
|
const treeNode = {
|
||||||
title: key,
|
title: key,
|
||||||
@ -68,65 +29,16 @@ FluScrollablePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FluArea{
|
FluArea{
|
||||||
id:layout_actions
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 20
|
Layout.topMargin: 10
|
||||||
height: 50
|
|
||||||
paddings: 10
|
paddings: 10
|
||||||
RowLayout{
|
height: 60
|
||||||
spacing: 14
|
FluText{
|
||||||
FluDropDownButton{
|
text:"共计:%1条数据".arg(tree_view.count())
|
||||||
id:btn_selection_model
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
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(","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FluArea{
|
FluArea{
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 10
|
Layout.topMargin: 10
|
||||||
@ -140,25 +52,6 @@ FluScrollablePage {
|
|||||||
left:parent.left
|
left:parent.left
|
||||||
bottom:parent.bottom
|
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: {
|
Component.onCompleted: {
|
||||||
var data = treeData()
|
var data = treeData()
|
||||||
dataSource = data
|
dataSource = data
|
||||||
@ -174,15 +67,10 @@ FluScrollablePage {
|
|||||||
width:240
|
width:240
|
||||||
height:600
|
height:600
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var datas = []
|
var data = treeData()
|
||||||
datas.push(createItem("Node1",false))
|
dataSource = data
|
||||||
datas.push(createItem("Node2",false))
|
|
||||||
datas.push(createItem("Node2",true,[createItem("Node2-1",false),createItem("Node2-2",false)]))
|
|
||||||
updateData(datas)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ Window {
|
|||||||
FluApp.init(app)
|
FluApp.init(app)
|
||||||
FluTheme.darkMode = FluThemeType.System
|
FluTheme.darkMode = FluThemeType.System
|
||||||
FluTheme.enableAnimation = true
|
FluTheme.enableAnimation = true
|
||||||
FluTheme.nativeText = true
|
|
||||||
FluApp.routes = {
|
FluApp.routes = {
|
||||||
"/":"qrc:/example/qml/window/MainWindow.qml",
|
"/":"qrc:/example/qml/window/MainWindow.qml",
|
||||||
"/about":"qrc:/example/qml/window/AboutWindow.qml",
|
"/about":"qrc:/example/qml/window/AboutWindow.qml",
|
||||||
|
@ -302,7 +302,7 @@ FluObject{
|
|||||||
onTap:{ navigationView.push(url) }
|
onTap:{ navigationView.push(url) }
|
||||||
}
|
}
|
||||||
FluPaneItem{
|
FluPaneItem{
|
||||||
title:"TreeView"
|
title:"TreeView(Todo)"
|
||||||
url:"qrc:/example/qml/page/T_TreeView.qml"
|
url:"qrc:/example/qml/page/T_TreeView.qml"
|
||||||
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
|
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
|
||||||
onTap:{ navigationView.push(url) }
|
onTap:{ navigationView.push(url) }
|
||||||
|
@ -10,105 +10,36 @@ FluScrollablePage {
|
|||||||
|
|
||||||
title:"TreeView"
|
title:"TreeView"
|
||||||
|
|
||||||
function randomName() {
|
function treeData(){
|
||||||
var names = ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十"]
|
const dig = (path = '0', level = 4) => {
|
||||||
return names[Math.floor(Math.random() * names.length)]
|
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);
|
||||||
function randomCompany() {
|
|
||||||
var companies = ["阿里巴巴", "腾讯", "百度", "京东", "华为", "小米", "字节跳动", "美团", "滴滴"]
|
|
||||||
return companies[Math.floor(Math.random() * companies.length)]
|
|
||||||
}
|
}
|
||||||
|
return list;
|
||||||
function randomDepartment() {
|
};
|
||||||
var departments = ["技术部", "销售部", "市场部", "人事部", "财务部", "客服部", "产品部", "设计部", "运营部"]
|
return dig();
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FluArea{
|
FluArea{
|
||||||
id:layout_actions
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 20
|
Layout.topMargin: 10
|
||||||
height: 50
|
|
||||||
paddings: 10
|
paddings: 10
|
||||||
RowLayout{
|
height: 60
|
||||||
spacing: 14
|
FluText{
|
||||||
FluDropDownButton{
|
text:"共计:%1条数据".arg(tree_view.count())
|
||||||
id:btn_selection_model
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
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(","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FluArea{
|
FluArea{
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 10
|
Layout.topMargin: 10
|
||||||
@ -122,15 +53,9 @@ FluScrollablePage {
|
|||||||
left:parent.left
|
left:parent.left
|
||||||
bottom:parent.bottom
|
bottom:parent.bottom
|
||||||
}
|
}
|
||||||
onItemClicked:
|
|
||||||
(model)=>{
|
|
||||||
showSuccess(model.text)
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var org = createOrg(3, 3, 3)
|
var data = treeData()
|
||||||
createItem()
|
dataSource = data
|
||||||
updateData(org)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,15 +68,10 @@ FluScrollablePage {
|
|||||||
width:240
|
width:240
|
||||||
height:600
|
height:600
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var datas = []
|
var data = treeData()
|
||||||
datas.push(createItem("Node1",false))
|
dataSource = data
|
||||||
datas.push(createItem("Node2",false))
|
|
||||||
datas.push(createItem("Node2",true,[createItem("Node2-1",false),createItem("Node2-2",false)]))
|
|
||||||
updateData(datas)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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/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/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/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(Fluent_Awesome::staticMetaObject, uri,major,minor,"FluentIcons", "Access to enums & flags only");
|
||||||
qmlRegisterUncreatableMetaObject(FluHttpType::staticMetaObject, uri,major,minor,"FluHttpType", "Access to enums & flags only");
|
qmlRegisterUncreatableMetaObject(FluHttpType::staticMetaObject, uri,major,minor,"FluHttpType", "Access to enums & flags only");
|
||||||
|
21
src/Qt5/imports/FluentUI/Controls/FluTreeItem.qml
Normal file
21
src/Qt5/imports/FluentUI/Controls/FluTreeItem.qml
Normal file
@ -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
|
||||||
|
}
|
@ -2,291 +2,143 @@ import QtQuick 2.15
|
|||||||
import QtQuick.Window 2.15
|
import QtQuick.Window 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
import Qt.labs.qmlmodels 1.0
|
||||||
import FluentUI 1.0
|
import FluentUI 1.0
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property int selectionMode: FluTreeViewType.None
|
property var dataSource
|
||||||
property var currentElement
|
id:control
|
||||||
property var currentParentElement
|
QtObject {
|
||||||
property var rootModel: tree_model.get(0).items
|
id:d
|
||||||
signal itemClicked(var item)
|
signal refreshLayout()
|
||||||
id:root
|
onRefreshLayout: {
|
||||||
ListModel{
|
table_view.forceLayout()
|
||||||
id:tree_model
|
|
||||||
ListElement{
|
|
||||||
text: "根节点"
|
|
||||||
expanded:true
|
|
||||||
items:[]
|
|
||||||
key:"123456"
|
|
||||||
multipSelected:false
|
|
||||||
multipIndex:0
|
|
||||||
multipParentKey:""
|
|
||||||
}
|
}
|
||||||
}
|
function handleTree(treeData) {
|
||||||
Component{
|
var comItem = Qt.createComponent("FluTreeItem.qml");
|
||||||
id: delegate_root
|
if (comItem.status !== Component.Ready) {
|
||||||
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: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;
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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
|
|
||||||
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<curr.items.count ; i++){
|
|
||||||
curr.items.setProperty(i,"multipIndex",i)
|
|
||||||
curr.items.setProperty(i,"multipParentKey",curr.key)
|
|
||||||
stack.push(curr.items.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(var j=0 ; j<result.length-1 ; j++){
|
|
||||||
var item = result[j]
|
|
||||||
let obj = result.find(function(o) {
|
|
||||||
return o.key === item.multipParentKey;
|
|
||||||
});
|
|
||||||
if((item.items !== undefined) && (item.items.count !== 0)){
|
|
||||||
var items = item.items
|
|
||||||
for(var k=0 ; k<items.count ; k++){
|
|
||||||
if(items.get(k).multipSelected === false){
|
|
||||||
obj.items.setProperty(item.multipIndex,"multipSelected",false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
obj.items.setProperty(item.multipIndex,"multipSelected",true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clickListener:function(){
|
|
||||||
if(hasChild){
|
|
||||||
const stack = [itemModel];
|
|
||||||
while (stack.length > 0) {
|
|
||||||
const curr = stack.pop();
|
|
||||||
if (curr.items) {
|
|
||||||
for(var i=0 ; i<curr.items.count ; i++){
|
|
||||||
curr.items.setProperty(i,"multipSelected",!itemModel.multipSelected)
|
|
||||||
stack.push(curr.items.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refreshCheckBox()
|
|
||||||
}else{
|
|
||||||
itemModel.multipSelected = !itemModel.multipSelected
|
|
||||||
refreshCheckBox()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FluIconButton{
|
|
||||||
id:item_layout_expanded
|
|
||||||
color:"#00000000"
|
|
||||||
opacity: item_layout.hasChild
|
|
||||||
onClicked: {
|
|
||||||
if(!item_layout.hasChild){
|
|
||||||
item_layout_rect.onClickItem()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
model.expanded = !model.expanded
|
var stack = []
|
||||||
|
var rawData = []
|
||||||
|
for (var item of treeData) {
|
||||||
|
stack.push({node:item,depth:0,isExpanded:true,__parent:undefined})
|
||||||
}
|
}
|
||||||
contentItem: FluIcon{
|
stack = stack.reverse()
|
||||||
rotation: item_layout.expanded?0:-90
|
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 rawData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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
|
iconSource:FluentIcons.ChevronDown
|
||||||
iconSize: 15
|
iconSize: 15
|
||||||
Behavior on rotation {
|
Layout.alignment: Qt.AlignVCenter
|
||||||
enabled: FluTheme.enableAnimation
|
opacity: {
|
||||||
NumberAnimation{
|
if(display.children){
|
||||||
duration: 167
|
return true
|
||||||
easing.type: Easing.OutCubic
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
MouseArea{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
display.isExpanded = !display.isExpanded
|
||||||
|
d.refreshLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FluText {
|
FluText {
|
||||||
text: item_layout.text
|
id:item_text
|
||||||
Layout.alignment: Qt.AlignVCenter
|
text: display.title
|
||||||
topPadding: 7
|
anchors.centerIn: parent
|
||||||
bottomPadding: 7
|
|
||||||
}
|
}
|
||||||
}
|
MouseArea{
|
||||||
}
|
|
||||||
Item{
|
|
||||||
id:item_sub
|
|
||||||
visible: {
|
|
||||||
if(!hasChild){
|
|
||||||
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
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
delegate: delegate_root
|
onClicked: {
|
||||||
contentWidth: contentItem.childrenRect.width
|
d.refreshLayout()
|
||||||
model: tree_model
|
|
||||||
flickableDirection: Flickable.HorizontalAndVerticalFlick
|
|
||||||
clip: true
|
|
||||||
boundsBehavior: ListView.StopAtBounds
|
|
||||||
ScrollBar.vertical: FluScrollBar {}
|
|
||||||
ScrollBar.horizontal: FluScrollBar { }
|
|
||||||
}
|
|
||||||
function updateData(items){
|
|
||||||
rootModel.clear()
|
|
||||||
rootModel.append(items)
|
|
||||||
}
|
|
||||||
function signleData(){
|
|
||||||
return currentElement
|
|
||||||
}
|
|
||||||
function multipData(){
|
|
||||||
const stack = [tree_model.get(0)];
|
|
||||||
const result = [];
|
|
||||||
while (stack.length > 0) {
|
|
||||||
const curr = stack.pop();
|
|
||||||
if(curr.multipSelected){
|
|
||||||
result.push(curr)
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var i=0 ; i<curr.items.count ; i++){
|
|
||||||
stack.push(curr.items.get(i));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
function createItem(text="",expanded=true,items=[],data={}){
|
|
||||||
return {text:text,expanded:expanded,items:items,key:uniqueRandom(),multipSelected:false,multipIndex:0,multipParentKey:"",data:data};
|
|
||||||
}
|
}
|
||||||
function uniqueRandom() {
|
|
||||||
var timestamp = Date.now();
|
|
||||||
var random = Math.floor(Math.random() * 1000000);
|
|
||||||
return timestamp.toString() + random.toString();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function count(){
|
||||||
|
return table_model.rowCount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,4 +96,5 @@ FluRangeSlider 1.0 Controls/FluRangeSlider.qml
|
|||||||
FluStaggeredView 1.0 Controls/FluStaggeredView.qml
|
FluStaggeredView 1.0 Controls/FluStaggeredView.qml
|
||||||
FluProgressButton 1.0 Controls/FluProgressButton.qml
|
FluProgressButton 1.0 Controls/FluProgressButton.qml
|
||||||
FluLoadingButton 1.0 Controls/FluLoadingButton.qml
|
FluLoadingButton 1.0 Controls/FluLoadingButton.qml
|
||||||
|
FluTreeItem 1.0 Controls/FluTreeItem.qml
|
||||||
plugin fluentuiplugin
|
plugin fluentuiplugin
|
||||||
|
@ -96,5 +96,6 @@
|
|||||||
<file>FluentUI/Controls/ColorPicker/Content/PanelBorder.qml</file>
|
<file>FluentUI/Controls/ColorPicker/Content/PanelBorder.qml</file>
|
||||||
<file>FluentUI/Controls/ColorPicker/Content/SBPicker.qml</file>
|
<file>FluentUI/Controls/ColorPicker/Content/SBPicker.qml</file>
|
||||||
<file>FluentUI/Controls/FluLoadingButton.qml</file>
|
<file>FluentUI/Controls/FluLoadingButton.qml</file>
|
||||||
|
<file>FluentUI/Controls/FluTreeItem.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -21,6 +21,7 @@ T.ScrollBar {
|
|||||||
property int minLine : 2
|
property int minLine : 2
|
||||||
property int maxLine : 6
|
property int maxLine : 6
|
||||||
}
|
}
|
||||||
|
z: horizontal? 10 : 20
|
||||||
verticalPadding : vertical ? 15 : 3
|
verticalPadding : vertical ? 15 : 3
|
||||||
horizontalPadding : horizontal ? 15 : 3
|
horizontalPadding : horizontal ? 15 : 3
|
||||||
background: Rectangle{
|
background: Rectangle{
|
||||||
|
@ -7,4 +7,15 @@ QtObject {
|
|||||||
property int depth: 0
|
property int depth: 0
|
||||||
property bool isExpanded: true
|
property bool isExpanded: true
|
||||||
property var __parent
|
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
|
||||||
}
|
}
|
||||||
|
@ -2,291 +2,146 @@ import QtQuick
|
|||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import Qt.labs.qmlmodels
|
||||||
import FluentUI
|
import FluentUI
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property int selectionMode: FluTreeViewType.None
|
property var dataSource
|
||||||
property var currentElement
|
id:control
|
||||||
property var currentParentElement
|
QtObject {
|
||||||
property var rootModel: tree_model.get(0).items
|
id:d
|
||||||
signal itemClicked(var item)
|
signal refreshLayout()
|
||||||
id:root
|
onRefreshLayout: {
|
||||||
ListModel{
|
table_view.forceLayout()
|
||||||
id:tree_model
|
|
||||||
ListElement{
|
|
||||||
text: "根节点"
|
|
||||||
expanded:true
|
|
||||||
items:[]
|
|
||||||
key:"123456"
|
|
||||||
multipSelected:false
|
|
||||||
multipIndex:0
|
|
||||||
multipParentKey:""
|
|
||||||
}
|
}
|
||||||
}
|
function handleTree(treeData) {
|
||||||
Component{
|
var comItem = Qt.createComponent("FluTreeItem.qml");
|
||||||
id: delegate_root
|
if (comItem.status !== Component.Ready) {
|
||||||
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: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;
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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
|
|
||||||
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<curr.items.count ; i++){
|
|
||||||
curr.items.setProperty(i,"multipIndex",i)
|
|
||||||
curr.items.setProperty(i,"multipParentKey",curr.key)
|
|
||||||
stack.push(curr.items.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(var j=0 ; j<result.length-1 ; j++){
|
|
||||||
var item = result[j]
|
|
||||||
let obj = result.find(function(o) {
|
|
||||||
return o.key === item.multipParentKey;
|
|
||||||
});
|
|
||||||
if((item.items !== undefined) && (item.items.count !== 0)){
|
|
||||||
var items = item.items
|
|
||||||
for(var k=0 ; k<items.count ; k++){
|
|
||||||
if(items.get(k).multipSelected === false){
|
|
||||||
obj.items.setProperty(item.multipIndex,"multipSelected",false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
obj.items.setProperty(item.multipIndex,"multipSelected",true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clickListener:function(){
|
|
||||||
if(hasChild){
|
|
||||||
const stack = [itemModel];
|
|
||||||
while (stack.length > 0) {
|
|
||||||
const curr = stack.pop();
|
|
||||||
if (curr.items) {
|
|
||||||
for(var i=0 ; i<curr.items.count ; i++){
|
|
||||||
curr.items.setProperty(i,"multipSelected",!itemModel.multipSelected)
|
|
||||||
stack.push(curr.items.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refreshCheckBox()
|
|
||||||
}else{
|
|
||||||
itemModel.multipSelected = !itemModel.multipSelected
|
|
||||||
refreshCheckBox()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FluIconButton{
|
|
||||||
id:item_layout_expanded
|
|
||||||
color:"#00000000"
|
|
||||||
opacity: item_layout.hasChild
|
|
||||||
onClicked: {
|
|
||||||
if(!item_layout.hasChild){
|
|
||||||
item_layout_rect.onClickItem()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
model.expanded = !model.expanded
|
var stack = []
|
||||||
|
var rawData = []
|
||||||
|
for (var item of treeData) {
|
||||||
|
stack.push({node:item,depth:0,isExpanded:true,__parent:undefined})
|
||||||
}
|
}
|
||||||
contentItem: FluIcon{
|
stack = stack.reverse()
|
||||||
rotation: item_layout.expanded?0:-90
|
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 rawData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
iconSource:FluentIcons.ChevronDown
|
||||||
iconSize: 15
|
iconSize: 15
|
||||||
Behavior on rotation {
|
Layout.alignment: Qt.AlignVCenter
|
||||||
enabled: FluTheme.enableAnimation
|
opacity: {
|
||||||
NumberAnimation{
|
if(display.children){
|
||||||
duration: 167
|
return true
|
||||||
easing.type: Easing.OutCubic
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
MouseArea{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
display.isExpanded = !display.isExpanded
|
||||||
|
d.refreshLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FluText {
|
FluText {
|
||||||
text: item_layout.text
|
id:item_text
|
||||||
Layout.alignment: Qt.AlignVCenter
|
text: display.title
|
||||||
topPadding: 7
|
anchors.centerIn: parent
|
||||||
bottomPadding: 7
|
|
||||||
}
|
}
|
||||||
}
|
MouseArea{
|
||||||
}
|
|
||||||
Item{
|
|
||||||
id:item_sub
|
|
||||||
visible: {
|
|
||||||
if(!hasChild){
|
|
||||||
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
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
delegate: delegate_root
|
onClicked: {
|
||||||
contentWidth: contentItem.childrenRect.width
|
d.refreshLayout()
|
||||||
model: tree_model
|
|
||||||
flickableDirection: Flickable.HorizontalAndVerticalFlick
|
|
||||||
clip: true
|
|
||||||
boundsBehavior: ListView.StopAtBounds
|
|
||||||
ScrollBar.vertical: FluScrollBar {}
|
|
||||||
ScrollBar.horizontal: FluScrollBar { }
|
|
||||||
}
|
|
||||||
function updateData(items){
|
|
||||||
rootModel.clear()
|
|
||||||
rootModel.append(items)
|
|
||||||
}
|
|
||||||
function signleData(){
|
|
||||||
return currentElement
|
|
||||||
}
|
|
||||||
function multipData(){
|
|
||||||
const stack = [tree_model.get(0)];
|
|
||||||
const result = [];
|
|
||||||
while (stack.length > 0) {
|
|
||||||
const curr = stack.pop();
|
|
||||||
if(curr.multipSelected){
|
|
||||||
result.push(curr)
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var i=0 ; i<curr.items.count ; i++){
|
|
||||||
stack.push(curr.items.get(i));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
function createItem(text="",expanded=true,items=[],data={}){
|
|
||||||
return {text:text,expanded:expanded,items:items,key:uniqueRandom(),multipSelected:false,multipIndex:0,multipParentKey:"",data:data};
|
|
||||||
}
|
}
|
||||||
function uniqueRandom() {
|
|
||||||
var timestamp = Date.now();
|
|
||||||
var random = Math.floor(Math.random() * 1000000);
|
|
||||||
return timestamp.toString() + random.toString();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function count(){
|
||||||
|
return table_model.rowCount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,144 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Window
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
|
||||||
import Qt.labs.qmlmodels
|
|
||||||
import FluentUI
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color:"#33000000"
|
|
||||||
property var dataSource
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
function iterateTree(treeData) {
|
|
||||||
var comItem = Qt.createComponent("FluTreeItem.qml");
|
|
||||||
if (comItem.status !== Component.Ready) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const stack = [{ node: treeData[0], depth: 0 , isExpanded: true, __parent: undefined}];
|
|
||||||
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
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user