Qml实现自定义右键菜单

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/r5014/article/details/73770869

先上效果图吧:




在正式开始之前大致阐述一下思路:

结构,对于每一个菜单而言,其实就是一个菜单项的列表。而每一个菜单项都可以包含自己的子菜单项。


所以用可以这样简单的描述一个菜单:

typdef struct _item_s

{

QString text

QList<_item_s*> subItem

}Item;


typedef struct

{

QList<Item> items;

}Menu;


接下来开始设计Qml界面代码(即菜单代码)

这里主要是用一个Window和一个ListView作为主要部分,每个菜单对应一个model。

使用了递归的方式,也就是subItem 其实也就是个Menu,

具体看如下代码:


import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4

Window
{
    id                            : popPage
    flags                         : Qt.FramelessWindowHint | Qt.WindowActive  | Qt.Popup | Qt.WindowStaysOnTopHint
    modality                      : Qt.WindowModal
    visible                       : false
    width                         : itemWidth
    height                        : itemHeight * listView.count + 10
    property var itemModel        : null                                        //数据,可以使用JSValue或JSON或QStandardItemModel或ListModel等等
    property int itemHeight       : 25
    property int itemWidth        : 100
    property int _itemCount       : listView.count
    property var _lastPopupItem   : null                                        //弹出的子菜单  (如果没有子菜单弹出过,则为null)
    property var _parentPopupItem : null                                        //自己的父菜单项(当自己是子菜单时有效,其他情况是null)

    onActiveChanged:
    {
       popPage.color = active ? "green" : "lightgray"
    }

    ScrollView
    {
        id: scrollView
        anchors.fill: parent


        ListView
        {
            id: listView
            anchors.fill: parent
            model: popPage.itemModel
            delegate: itemDelegate

            Component
            {
                id: itemDelegate
                Rectangle
                {
                    implicitWidth : listView.width
                    implicitHeight: 25
                    color: ((index % 2) == 0) ? "gray" : "lightblue"

                    Loader
                    {
                        id: subItem
                        source: (model.sub == null) ? "" : "PopupPage.qml"                       //当有子菜单时(sub不为null)的时候载入当前qml作为子菜单

                        onLoaded:                                                                //初始化子菜单项并且设置为不接受焦点的窗口
                        {
                            item.flags            = item.flags | Qt.WindowDoesNotAcceptFocus
                            item._parentPopupItem = popPage
                            item.itemModel        = model.sub
                            console.log(model.sub)

                        }
                    }

                    Text
                    {
                        id: itemLabel
                        anchors.left: parent.left
                        anchors.verticalCenter: parent.verticalCenter
                        text: (subItem.item == null) ? model.name : model.name + " --->"         //如果有子菜单项则添加箭头text
                    }
                    MouseArea                                                                    //主要用于控制子菜单的显示与否
                    {
                        id: itemControl
                        anchors.fill: parent
                        hoverEnabled: true
                        onClicked:
                        {
                            if(subItem.item == null)
                            {
                                popPage.hide()
                                var item = popPage._parentPopupItem
                                while(item != null)
                                {
                                    item.hide()
                                    item = item._parentPopupItem
                                }

                                return
                            }

                            popSubItem()
                        }

                        onEntered:
                        {
                            itemLabel.font.bold = true
                            popSubItem()
                        }
                        onExited:
                        {
                            itemLabel.font.bold = false
                        }
                    }

                    function popSubItem()
                    {
                        popPage.show()
                        popPage.requestActivate()

                        if(popPage._lastPopupItem != null &&
                           popPage._lastPopupItem != subItem.item)
                        {
                            popPage._lastPopupItem.hide()
                        }

                        if(model.sub == null)
                            return

                        console.log("pop sub")
                        popPage._lastPopupItem = subItem.item

                        subItem.item.x = popPage.x + popPage.width - 10
                        subItem.item.y = popPage.y + 25 * index
                        subItem.item.show()
                        subItem.item.raise()
                    }

                    function hideSubItem()
                    {
                        if(model.sub == null)
                            return

                        subItem.item.hide()
                        popPage.requestActivate()
                        console.log("hide")
                    }
                }
            }
        }
    }

    onVisibleChanged:                                                                        //处理细节让菜单的弹出和隐藏更加合理
    {
        if(!visible)
        {
            if(popPage._lastPopupItem != null)
            {
                popPage._lastPopupItem.hide()
            }
        }
    }


}

值得注意的是我现在菜单是一个Qt.ApplicationModal的模态框,所以我写了一些Qt代码用来控制当点击目标窗口的时候隐藏这个弹出菜单,如果没有必要用

模态框的话请把这个标志去掉,并且在ActiveChanged的时候决定是否关闭弹出菜单(只有主菜单才会有这个事件,子菜单都被设置了不接受焦点)。








猜你喜欢

转载自blog.csdn.net/r5014/article/details/73770869