Skip to content

Context menu(上下文菜单) ​

ContextMenu 给一个元素一个系统菜单,在被右键点击元素处(macOS 上为 Control 单击)打开;当它或其内部的元素拥有焦点时按下菜单键或 Shift+F10, 则在其下方打开。这个函数在菜单打开时构建菜单项,并在选中某一项之后的那 一帧再次运行,届时它的 Chosen 会上报选中:

go
row.ContextMenu(func(m *ui.Menu) {
	if m.Item("Rename").Shortcut(0, ui.KeyF2).Chosen() {
		app.renaming = i
	}
	if m.Item("Pinned").Checked(note.pinned).Chosen() {
		note.pinned = !note.pinned
	}
	m.Submenu("Move to", func(m *ui.Menu) {
		for _, f := range app.folders {
			if m.Item(f.name).Chosen() {
				moveTo, moved = f, i
			}
		}
	})
	m.Separator()
	if m.Item("Delete").Disabled(note.locked).Chosen() {
		deleted = i
	}
})

这个函数在元素构建时运行,位于构建各行的循环中:一个把该行从笔记中移除的 选择,如移动或删除它,会被记下来,以便在循环结束后进行更改(参见 视图)。

菜单项 ​

  • Item(label) 添加一个菜单项;Chosen 报告它是否被选中。
  • Checked(on) 在其旁显示一个对勾,用于选择该项会切换的设置;Radio(on) 将其显示为一组中选择一个设置的一项,当 on 为 true 时标记为被选中的那个。
  • Disabled(d) 将其置灰:它不能被选中。
  • Shortcut(mods, key) 在其旁显示一个按键,作为执行相同操作的快捷键。它 只显示按键:用上下文或元素上的 Shortcut 来处理它。
  • Separator() 在菜单项组之间添加一条线,Submenu(label, build) 添加一个 打开子菜单的菜单项,子菜单由 build 填充。

由哪个元素响应 ​

最内层带菜单的元素获得点击,比如位于带另一个菜单的行之内、带有自己菜单的 行内按钮。文本输入框带有其平台文本字段的编辑命令,可选中 的文本带有复制和全选。在输入框、文本或 Selectable 容器上的 ContextMenu 会替换那个菜单,EditItems 则把这些命令加入你自己的菜单, 作用于被点击的文字,就像聊天消息的文字在复制之上提供回复:

go
message.Selectable().ContextMenu(func(m *ui.Menu) {
	if m.Item("Reply").Chosen() {
		app.reply(msg)
	}
	m.Separator()
	m.EditItems()
})

同样的菜单在带 Element.Menu 的按钮下方打开:参见 菜单按钮。在测试中,tt.RightClick 打开上下文菜单, tt.Menu 列出它,tt.ChooseMenuItem 从中选择。

在窗口内绘制 ​

PopoverMenu 接受同样的函数,由 MyGo 以主题的外观在窗口内绘制菜单,作为 一个弹出面板,用于系统本来会显示自己菜单的场合:在应用自己 设计的弹出面板和按钮旁边,系统菜单往往是那个看起来格格不入的。

go
card.PopoverMenu(func(m *ui.Menu) {
	if m.Item("Play Next").Chosen() {
		app.playNext(album)
	}
	if m.Item("Pinned").Checked(album.pinned).Chosen() {
		album.pinned = !album.pinned
	}
	m.Submenu("Sort by", func(m *ui.Menu) {
		for _, by := range []string{"Title", "Artist", "Year"} {
			if m.Item(by).Radio(app.sort == by).Chosen() {
				app.sort = by
			}
		}
	})
	m.Separator()
	if m.Item("Remove").Shortcut(0, ui.KeyDelete).Disabled(album.locked).Chosen() {
		app.remove(album)
	}
})

它像系统菜单一样打开:在元素被右键点击处,或在菜单键或 Shift+F10 之后于 其下方打开,在该点之后,或当窗口没有空间时在其之前,并随窗口滚动跟随元素。 它在打开时获得焦点,在关闭时把焦点交还给之前拥有它的元素,并具有系统菜单的 按键:

  • 上和下在菜单项间移动,跳过分隔线和被禁用的项,并且循环;Home 和 End 前往 第一个和最后一个,键入菜单项的首字母会前往该项。
  • 右打开该项的子菜单,左关闭它,从右到左时相反;指针 移到该项上时也会打开子菜单。
  • Enter 和空格选择该项,如同点击;Escape 先关闭最上层的子菜单,再关闭菜单, Tab 关闭菜单。
  • 菜单外的按下会关闭菜单,并继续传给指针下的内容。

它的菜单项在标签后显示它们的 Shortcut,被 Checked 或 Radio 标记的项 旁带有对勾或圆点。辅助技术看到的是由菜单项、复选框项和单选项组成的菜单, 无论是否勾选,与它看到系统菜单时一样。

绘制菜单的菜单项是元素:在测试中,tt.RightClick 打开它,tt.HasText 找到它的菜单项,tt.Click 选择一个,而 tt.Menu 只列出系统的菜单。

PopoverMenuButton 以这种方式绘制 菜单按钮的菜单,在其按钮下方,并接受 同样的函数:一行的右键点击和它的 ⋯ 按钮可以共用一个菜单,绘制得一模一样。