ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Wails v2 菜单系统完整指南:从 ApplicationMenu、TrayMenu 到加速键

Wails v2 菜单系统完整指南:从 ApplicationMenu、TrayMenu 到加速键 Wails v2 菜单系统完整指南从 ApplicationMenu、TrayMenu 到加速键【免费下载链接】wailsCreate beautiful applications using Go项目地址: https://gitcode.com/gh_mirrors/wa/wails导读v2/pkg/menu是 Wails v2 提供的一套纯 Go、跨平台的菜单 API其设计重度借鉴 Electron 的菜单方案源码 menuroles.go 头注释明确写道Heavily inspired by Electron (c) 2013-2020 Github Inc.。通过它你可以在不写一行 Objective-C、C 或平台 API 代码的情况下为应用窗口配置应用菜单Application Menu、为系统托盘配置右键菜单Tray Menu、为 WebView 区域配置右键上下文菜单Context Menu并统一声明快捷键加速键。阅读本文后你将掌握菜单项的 5 种类型与工厂函数、菜单的动态增删改、加速键的声明与解析规则、三种菜单应用/托盘/上下文的接入方式以及菜单事件如何从原生层回调到 Go 端。一、整体架构一个 API三个消费场景从源码结构看v2/pkg/menu包目录是一组与平台无关的纯数据模型它不直接调用任何系统 API而是由上层消费方把 Go 侧描述好的菜单树翻译成各平台的原生菜单应用菜单通过 options.App.Menu 字段注入构建应用时生效运行时可用 pkg/runtime 的 MenuSetApplicationMenu / MenuUpdateApplicationMenu 动态替换或刷新。托盘菜单通过 menu.TrayMenu 配置托盘图标、提示与右键菜单。上下文菜单通过 menu.NewContextMenu 注册带 ID 的菜单在 WebView 中配合事件触发右键菜单。在v2/internal侧菜单会被序列化为 JSON 后下发给各平台前端层macOS 侧由 darwin/menu.go 的NSMenu桥接 Cocoa 菜单Windows 与 Linux 也各有对应实现windows/menu.go、linux/menu.go。菜单项的回调点击、勾选等由 menumanager 维护的 ID 映射表反向定位到 Go 函数形成完整的Go 定义 → 原生渲染 → 原生事件 → Go 回调闭环。二、菜单与菜单项的核心数据模型2.1 Menu菜单容器menu.go 定义Menu为Items []*MenuItem的简单列表容器提供一组链式构造方法方法作用底层工厂NewMenu()创建空菜单—Append(item)追加菜单项—Prepend(item)在头部插入菜单项—Merge(menu)将另一个菜单的全部项并入当前菜单—AddText(label, accel, click)添加文本项Text()AddCheckbox(label, checked, accel, click)添加复选菜单项Checkbox()AddRadio(label, checked, accel, click)添加单选菜单项Radio()AddSeparator()添加分隔线Separator()AddSubmenu(label)添加子菜单并返回子菜单实例便于继续往里填充SubMenu()NewMenuFromItems(first, rest...)用一组菜单项直接构建菜单—注意AddSubmenu返回的是新子菜单本身而非父菜单这是常见的嵌套写法parentMenu.AddSubmenu(File)拿到子菜单后再对其调用Append等继续填充。2.2 MenuItem菜单项menuitem.go 定义MenuItem其公开字段构成一个菜单项的完整描述Label菜单显示文本支持 UTF-8Type菜单项类型见下文五种类型Accelerator *keys.Accelerator快捷键绑定Disabled置灰不可点击Hidden隐藏该菜单项Checked勾选状态仅 Checkbox / Radio 有意义SubMenu *Menu子菜单内容仅 Submenu 类型有效Click Callback点击回调Role预定义菜单角色见第六节。2.3 五种菜单项类型type.go 定义了五个类型常量TextType文本、SeparatorType分隔线、SubmenuType子菜单、CheckboxType复选框、RadioType单选。单选组Radio Group的划分规则是任意相邻的 Radio 菜单项组成一组这正是 v2/pkg/menu/README.md 中Radio groups are defined as any number of adjacent radio items的语义。具体分组逻辑由 processedMenu.go 的processRadioGroups实现遍历菜单项时连续的RadioType归入同一个RadioGroup一旦遇到非 Radio 类型包括子菜单边界就 finalise 当前组——所以子菜单之间、被分隔线或其他类型隔开的 Radio 项不会串组。2.4 工厂函数速查除Menu上的AddXxx便捷方法外包级还提供直接构造*MenuItem的工厂函数见 menuitem.goText(label, accel, click)— 普通文本项Checkbox(label, checked, accel, click)— 复选项Radio(label, selected, accel, click)— 单选项Separator()— 分隔线SubMenu(label, menu)— 子菜单项Label(label)— 仅带文本、无加速键无回调的最小文本项。三、实战构建一个完整的应用菜单以下示例演示如何用NewMenu()构建含子菜单、单选组、复选框、分隔线的菜单树并挂载到 Wails 应用package main import ( github.com/wailsapp/wails/v2 github.com/wailsapp/wails/v2/pkg/menu github.com/wailsapp/wails/v2/pkg/menu/keys github.com/wailsapp/wails/v2/pkg/options ) func main() { appMenu : menu.NewMenu() // 应用菜单macOS 特有角色 appMenu.Append(menu.AppMenu()) // 编辑菜单预定义角色Undo/Copy/Paste 等 appMenu.Append(menu.EditMenu()) // 文件子菜单AddSubmenu 返回子菜单实例 fileMenu : appMenu.AddSubmenu(File) fileMenu.AddText(Open..., keys.CmdOrCtrl(o), func(_ *menu.CallbackData) { // 打开文件逻辑 }) fileMenu.AddSeparator() fileMenu.AddText(Quit, keys.CmdOrCtrl(q), func(_ *menu.CallbackData) { // 退出应用 }) // 视图子菜单单选组 复选框 viewMenu : appMenu.AddSubmenu(View) viewMenu.AddRadio(Small, true, nil, nil) viewMenu.AddRadio(Medium, false, nil, nil) viewMenu.AddRadio(Large, false, nil, nil) // 以上三个相邻 Radio 自动成一组 viewMenu.AddCheckbox(Always On Top, true, nil, nil) app : wails.CreateApp(options.App{ Title: Menu Demo, Width: 1024, Height: 768, Menu: appMenu, // 注入应用菜单 Bind: []interface{}{}, }) if err : app.Run(); err ! nil { panic(err) } }3.1 挂载点options.App.Menu菜单通过 options.App.Menu类型为*menu.Menu在创建应用时传入。Wails 内部app.go会把该菜单交给menumanager处理SetApplicationMenu先将整棵菜单树注册进 ID 映射表applicationMenuItemMap再调用processApplicationMenu生成带RadioGroups信息的WailsMenu并序列化为 JSON 下发前端层渲染见 applicationmenu.go。3.2 运行时动态更新菜单菜单并非只能在启动时定义。通过 pkg/runtime/menu.go 暴露的两个函数可以在应用运行期操作import github.com/wailsapp/wails/v2/pkg/runtime // 用新菜单整体替换当前应用菜单 runtime.MenuSetApplicationMenu(ctx, newMenu) // 结构变化增删项、改状态后重新序列化下发 runtime.MenuUpdateApplicationMenu(ctx)UpdateApplicationMenu对应 manager 侧的重新处理流程重建 ID 映射并重新processApplicationMenu用于拾取结构变更applicationmenu.go。四、菜单项的运行时操作menuitem.go 为MenuItem提供了丰富的实例方法大多数返回*MenuItem以便链式调用4.1 状态切换类Disable()/Enable()— 置灰 / 恢复可选Hide()/Show()— 隐藏 / 显示SetChecked(value)— 设置勾选注意当调用者不是 Radio 类型时会把类型强制改为CheckboxType源码 menuitem.goSetLabel(name)— 修改显示文本相同文本时直接返回避免无谓刷新SetAccelerator(acc)— 运行时更换快捷键OnClick(click)— 设置或替换点击回调。4.2 结构调整类父子关系相关菜单项通过内部parent *MenuItem字段维护层级派生出一系列结构调整方法Parent()— 返回父菜单项顶层菜单项返回nilAppend(item)/Prepend(item)— 向子菜单追加 / 头部插入项若当前项不是 Submenu 类型则返回false且不生效InsertAfter(item)/InsertBefore(item)— 在父菜单中相对于当前项插入新项没有父菜单顶层项时返回falseRemove()— 将自身从父菜单中移除内部通过removeLock保证并发安全。这些方法的底层实现insertItemAtIndex等展示了 Wails 对数组索引插入的处理目标索引越界返回false索引等于末尾时退化为普通 append见 menuitem.go。类型判定辅助方法还包括IsSeparator()、IsCheckbox()、IsRadio()。五、加速键Accelerator声明与解析规则菜单快捷键由 keys 子包提供完整支持包含Accelerator结构体、修饰键常量、解析器与跨平台序列化。5.1 Accelerator 与修饰键keys.go 定义Accelerator{Key string, Modifiers []Modifier}并提供以下构造器构造器语义Key(a)普通键自动转小写CmdOrCtrl(a)macOS 为 Cmd其他平台为 CtrlOptionOrAlt(a)macOS 为 Option其他平台为 AltShift(a)Shift 修饰Control(a)Ctrl 修饰Combo(key, m1, m2, rest...)任意多个修饰键组合修饰键常量为CmdOrCtrlKey、OptionOrAltKey、ShiftKey、ControlKey见 keys.go。CmdOrCtrlKey是跨平台最常用的写法——这正是 README 所述支持 UTF-8 标签与 ID之外加速键层面对平台差异的自动化处理。5.2 字符串解析keys.Parseparser.go 提供keys.Parse(shortcut string) (*Accelerator, error)可按字符串形式声明快捷键规则如下以分隔组件最后一个组件必须是键其余必须是修饰键修饰键必须是cmdorctrl、optionoralt、shift、ctrl大小写不敏感同一修饰键不得重复声明重复会报Modifier xxx is defined twice键可以是单个可打印字符也可以是一组命名键backspace, tab, return, enter, escape, left, right, up, down, space, delete, home, end, page up, page down, f1~f35, numlock特殊键名plus会解析为字面量。测试用例 parser_test.go 给出了正反例// 合法 keys.Parse(CmdOrCtrlA) // → CmdOrCtrl(a) keys.Parse(SHIFT.) // → Shift(.) keys.Parse(CTRLplus) // → Control() keys.Parse(CTRLSHIFTescape) // → Combo(escape, ControlKey, ShiftKey) keys.Parse(OptionOrAltPage Down) // → OptionOrAlt(page down) // 非法拼写错误、修饰键作尾、缺修饰键的复合写法均报错 keys.Parse(CmdOrCrlA) // 错误 keys.Parse(OptionOrAlt) // 错误最后一个组件必须是键5.3 跨平台展示keys.Stringifystringify.go 的Stringify(accelerator, platform)负责把Accelerator渲染成平台风格快捷键文案Windows/Linux 上CmdOrCtrlKey显示为CtrlmacOS 上显示为Cmd键名统一大写例如CtrlO/CmdO。macOS 侧的原生菜单桥接会通过 macmodifiers.go 的ToMacModifier把修饰键映射为NSEventModifierFlagCommand/Control/Option/Shift位标志直接喂给 Cocoa 层见 darwin/menu.go。六、预定义菜单角色Rolemenuroles.go 定义了Role类型与三个可用角色常量并明确要求与原生层常量保持同步AppMenuRole— 对应AppMenu()macOS 应用菜单About、Services 等仅 macOS 有意义EditMenuRole— 对应EditMenu()标准编辑菜单Undo、Redo、Cut、Copy、Paste、SelectAll 等WindowMenuRole— 对应WindowMenu()标准窗口菜单Minimize、Zoom 等。appMenu.Append(menu.AppMenu()) appMenu.Append(menu.EditMenu()) appMenu.Append(menu.WindowMenu())源码注释提示两个注意点一是Role常量的取值必须与v2/internal/frontend/desktop/darwin/Role.h保持同步二是 macOS 上无边框frameless窗口内 Window 菜单的选项可能不生效。其余 Electron 风格角色About、Undo、Cut、Quit 等在当前版本中处于注释状态未对外提供——写代码时不要假设它们可用。七、托盘菜单Tray Menu与上下文菜单Context Menu7.1 TrayMenu 配置项menu/tray.go 定义TrayMenu托盘相关字段如下Label托盘悬停提示文本Image托盘图标。构建时会从项目目录/trayicons目录读取图标文件名不含扩展名即引用 ID例如trayicons/main.png用main引用若非文件名则按 base64 图片数据处理MacTemplateImagemacOS 模板图随系统深浅色自动适配RGBA文本颜色FontSize/FontName字体设置Tooltip工具提示Disabled整体置灰Menu *Menu托盘右键菜单树OnOpen()/OnClose()菜单打开 / 关闭回调。7.2 ContextMenu 注册与更新contextmenu.go 提供NewContextMenu(ID, menu)创建带唯一 ID 的上下文菜单。manager 侧menumanager/contextmenu.go维护contextMenus/contextMenuPointers两个映射支持AddContextMenu注册与UpdateContextMenu刷新更新前必须已注册否则返回错误提示先AddContextMenu()。7.3 点击事件的统一分发无论应用菜单、托盘菜单还是上下文菜单点击事件最终都会进入menumanager的ProcessClick(menuID, data, menuType, parentID)menumanager.go它根据menuTypeApplicationMenu/ContextMenu/TrayMenu找到对应菜单项 ID 映射表再反查*menu.MenuItem并触发其Click回调。回调签名为type Callback func(*CallbackData)CallbackData携带被点击的MenuItem引用callback.go。八、设计与使用要点小结单选组 相邻 Radio 项分组在序列化阶段由 processedMenu.go 完成跨子菜单、被分隔线隔断的 Radio 不会合并成组。UTF-8 全支持菜单标签与菜单 ID 均支持 UTF-8见 v2/pkg/menu/README.md中文菜单可直接书写。平台差异由框架消化CmdOrCtrl这类抽象修饰键 Stringify/ToMacModifier的转换让同一份菜单代码可在三平台呈现正确的快捷键。动态更新三途径启动时经options.App.Menu注入运行时用runtime.MenuSetApplicationMenu整树替换结构小改后runtime.MenuUpdateApplicationMenu刷新下发。先注册后更新上下文菜单必须先AddContextMenu才能UpdateContextMenu否则会收到明确的错误提示。Role 有平台边界AppMenu仅 macOS 生效frameless 窗口下的 Window 菜单选项在 macOS 上可能不可用注释掉的 Electron 角色未实现不应使用。延伸阅读菜单数据模型 v2/pkg/menu/menu.go、v2/pkg/menu/menuitem.go加速键实现与测试 keys.go、parser.go、stringify.go、parser_test.go菜单角色 menuroles.go运行时 API v2/pkg/runtime/menu.go菜单管理器序列化、单选组、事件分发 v2/internal/menumanager/menumanager.go、v2/internal/menumanager/applicationmenu.go、v2/internal/menumanager/contextmenu.go、v2/internal/menumanager/processedMenu.go平台桥接示例macOS v2/internal/frontend/desktop/darwin/menu.go挂载入口 v2/pkg/options/options.go【免费下载链接】wailsCreate beautiful applications using Go项目地址: https://gitcode.com/gh_mirrors/wa/wails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表