29. QML实现抽屉式选项窗口
1. 说明
最近使用Unity中的可视化编程组件Visual Scripting时,发现在组件设计窗口的鼠标右键菜单项效果很好,在有限的区域内能够展示很多内容,所以突发奇想使用QML语言自己大致实现了一下,效果还行,特记录在此,方便以后使用。
Unity本身效果:
unity中的右键菜单窗口
自己实现的效果:
类似抽屉式窗口设计
2. 实现思路
在内容呈现上是使用ListView空间展示每一个页面中的内容,页面切换是利用动态加载的方式创建每一个子页面,并使用动画过渡达到页面切换时的位移效果。
使用这种方式,理论上可以在页面中无限制的进行嵌套。
2.1 主要代码如下:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")color: Qt.rgba(0,0,0,0.4)property QtObject childObjRectangle{id:containerwidth: 200height: 400anchors.centerIn: parentcolor:"#202020"clip:trueRectangle{id:titleRecwidth: parent.widthheight: 20color: /*"#3C3C3C"*/Qt.rgba(0,0,0,0)Text{id:titleTxtanchors.horizontalCenter: parent.horizontalCenteranchors.verticalCenter: parent.verticalCentertext: "Node"color: "white"}Text{id:rtnTxtanchors.verticalCenter: parent.verticalCenteranchors.left: parent.leftanchors.leftMargin: 10text: "<"color: "white"visible: titleTxt.text == "Node" ? false : trueMouseArea{anchors.fill: parentonClicked: {childObj.animout.start()childObj = nulltitleTxt.text = "Node"}}}}ListView{id:viewwidth: parent.widthanchors.horizontalCenter: parent.horizontalCenteranchors.top: titleRec.bottomanchors.topMargin: 5anchors.bottom: parent.bottomanchors.bottomMargin: 5spacing: 10highlight:Rectangle{anchors.horizontalCenter: parent.horizontalCenterwidth: parent.width * 0.9height: 30color: "#3E5F96"}highlightFollowsCurrentItem: truehighlightMoveDuration: 1focus:truemodel:ListModel{ListElement {name: "ScriptMachine"}ListElement {name: "Codebase"}ListElement {name: "Collections"}ListElement {name: "Contorl"}ListElement {name: "Events"}ListElement {name: "Graphs"}}delegate: Rectangle{id:viewdelanchors.horizontalCenter: parent.horizontalCenterwidth: parent.width * 0.9height: 30color: /*"#3C3C3C"*/Qt.rgba(0,0,0,0)Text{id:curLayerNameanchors.verticalCenter: parent.verticalCenteranchors.left: parent.leftanchors.leftMargin: 10text:namecolor: "white"}Text{id:curLayerIndicatoranchors.verticalCenter: parent.verticalCenteranchors.right: parent.rightanchors.rightMargin: 10text:">"color: "white"}MouseArea{id:curLayerMouseanchors.fill: parenthoverEnabled: trueonEntered: {view.currentIndex = index}onClicked: {switch(curLayerName.text){case ("ScriptMachine"):titleTxt.text = curLayerName.textvar SM = Qt.createComponent("qrc:/ScriptMachine.qml")//针对不同的选项,创建不同的页面childObj = SM.createObject(viewdel.parent.parent)breakcase ("Codebase"):titleTxt.text = curLayerName.textvar CB = Qt.createComponent("qrc:/CodeBase.qml")childObj = CB.createObject(viewdel.parent.parent)break}}}}}}}
上面的代码是主页面的,对于子页面也可以利用这种方式去创建自己的子页面,从而实现无限制的嵌套,不过要注意页面的切换逻辑不要搞混乱了。在上面代码中有个switch … case结构用于选择创建的子页面,这里只弄了两个,在每个子页面中需要设置一个动画,用于控制子页面的进入和退出,子页面的大致代码如下:
ScriptMachine.qml
import QtQuick 2.15Rectangle {id:rootwidth: parent.widthheight: parent.heightcolor: "#202020"property alias animout:animOutListView{id:viewwidth: parent.widthanchors.horizontalCenter: parent.horizontalCenteranchors.top: root.topanchors.topMargin: 5anchors.bottom: parent.bottomanchors.bottomMargin: 5spacing: 10highlight:Rectangle{anchors.horizontalCenter: parent.horizontalCenterwidth: parent.width * 0.9height: 30color: "#3E5F96"}highlightFollowsCurrentItem: truehighlightMoveDuration: 1focus:truemodel:ListModel{ListElement {name: "Game Object"}ListElement {name: "Transform"}}delegate: Rectangle{id:viewdelanchors.horizontalCenter: parent.horizontalCenterwidth: parent.width * 0.9height: 30color: /*"#3C3C3C"*/Qt.rgba(0,0,0,0)Text{id:curLayerNameanchors.verticalCenter: parent.verticalCenteranchors.left: parent.leftanchors.leftMargin: 10text:namecolor: "white"}Text{id:curLayerIndicatoranchors.verticalCenter: parent.verticalCenteranchors.right: parent.rightanchors.rightMargin: 10text:">"color: "white"}MouseArea{id:curLayerMouseanchors.fill: parenthoverEnabled: trueonEntered: {view.currentIndex = index}onClicked: {//这里可以使用switch...case结构创建子页面的子页面进行嵌套switch(curLayerName.text){case (""):break}}}}}//下面的动画用于控制当前页面的进入和退出效果NumberAnimation {id: animInrunning: falsetarget: rootproperty: "x"from:root.parent.width;to:root.parent.xduration: 200;easing.type: Easing.InOutQuad}NumberAnimation {id: animOutrunning: falsetarget: rootproperty: "x"from:root.parent.xto:root.parent.widthduration: 200;easing.type: Easing.InOutQuadonStopped: {root.destroy()//撤销动画执行完毕后销毁页面,防止占用内存}}Component.onCompleted: {animIn.start()}
}
整体代码已上传到gitee仓库中,需要的可以自行下载:
抽屉式窗口页面gitee仓库地址