qml自定义Combobox

qml自定义具有二级菜单的Combobox

  • qml自定义具有二级菜单的Combobox
  • 废话
  • 先来看看效果
  • 设计思路
  • 上代码

废话

由于项目需要计划做个多级菜单,后来因为项目的特殊性放弃了这种多级菜单,但是觉得这种菜单应该挺有意思,所以在闲暇时候还是做了一个具有二级菜单的Combobox。

先来看看效果

-☞表示具有有子菜单

设计思路

其实比较简单!界面效果是一个文本框和一张图片组合,加两个列表菜单组成的,具体代码中可以很清楚看到,Combobox中数据是通过ListModel填充。

上代码

控件是由纯qml完成的不涉及c++,控件部分总共用了两个qml文件(一个文件也可以,无关紧要),还有一个是main.qml是调用控件的.
ComboBoxButton.qml:

import QtQuick 2.2

FocusScope {
    id: container
    signal clicked
    property alias source: image.source
    property alias text: label.text
    property color textColor: "white"
    property color borderColor: "limegreen"
    property color backgroundColor: "transparent"
    property int borderWidth: 2
    property int textSize: 12
    property int radius: 5
    property int margin: 0

    Rectangle {
        id: buttonRectangle
        anchors.fill: parent
        color: container.backgroundColor
        radius: container.radius
        border{width: container.borderWidth; color: container.borderColor;}

        Image {
            id: image
            smooth: true
            fillMode: Image.PreserveAspectFit
            anchors{top: parent.top; right: parent.right; margins: container.margin;}
            width: parent.height; height: parent.height-2*container.margin
        }

        Item {
            anchors{top: parent.top; bottom: parent.bottom; left: parent.left; right: image.left; leftMargin: container.margin * 2;}
            Text {
                id: label
                color: container.textColor
                anchors.centerIn: parent
                font{pixelSize: container.textSize-5; bold: true;}
            }
        }

        MouseArea {
            id: mouseArea;
            anchors.fill: parent
            onClicked: {
                buttonRectangle.state = "pressed"
                container.clicked()
            }
        }

        states: State {
            name: "pressed"
            PropertyChanges { target: image; scale: 0.7 }
        }

        transitions: Transition {
            NumberAnimation { properties: "scale"; duration: 200; easing.type: Easing.InOutQuad }
        }
    }
}

Mycombobox.qml:

import QtQuick 2.2

FocusScope {
    id: comboBox
    property int maxHeight: 1000
    property alias currentIndex: listView.currentIndex
    property alias currentIndex2: delegatelistview.currentIndex
    property alias buttonTextSize: comboBoxButton.textSize
    property alias text: comboBoxButton.text
    property bool readOnly: false
    property variant listModel
    property int beforeDropIndex:0
    property int beforeDropIndex2: 0
    property color textColor: "white"
    property color borderColor: "olivedrab"
    property color backgroundColor: "#FF00688A"
    property color focus_borderColor: "lightsalmon"
    property color focus_backgroundColor: "#FF00688A"
    property color focus_textColor: "darkred"
    signal comboBoxSelected(int idx,int index)
    signal comboBoxTextChanged(string comboxtext)
    width: 160; height: 32
    z: listBackground.height===0 ? 0 : 100

    ComboBoxButton {
        id: comboBoxButton
        anchors.fill: parent;
        source: "ico/down.png"
        text: typeof(listModel) == "undefined"? "":typeof( listModel.get(currentIndex).attributes)=="undefined"?listModel.get(comboBox.currentIndex).name:listModel.get(currentIndex).attributes.get(currentIndex2).description
        textSize: parent.height-4
        textColor: comboBox.activeFocus ? comboBox.focus_textColor : comboBox.textColor
        borderColor: comboBox.activeFocus ? comboBox.focus_borderColor : comboBox.borderColor
        backgroundColor: comboBox.activeFocus ? comboBox.focus_backgroundColor : comboBox.backgroundColor
        onClicked: comboxClick()
    }
    Component {
        id: comboBoxDelegate
        Item {
            id:comitem
            width: parent.width; height: comboBoxButton.height;
            Text {
                id:comtext
                color: index == listView.currentIndex ? "#ffff00" : "white"
                anchors.centerIn: parent
                font{pixelSize: comboBoxButton.textSize-5; bold: true;}
                text:name          }
            Text{
                id:icotext
                color:"white"
                text:typeof(listModel.get(index).attributes) == "undefined"?"":"☞";
                font{pixelSize: comboBoxButton.textSize-5; bold: true;}
                anchors{top:parent.top;right: parent.right}
                verticalAlignment: TextInput.AlignVCenter
            }
            MouseArea {
                anchors.fill: parent
                onClicked: comboBox.comboxSelect(index);
            }
            onFocusChanged: {delegatelistview.visible=true;}
        }


    }
    Component {
        id: delegate
        Item {
            width: parent.width; height: comboBoxButton.height;
            Text {
                id:comtext
                color:"white"
                anchors.centerIn: parent
                font{pixelSize: comboBoxButton.textSize-5; bold: true;}
                text:description;
            }
            MouseArea {
                anchors.fill: parent
                onClicked: comboBox.comboxSelect2(index);
            }
            onFocusChanged: {delegatelistview.visible=true;}
            Keys.onPressed:
            {
                if(event.key===Qt.Key_Enter||event.key===Qt.Key_Return)
                {
                    comboBox.comboxClick();
                }
            }

        }

    }

    Rectangle{
        id:delegateback
        x:listView.x+listView.width
        y:listBackground.y+listView.currentIndex*listView.highlightItem.height
        color:"#FF000000"
        radius: comboBoxButton.radius
        visible: false
        border{width: comboBoxButton.borderWidth; color: comboBoxButton.borderColor;}
        ListView
        {
            id:delegatelistview
            anchors.fill: parent
            visible:false
            clip:true
            delegate: delegate
            keyNavigationWraps :true
            highlight: Rectangle{color: delegatelistview.focus?"#FF00688A":"transparent"; radius: 5;}
        }
        Behavior on height {
            NumberAnimation {property: "height"; duration: 200 }
        }
        state: "Hide"
        states: [
            State {
                name: "Hide"
                PropertyChanges {target: delegateback; visible:false;height:0;width:0}
                StateChangeScript{
                    script: {
                        delegatelistview.focus=false
                    }
                }
            },
            State {
                name: "Show"
                PropertyChanges {target: delegateback;visible:typeof(delegatelistview.model) == "undefined"?false:true; focus: false;height: Math.min(maxHeight, typeof(delegatelistview.model) == "undefined"?0:delegatelistview.model.count*comboBoxButton.height);width:comboBoxButton.width}
                StateChangeScript{
                    script: {
                    }
                }
            }
        ]
    }
    ListModel{id:model}
    Rectangle {
        id: listBackground
        anchors{top: comboBoxButton.bottom; left: comboBoxButton.left;}
        width: parent.width
        color: "#FF000000"
        radius: comboBoxButton.radius
        border{width: comboBoxButton.borderWidth; color: comboBoxButton.borderColor;}
        ListView {
            id: listView
            anchors.fill: parent
            clip: true
            focus:true
            model:listModel
            delegate: comboBoxDelegate
            highlight: Rectangle{color:"#FF00688A"; radius: 5;}
            onCurrentIndexChanged: {delegatelistview.model=listModel.get(currentIndex).attributes;}
        }

        Behavior on height {
            NumberAnimation {property: "height"; duration: 200 }
        }
    }
    function comboxSelect2(index)
    {
        currentIndex2=index
        console.log(index)
        state="Close"
    }
    function comboxSelect(index){
        currentIndex = index
        state = "Close"
    }
    function comboxClick(){
        if(readOnly) return
        forceActiveFocus()
        if (state == "Close"){
            state = "Drop"
            delegatelistview.model=listModel.get(currentIndex).attributes
        }
        else{
            state = "Close"
            delegateback.state="Hide"
        }
    }
    onActiveFocusChanged: { if(!activeFocus) state = "Close" }
    onStateChanged: {if(state=="Close")delegateback.state="Hide"}
    state: "Close"
    states: [
        State {
            name: "Close"
            PropertyChanges {target: listBackground; height: 0}
            StateChangeScript{
                script: {
                    if(currentIndex===beforeDropIndex&¤tIndex2===beforeDropIndex2)
                        return
                    comboBoxSelected(currentIndex,currentIndex2)
                    comboBoxTextChanged(text)
                    delegateback.state="Hide"
                }
            }
        },
        State {
            name: "Drop"
            PropertyChanges {target: listBackground; height: Math.min(maxHeight, listModel.count*comboBoxButton.height); focus: true}
            StateChangeScript{
                script: {
                    beforeDropIndex = currentIndex
                    beforeDropIndex2=currentIndex2
                    delegateback.state="Show"
                }
            }
        }
    ]


    Keys.onUpPressed: {
        if(state == "Drop"){ listView.decrementCurrentIndex(); return}
        event.accepted = false
    }
    Keys.onDownPressed: {
        if(state == "Drop"){ listView.incrementCurrentIndex(); return}
        event.accepted = false
    }
    Keys.onReturnPressed: {
        if(typeof(delegatelistview.model) == "undefined")
        {
            comboxClick();
            return}
        listView.focus=false;
        delegatelistview.forceActiveFocus();
        event.accepted = false
    }
    Keys.onEnterPressed: {
        if(typeof(delegatelistview.model) == "undefined")
        {
            comboxClick();
            return}
        listView.focus=false;
        delegatelistview.forceActiveFocus();
        event.accepted = false}
    Keys.onRightPressed: {if(typeof(delegatelistview.model) == "undefined")return;listView.focus=false;delegatelistview.forceActiveFocus();event.accepted = false}
    Keys.onLeftPressed: {if(delegatelistview.focus)listView.forceActiveFocus();event.accepted = false;}
    Keys.onPressed: {
        if(event.key === Qt.Key_Escape){
            if(state !== "Close"){
                state = "Close"
                event.accepted = true
            }
        }
    }
}

main.qml:

import QtQuick 2.3
import QtQuick.Window 2.2
import "./"
Window {
    visible: true

    MouseArea {
        anchors.fill: parent
        onClicked: {
           // Qt.quit();
        }
    }
    Mycombobox{listModel: fruitModel;anchors.centerIn: parent}
    ListModel {
        id: fruitModel

        ListElement {
            name: "Apple"
            attributes: [
                ListElement { description: "Core" },
                ListElement { description: "Deciduous" }
            ]
        }
        ListElement {
            name: "Orange"
            attributes: [
                ListElement { description: "Citrus" }
            ]
        }
        ListElement {
            name: "mango"
        }
        ListElement {
            name: "Banana"
            attributes: [
                ListElement { description: "Tropical" },
                ListElement { description: "Seedless" },
                ListElement { description: "Yellow" }
            ]
        }

    }
}


你可能感兴趣的:(qml,combobox,qml,二级菜单,自定义控件)