相关类型: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()
}
自定义菜单
我们可以定制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
我们可以定制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)