diff --git a/example/qml-Qt6/page/T_TreeView.qml b/example/qml-Qt6/page/T_TreeView.qml index 646827d1..d49f796b 100644 --- a/example/qml-Qt6/page/T_TreeView.qml +++ b/example/qml-Qt6/page/T_TreeView.qml @@ -5,7 +5,7 @@ import QtQuick.Controls import FluentUI import "qrc:///example/qml/component" -FluScrollablePage { +FluContentPage { title:"TreeView" @@ -28,105 +28,94 @@ FluScrollablePage { return dig(); } - FluArea{ - Layout.fillWidth: true - Layout.topMargin: 10 - paddings: 10 - height: 80 - Column{ - anchors.verticalCenter: parent.verticalCenter + Column{ + id:layout_column + spacing: 12 + width: 300 + anchors{ + topMargin: 20 + top:parent.top + left: parent.left + leftMargin: 10 + bottom:parent.bottom + bottomMargin: 20 + } + + FluText{ + text:"共计%1条数据,当前显示的%2条数据".arg(tree_view.count()).arg(tree_view.visibleCount()) + } + + RowLayout{ spacing: 10 FluText{ - text:"高性能树控件,新的TreeView用TableView实现!!" + text:"cellHeight:" + Layout.alignment: Qt.AlignVCenter } + FluSlider{ + id:slider_cell_height + value: 30 + from: 30 + to:100 + } + } + RowLayout{ + spacing: 10 FluText{ - text:"共计:%1条数据,当前显示的%2条数据".arg(tree_view.count()).arg(tree_view.visibleCount()) + text:"depthPadding:" + Layout.alignment: Qt.AlignVCenter + } + FluSlider{ + id:slider_depth_padding + value: 30 + from: 30 + to:100 + } + } + FluToggleSwitch{ + id:switch_showline + text:"showLine" + checked: true + } + FluToggleSwitch{ + id:switch_draggable + text:"draggable" + checked: true + } + FluButton{ + text:"all expand" + onClicked: { + tree_view.allExpand() + } + } + FluButton{ + text:"all collapse" + onClicked: { + tree_view.allCollapse() } } } FluArea{ - Layout.fillWidth: true - Layout.topMargin: 10 - paddings: 10 - height: 420 - Item{ - anchors.fill: tree_view - FluShadow{} + anchors{ + left: layout_column.right + top: parent.top + bottom: parent.bottom + right: parent.right + rightMargin: 5 + topMargin: 5 + bottomMargin: 5 } + FluShadow{} FluTreeView{ id:tree_view - width:slider_width.value - anchors{ - top:parent.top - left:parent.left - bottom:parent.bottom - } + anchors.fill: parent + cellHeight: slider_cell_height.value draggable:switch_draggable.checked showLine: switch_showline.checked + depthPadding: slider_depth_padding.value Component.onCompleted: { var data = treeData() dataSource = data } } - Column{ - spacing: 15 - anchors{ - top:parent.top - topMargin: 10 - bottomMargin: 10 - rightMargin: 10 - bottom:parent.bottom - right: parent.right - } - RowLayout{ - spacing: 10 - FluText{ - text:"width:" - Layout.alignment: Qt.AlignVCenter - } - FluSlider{ - id:slider_width - value: 280 - from: 160 - to:400 - } - } - FluToggleSwitch{ - id:switch_showline - text:"showLine" - checked: true - } - FluToggleSwitch{ - id:switch_draggable - text:"draggable" - checked: true - } - FluButton{ - text:"all expand" - onClicked: { - tree_view.allExpand() - } - } - FluButton{ - text:"all collapse" - onClicked: { - tree_view.allCollapse() - } - } - } - } - CodeExpander{ - Layout.fillWidth: true - Layout.topMargin: -1 - code:'FluTreeView{ - id:tree_view - width:240 - height:600 - Component.onCompleted: { - var data = treeData() - dataSource = data - } -} -' } } diff --git a/example/qml-Qt6/window/MainWindow.qml b/example/qml-Qt6/window/MainWindow.qml index d264fb99..dcd53be3 100644 --- a/example/qml-Qt6/window/MainWindow.qml +++ b/example/qml-Qt6/window/MainWindow.qml @@ -183,7 +183,7 @@ CustomWindow { z:999 //Stack模式,每次切换都会将页面压入栈中,随着栈的页面增多,消耗的内存也越多,内存消耗多就会卡顿,这时候就需要按返回将页面pop掉,释放内存。该模式可以配合FluPage中的launchMode属性,设置页面的启动模式 // pageMode: FluNavigationViewType.Stack - //NoStack模式,每次切换都会销毁之前的页面然后创建一个新的页面,只需消耗少量内存(推荐) + //NoStack模式,每次切换都会销毁之前的页面然后创建一个新的页面,只需消耗少量内存,可以配合FluViewModel保存页面数据(推荐) pageMode: FluNavigationViewType.NoStack items: ItemsOriginal footerItems:ItemsFooter diff --git a/example/qml/page/T_TreeView.qml b/example/qml/page/T_TreeView.qml index 54206aff..2caa5f9f 100644 --- a/example/qml/page/T_TreeView.qml +++ b/example/qml/page/T_TreeView.qml @@ -6,7 +6,7 @@ import FluentUI 1.0 import "qrc:///example/qml/component" import "../component" -FluScrollablePage { +FluContentPage { title:"TreeView" @@ -29,105 +29,94 @@ FluScrollablePage { return dig(); } - FluArea{ - Layout.fillWidth: true - Layout.topMargin: 10 - paddings: 10 - height: 80 - Column{ - anchors.verticalCenter: parent.verticalCenter + Column{ + id:layout_column + spacing: 12 + width: 300 + anchors{ + topMargin: 20 + top:parent.top + left: parent.left + leftMargin: 10 + bottom:parent.bottom + bottomMargin: 20 + } + + FluText{ + text:"共计%1条数据,当前显示的%2条数据".arg(tree_view.count()).arg(tree_view.visibleCount()) + } + + RowLayout{ spacing: 10 FluText{ - text:"高性能树控件,新的TreeView用TableView实现!!" + text:"cellHeight:" + Layout.alignment: Qt.AlignVCenter } + FluSlider{ + id:slider_cell_height + value: 30 + from: 30 + to:100 + } + } + RowLayout{ + spacing: 10 FluText{ - text:"共计:%1条数据,当前显示的%2条数据".arg(tree_view.count()).arg(tree_view.visibleCount()) + text:"depthPadding:" + Layout.alignment: Qt.AlignVCenter + } + FluSlider{ + id:slider_depth_padding + value: 30 + from: 30 + to:100 + } + } + FluToggleSwitch{ + id:switch_showline + text:"showLine" + checked: true + } + FluToggleSwitch{ + id:switch_draggable + text:"draggable" + checked: true + } + FluButton{ + text:"all expand" + onClicked: { + tree_view.allExpand() + } + } + FluButton{ + text:"all collapse" + onClicked: { + tree_view.allCollapse() } } } FluArea{ - Layout.fillWidth: true - Layout.topMargin: 10 - paddings: 10 - height: 420 - Item{ - anchors.fill: tree_view - FluShadow{} + anchors{ + left: layout_column.right + top: parent.top + bottom: parent.bottom + right: parent.right + rightMargin: 5 + topMargin: 5 + bottomMargin: 5 } + FluShadow{} FluTreeView{ id:tree_view - width:slider_width.value - anchors{ - top:parent.top - left:parent.left - bottom:parent.bottom - } + anchors.fill: parent + cellHeight: slider_cell_height.value draggable:switch_draggable.checked showLine: switch_showline.checked + depthPadding: slider_depth_padding.value Component.onCompleted: { var data = treeData() dataSource = data } } - Column{ - spacing: 15 - anchors{ - top:parent.top - topMargin: 10 - bottomMargin: 10 - rightMargin: 10 - bottom:parent.bottom - right: parent.right - } - RowLayout{ - spacing: 10 - FluText{ - text:"width:" - Layout.alignment: Qt.AlignVCenter - } - FluSlider{ - id:slider_width - value: 280 - from: 160 - to:400 - } - } - FluToggleSwitch{ - id:switch_showline - text:"showLine" - checked: true - } - FluToggleSwitch{ - id:switch_draggable - text:"draggable" - checked: true - } - FluButton{ - text:"all expand" - onClicked: { - tree_view.allExpand() - } - } - FluButton{ - text:"all collapse" - onClicked: { - tree_view.allCollapse() - } - } - } - } - CodeExpander{ - Layout.fillWidth: true - Layout.topMargin: -1 - code:'FluTreeView{ - id:tree_view - width:240 - height:600 - Component.onCompleted: { - var data = treeData() - dataSource = data - } -} -' } } diff --git a/example/qml/window/MainWindow.qml b/example/qml/window/MainWindow.qml index 5b8d6f68..e5bee768 100644 --- a/example/qml/window/MainWindow.qml +++ b/example/qml/window/MainWindow.qml @@ -186,7 +186,7 @@ CustomWindow { z:999 //Stack模式,每次切换都会将页面压入栈中,随着栈的页面增多,消耗的内存也越多,内存消耗多就会卡顿,这时候就需要按返回将页面pop掉,释放内存。该模式可以配合FluPage中的launchMode属性,设置页面的启动模式 // pageMode: FluNavigationViewType.Stack - //NoStack模式,每次切换都会销毁之前的页面然后创建一个新的页面,只需消耗少量内存(推荐) + //NoStack模式,每次切换都会销毁之前的页面然后创建一个新的页面,只需消耗少量内存,可以配合FluViewModel保存页面数据(推荐) pageMode: FluNavigationViewType.NoStack items: ItemsOriginal footerItems:ItemsFooter diff --git a/src/FluHttp.cpp b/src/FluHttp.cpp index 1103c3bb..7065551e 100644 --- a/src/FluHttp.cpp +++ b/src/FluHttp.cpp @@ -119,7 +119,8 @@ void FluHttp::post(HttpRequest* r,HttpCallable* c){ QString result = QString::fromUtf8(reply->readAll()); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); - bool isSuccess = reply->error() == QNetworkReply::NoError; + QNetworkReply::NetworkError error = reply->error(); + bool isSuccess = error == QNetworkReply::NoError; reply->deleteLater(); reply = nullptr; if (isSuccess) { @@ -134,6 +135,9 @@ void FluHttp::post(HttpRequest* r,HttpCallable* c){ onError(callable,status,errorString,result); } } + if(error == QNetworkReply::OperationCanceledError){ + break; + } } onFinish(callable,request); }); @@ -174,7 +178,8 @@ void FluHttp::postString(HttpRequest* r,HttpCallable* c){ QString result = QString::fromUtf8(reply->readAll()); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); - bool isSuccess = reply->error() == QNetworkReply::NoError; + QNetworkReply::NetworkError error = reply->error(); + bool isSuccess = error == QNetworkReply::NoError; reply->deleteLater(); reply = nullptr; if (isSuccess) { @@ -189,6 +194,9 @@ void FluHttp::postString(HttpRequest* r,HttpCallable* c){ onError(callable,status,errorString,result); } } + if(error == QNetworkReply::OperationCanceledError){ + break; + } } onFinish(callable,request); }); @@ -228,7 +236,8 @@ void FluHttp::postJson(HttpRequest* r,HttpCallable* c){ QString result = QString::fromUtf8(reply->readAll()); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); - bool isSuccess = reply->error() == QNetworkReply::NoError; + QNetworkReply::NetworkError error = reply->error(); + bool isSuccess = error == QNetworkReply::NoError; reply->deleteLater(); reply = nullptr; if (isSuccess) { @@ -243,6 +252,9 @@ void FluHttp::postJson(HttpRequest* r,HttpCallable* c){ onError(callable,status,errorString,result); } } + if(error == QNetworkReply::OperationCanceledError){ + break; + } } onFinish(callable,request); }); @@ -273,14 +285,15 @@ void FluHttp::get(HttpRequest* r,HttpCallable* c){ QNetworkRequest req(url); addHeaders(&req,data["headers"].toMap()); QEventLoop loop; - QNetworkReply* reply = manager.get(req); + auto reply = QPointer(manager.get(req)); _cacheReply.append(reply); connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();}); connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();}); loop.exec(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); - bool isSuccess = reply->error() == QNetworkReply::NoError; + QNetworkReply::NetworkError error = reply->error(); + bool isSuccess = error == QNetworkReply::NoError; QString result = QString::fromUtf8(reply->readAll()); if (isSuccess) { handleCache(httpId,result); @@ -296,6 +309,9 @@ void FluHttp::get(HttpRequest* r,HttpCallable* c){ } reply->deleteLater(); reply = nullptr; + if(error == QNetworkReply::OperationCanceledError){ + break; + } } onFinish(callable,request); }); diff --git a/src/FluTreeModel.cpp b/src/FluTreeModel.cpp index 89ebc001..05fc9010 100644 --- a/src/FluTreeModel.cpp +++ b/src/FluTreeModel.cpp @@ -2,15 +2,10 @@ #include -Node::Node(QObject *parent) - : QObject{parent} -{ - +Node::Node(QObject *parent): QObject{parent}{ } -FluTreeModel::FluTreeModel(QObject *parent) - : QAbstractItemModel{parent} -{ +FluTreeModel::FluTreeModel(QObject *parent): QAbstractItemModel{parent}{ dataSourceSize(0); } @@ -209,7 +204,6 @@ void FluTreeModel::dragAnddrop(int dragIndex,int dropIndex,bool isDropTopArea){ } _rows.move(dragIndex,targetIndex); endMoveRows(); - Q_EMIT layoutAboutToBeChanged(); if(dragItem->_parent == dropItem->_parent){ QList* children = &(dragItem->_parent->_children); @@ -256,7 +250,6 @@ void FluTreeModel::dragAnddrop(int dragIndex,int dropIndex,bool isDropTopArea){ } } srcChildren->removeAt(srcIndex); - if(dropIndex > dragIndex){ if(isDropTopArea){ targetIndex = destIndex; @@ -270,26 +263,18 @@ void FluTreeModel::dragAnddrop(int dragIndex,int dropIndex,bool isDropTopArea){ targetIndex = destIndex + 1; } } - destChildren->insert(targetIndex,dragItem); - - foreach (auto item,*destChildren) { - qDebug()<title(); - } - } - changePersistentIndex(index(qMin(dragIndex,dropIndex),0),index(qMax(dragIndex,dropIndex),0)); - Q_EMIT layoutChanged(QList(),QAbstractItemModel::VerticalSortHint); } bool FluTreeModel::hitHasChildrenExpanded(int row){ - // auto itemData = _rows.at(row); - // if(itemData->hasChildren() && itemData->_isExpanded){ - // return true; - // } + auto itemData = _rows.at(row); + if(itemData->hasChildren() && itemData->_isExpanded){ + return true; + } return false; } diff --git a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml index 51fbad6d..b5b04611 100644 --- a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml +++ b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml @@ -10,6 +10,8 @@ Item { property var dataSource property bool showLine: true property bool draggable: false + property int cellHeight: 30 + property int depthPadding: 30 property color lineColor: FluTheme.dark ? Qt.rgba(111/255,111/255,111/255,1) : Qt.rgba(217/255,217/255,217/255,1) id:control QtObject { @@ -112,13 +114,13 @@ Item { property bool isCurrent: d.current === itemModel id:item_container width: { - var w = 46 + item_layout_text.width + 30*itemModel.depth + var w = 46 + item_loader_cell.width + control.depthPadding*itemModel.depth if(control.width>w){ return control.width } return w } - height: 30 + height: control.cellHeight implicitWidth: width implicitHeight: height function toggle(){ @@ -194,13 +196,13 @@ Item { var pos = FluTools.cursorPos() var viewPos = table_view.mapToGlobal(0,0) var y = table_view.contentY + pos.y-viewPos.y - var index = Math.floor(y/30) - if(tree_model.hitHasChildrenExpanded(index) && y>index*30+15){ + var index = Math.floor(y/control.cellHeight) + if(tree_model.hitHasChildrenExpanded(index) && y>index*control.cellHeight+control.cellHeight/2){ d.dropIndex = index + 1 d.isDropTopArea = true }else{ d.dropIndex = index - if(y>index*30+15){ + if(y>index*control.cellHeight+control.cellHeight/2){ d.isDropTopArea = false }else{ d.isDropTopArea = true @@ -229,14 +231,8 @@ Item { Rectangle{ id:item_line_drop_tip anchors{ - left: parent.left - leftMargin: { - var count = itemModel.depth+1 - if(itemModel.hasChildren()){ - return 30*count - 8 - } - return 30*count + 18 - } + left: layout_row.left + leftMargin: 26 right: parent.right rightMargin: 10 bottom: parent.bottom @@ -283,18 +279,18 @@ Item { height: itemModel.hideLineFooter() ? parent.height/2 : parent.height anchors{ top: parent.top - right: layout_row.left - rightMargin: -9 + left: item_line_h.left } } FluRectangle{ + id:item_line_h height: 1 color: control.lineColor visible: control.showLine && isItemLoader && itemModel.depth !== 0 && !itemModel.hasChildren() - width: 18 + width: depthPadding - 10 anchors{ right: layout_row.left - rightMargin: -27 + rightMargin: -24 verticalCenter: parent.verticalCenter } } @@ -309,7 +305,7 @@ Item { top:parent.top bottom: parent.bottom left: parent.left - leftMargin: 30*(index+2) - 8 + leftMargin: control.depthPadding*(index+1) + 24 } } } @@ -342,9 +338,10 @@ Item { } RowLayout{ id:layout_row + height: parent.height anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - anchors.leftMargin: 14 + 30*itemModel.depth + anchors.leftMargin: 14 + control.depthPadding*itemModel.depth Component{ id:com_icon_btn FluIconButton{ @@ -364,23 +361,38 @@ Item { Layout.preferredWidth: 20 Layout.preferredHeight: 20 sourceComponent: itemModel.hasChildren() ? com_icon_btn : undefined - } - Item{ - id:item_layout_text - Layout.preferredWidth: item_text.implicitWidth+14 - Layout.preferredHeight:item_text.implicitHeight+14 Layout.alignment: Qt.AlignVCenter - FluText { - id:item_text - text: itemModel.title - anchors.centerIn: parent - color:{ - if(item_mouse.pressed){ - return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120 - } - return FluTheme.dark ? FluColors.White : FluColors.Grey220 + } + Loader{ + property var modelData: itemModel + property var itemMouse: item_mouse + id:item_loader_cell + Layout.preferredWidth: { + if(item){ + return item.width } + return 0 } + Layout.fillHeight: true + sourceComponent:com_item_text + } + } + } + } + Component{ + id:com_item_text + Item{ + width: item_text.width + FluText { + id:item_text + text: modelData.title + rightPadding: 14 + anchors.centerIn: parent + color:{ + if(itemMouse.pressed){ + return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120 + } + return FluTheme.dark ? FluColors.White : FluColors.Grey220 } } } @@ -403,5 +415,4 @@ Item { function allCollapse(){ tree_model.allCollapse() } - } diff --git a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml index 3da6f21c..f783c5d1 100644 --- a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml +++ b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml @@ -10,6 +10,8 @@ Item { property var dataSource property bool showLine: true property bool draggable: false + property int cellHeight: 30 + property int depthPadding: 30 property color lineColor: FluTheme.dark ? Qt.rgba(111/255,111/255,111/255,1) : Qt.rgba(217/255,217/255,217/255,1) id:control QtObject { @@ -112,13 +114,13 @@ Item { property bool isCurrent: d.current === itemModel id:item_container width: { - var w = 46 + item_layout_text.width + 30*itemModel.depth + var w = 46 + item_loader_cell.width + control.depthPadding*itemModel.depth if(control.width>w){ return control.width } return w } - height: 30 + height: control.cellHeight implicitWidth: width implicitHeight: height function toggle(){ @@ -194,13 +196,13 @@ Item { var pos = FluTools.cursorPos() var viewPos = table_view.mapToGlobal(0,0) var y = table_view.contentY + pos.y-viewPos.y - var index = Math.floor(y/30) - if(tree_model.hitHasChildrenExpanded(index) && y>index*30+15){ + var index = Math.floor(y/control.cellHeight) + if(tree_model.hitHasChildrenExpanded(index) && y>index*control.cellHeight+control.cellHeight/2){ d.dropIndex = index + 1 d.isDropTopArea = true }else{ d.dropIndex = index - if(y>index*30+15){ + if(y>index*control.cellHeight+control.cellHeight/2){ d.isDropTopArea = false }else{ d.isDropTopArea = true @@ -229,14 +231,8 @@ Item { Rectangle{ id:item_line_drop_tip anchors{ - left: parent.left - leftMargin: { - var count = itemModel.depth+1 - if(itemModel.hasChildren()){ - return 30*count - 8 - } - return 30*count + 18 - } + left: layout_row.left + leftMargin: 26 right: parent.right rightMargin: 10 bottom: parent.bottom @@ -283,18 +279,18 @@ Item { height: itemModel.hideLineFooter() ? parent.height/2 : parent.height anchors{ top: parent.top - right: layout_row.left - rightMargin: -9 + left: item_line_h.left } } FluRectangle{ + id:item_line_h height: 1 color: control.lineColor visible: control.showLine && isItemLoader && itemModel.depth !== 0 && !itemModel.hasChildren() - width: 18 + width: depthPadding - 10 anchors{ right: layout_row.left - rightMargin: -27 + rightMargin: -24 verticalCenter: parent.verticalCenter } } @@ -309,7 +305,7 @@ Item { top:parent.top bottom: parent.bottom left: parent.left - leftMargin: 30*(index+2) - 8 + leftMargin: control.depthPadding*(index+1) + 24 } } } @@ -342,9 +338,10 @@ Item { } RowLayout{ id:layout_row + height: parent.height anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - anchors.leftMargin: 14 + 30*itemModel.depth + anchors.leftMargin: 14 + control.depthPadding*itemModel.depth Component{ id:com_icon_btn FluIconButton{ @@ -364,23 +361,38 @@ Item { Layout.preferredWidth: 20 Layout.preferredHeight: 20 sourceComponent: itemModel.hasChildren() ? com_icon_btn : undefined - } - Item{ - id:item_layout_text - Layout.preferredWidth: item_text.implicitWidth+14 - Layout.preferredHeight:item_text.implicitHeight+14 Layout.alignment: Qt.AlignVCenter - FluText { - id:item_text - text: itemModel.title - anchors.centerIn: parent - color:{ - if(item_mouse.pressed){ - return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120 - } - return FluTheme.dark ? FluColors.White : FluColors.Grey220 + } + Loader{ + property var modelData: itemModel + property var itemMouse: item_mouse + id:item_loader_cell + Layout.preferredWidth: { + if(item){ + return item.width } + return 0 } + Layout.fillHeight: true + sourceComponent:com_item_text + } + } + } + } + Component{ + id:com_item_text + Item{ + width: item_text.width + FluText { + id:item_text + text: modelData.title + rightPadding: 14 + anchors.centerIn: parent + color:{ + if(itemMouse.pressed){ + return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120 + } + return FluTheme.dark ? FluColors.White : FluColors.Grey220 } } } @@ -403,5 +415,4 @@ Item { function allCollapse(){ tree_model.allCollapse() } - }