【QML】菜单

相关类型:MenuBar、Menu、MenuItem、MenuSeparator、Action

注意:本文基于Qt Quick Control 2,在帮助文档里搜索MenuBar,将弹出以下选项
在这里插入图片描述
前两个是旧的MenuBar,用法跟最新的不一样,import的时候注意import QtQuick.Controls 2.x,否则会提示错误
同样的事情发生在搜索Menu、MenuItem、MenuSeparator时,也是弹出多个版本,这也是qml很让人头疼的地方,同样名字的类型,往往存在多个不同时期、互不兼容的版本,互相之间其实是两个完全不一样的类型了!


MenuBar
从Qt5.10开始加入,继承自Container,由多个Menu构成

帮助文档里给出了一个简单的例子

在这里插入图片描述

  ApplicationWindow {
      id: window
      width: 320
      height: 260
      visible: true

      menuBar: MenuBar {
          Menu {
              title: qsTr("&File")
              Action { text: qsTr("&New...") }
              Action { text: qsTr("&Open...") }
              Action { text: qsTr("&Save") }
              Action { text: qsTr("Save &As...") }
              MenuSeparator { }
              Action { text: qsTr("&Quit") }
          }
          Menu {
              title: qsTr("&Edit")
              Action { text: qsTr("Cu&t") }
              Action { text: qsTr("&Copy") }
              Action { text: qsTr("&Paste") }
          }
          Menu {
              title: qsTr("&Help")
              Action { text: qsTr("&About") }
          }
      }
  }

Menu
从Qt5.7开始加入,继承自Popup,Popup是qml专门为弹出式控件定义的基类,Menu属于Popup的一种,类似的还有Dialog,Drawer, ToolTip

Menu有两种使用场景:
Context menus; for example, a menu that is shown after right clicking
Popup menus; for example, a menu that is shown after clicking a button
不管哪种,都是通过click事件弹出菜单,它们的区别是第一种是通过 Menu.popup()打开菜单,而第二种是通过Popup.open()打开菜单

一个鼠标右键菜单的例子:
在这里插入图片描述

  MouseArea {
      anchors.fill: parent
      acceptedButtons: Qt.LeftButton | Qt.RightButton
      onClicked: {
          if (mouse.button === Qt.RightButton)
              contextMenu.popup()
      }
      onPressAndHold: {
          if (mouse.source === Qt.MouseEventNotSynthesized)
              contextMenu.popup()
      }

      Menu {
          id: contextMenu
          MenuItem { text: "Cut" }
          MenuItem { text: "Copy" }
          MenuItem { text: "Paste" }
      }
  }

上面通过MenuItem定义菜单子项,也可以通过Action来定义,效果是一样的

  MouseArea {
      anchors.fill: parent
      acceptedButtons: Qt.LeftButton | Qt.RightButton
      onClicked: {
          if (mouse.button === Qt.RightButton)
              contextMenu.popup()
      }
      onPressAndHold: {
          if (mouse.source === Qt.MouseEventNotSynthesized)
              contextMenu.popup()
      }

        Menu {
            id: contextMenu
            Action { text: "Cut" }
            Action { text: "Copy" }
            Action { text: "Paste" }
        }
  }

MenuItem
从Qt5.7开始加入,继承自AbstractButton,提供了一个triggered信号,通过onTriggered事件处理函数,如

Menu {
     id: contextMenu
     MenuItem {
     	text: "Cut" 
     	onTriggered: console.log("menu-cut")
	 }
 }

Action
从Qt5.10开始加入,继承自QtObject,专门用于菜单栏或者工具栏,可以check,可以分配快捷键。当作为menu的元素时,也被认为是一个MenuItem。

简单的例子:

  ToolButton {
      id: toolButton
      action: copyAction
  }
  Action {
      id: copyAction
      text: qsTr("&Copy")
      icon.name: "edit-copy"
      shortcut: StandardKey.Copy
      onTriggered: window.activeFocusItem.copy()
  }

自定义菜单

Customizing MenuBar

我们可以定制MenuBar的background和delegate,其中delegate定义为 MenuBarItem

例子:
在这里插入图片描述

import QtQuick 2.12
import QtQuick.Controls 2.12

MenuBar {
    id: menuBar

    Menu {
        title: qsTr("File")
        Action { text: "New" }
        Action { text: "Open" }
        Action { text: "Save" }
    }
    Menu {
        title: qsTr("Edit")
        Action { text: "Undo" }
        Action { text: "Redo" }
        MenuSeparator{}
        Action { text: "Cut" }
        Action { text: "Copy" }
        Action { text: "Phaste" }
    }
    Menu {
        title: qsTr("View")
        Action { text: "Manager" }
        Action { text: "Bookmark" }
        Action { text: "Toolbox" }
        Action { text: "Log" }
    }
    Menu {
        title: qsTr("Help")
        Action { text: "Manual" }
        Action { text: "Update" }
        Action { text: "About" }
    }

    delegate: MenuBarItem {
        id: menuBarItem

        contentItem: Text {
            text: menuBarItem.text
            font: menuBarItem.font
            opacity: enabled ? 1.0 : 0.3
            color: menuBarItem.highlighted ? "#ffffff" : "#21be2b"
            horizontalAlignment: Text.AlignLeft
            verticalAlignment: Text.AlignVCenter
            elide: Text.ElideRight
        }

        background: Rectangle {
            implicitWidth: 40
            implicitHeight: 40
            opacity: enabled ? 1 : 0.3
            color: menuBarItem.highlighted ? "#21be2b" : "transparent"
        }
    }

    background: Rectangle {
        implicitWidth: 40
        implicitHeight: 40
        color: "#ffffff"

        Rectangle {
            color: "#21be2b"
            width: parent.width
            height: 1
            anchors.bottom: parent.bottom
        }
    }
}

上面的例子只影响MenuBar的一级菜单,二级菜单需要进一步定制Menu

Customizing Menu

我们可以定制Menu的background 、MenuItem 、MenuSeparator ,其中,MenuItem是每个选项,又可以定制其 background、content item、indicator、arrow,而MenuSeparator则可以定制其 background、content item

我们在上面的MenuBar例子基础上,修改其中名为“View”的Menu:
在这里插入图片描述

        Menu {
            title: qsTr("View")
            Action { text: "Manager"; checkable: true; checked: true  }
            Action { text: "Bookmark"; checkable: true }
            Menu {
                title: "Toolbox"
                Action { text: "Selector" }
                Action { text: "Pen" }
                Action { text: "Brush" }
                MenuSeparator {
                    contentItem: Rectangle {
                        implicitWidth: 200
                        implicitHeight: 1
                        color: "#21be2b"
                    }
                }
                Action { text: "Zoom In" }
                Action { text: "Zoom Out" }
                Action { text: "Rotate" }
                Action { text: "Flip" }
            }
            Action { text: "Log" }

			//定义菜单每个选项的显示行为
            delegate: MenuItem {
                id: menuItem
                implicitWidth: 200
                implicitHeight: 40

                //MenuItem专属的arrow属性,用于定制展开选项的箭头
                arrow: Canvas {
                    x: parent.width - width
                    implicitWidth: 40
                    implicitHeight: 40
                    visible: menuItem.subMenu
                    onPaint: {
                        var ctx = getContext("2d")
                        ctx.fillStyle = menuItem.highlighted ? "#ffffff" : "#21be2b"
                        ctx.moveTo(15, 15)
                        ctx.lineTo(width - 15, height / 2)
                        ctx.lineTo(15, height - 15)
                        ctx.closePath()
                        ctx.fill()
                    }
                }

				//AbstractButton的属性,用于定制选项前的指示标记
                indicator: Item {
                    implicitWidth: 40
                    implicitHeight: 40
                    Rectangle {
                        width: 26
                        height: 26
                        anchors.centerIn: parent
                        visible: menuItem.checkable
                        border.color: "#21be2b"
                        radius: 3
                        Rectangle {
                            width: 14
                            height: 14
                            anchors.centerIn: parent
                            visible: menuItem.checked
                            color: "#21be2b"
                            radius: 2
                        }
                    }
                }

				//用于定制选项文本
                contentItem: Text {
                    leftPadding: menuItem.indicator.width
                    rightPadding: menuItem.arrow.width
                    text: menuItem.text
                    font: menuItem.font
                    opacity: enabled ? 1.0 : 0.3
                    color: menuItem.highlighted ? "#ffffff" : "#21be2b"
                    horizontalAlignment: Text.AlignLeft
                    verticalAlignment: Text.AlignVCenter
                    elide: Text.ElideRight
                }

				//用于定制选项背景
                background: Rectangle {
                    implicitWidth: 200
                    implicitHeight: 40
                    opacity: enabled ? 1 : 0.3
                    color: menuItem.highlighted ? "#21be2b" : "transparent"
                }
            }

			//定制整个菜单的背景
            background: Rectangle {
                implicitWidth: 200
                implicitHeight: 40
                color: "#ffffff"
                border.color: "#21be2b"
                radius: 2
            }
        }

这里偷懒没有定制“Toolbox”的次级菜单,可以通过把上面的例子封装为一个Menu模块,如MyMenu.qml,在创建菜单时直接使用MyMenu就可以达到定制效果


动态创建菜单

(To be continued)

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值