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