当前位置: 首页 > news >正文

【第二章自定义功能菜单_MenuItemAttribute_顶部菜单栏(本章进度1/7)】

第二章内容较多,打算分三个部分,七个小节进行记录,这是第一小节。自定义顶部菜单栏。

第一部分MenuItemAttribute(菜单项特性类),这个特性允许我们可以在自定义Unity顶部菜单、自定义Hierarchy窗口右键功能菜单、自定义Projcet窗口右键功能菜单、自定义组件下拉菜单列表功能菜单。在这部分里面有一个网格优化实践小项目,我会放到最后一节。

自定义Unity顶部菜单

在使用一些插件或者框架的时候,会看到一些unity顶部自定义一些菜单项(类似下图),这就是通过MenItemAttribute实现的。

在这里插入图片描述
下面这代码就是利用MenuItem这个特性,他的使用需要using UnityEditor,使用格式是
xxxx是顶部菜单,yyyy是下一级,算上根菜单,最多支持七级(正常三到四级就行了,别再多了)。点击对应的菜单,会执行下面绑定的静态方法,如果例子图,控制台显示出"Function 1 executed"。

  • 先介绍最普通的没有绑定快捷键的。
    [MenuItem(“xxxx/yyyy”)]
    private static void Function1()
    {
    Debug.Log(“Function 1 executed”);
    }

[MenuItem(“xxxx/xxxx”)]下面必须是无返回值的静态方法
下面是一个使用例子

using UnityEngine;
using UnityEditor;public class MenuItemExample
{[MenuItem("测试菜单/funtion1")]private static void Function1(){Debug.Log("Function 1 executed");}}

效果如下,
在这里插入图片描述

  • 接下来介绍绑定快捷键的,我们使用的其他插件或者插件的时候,经常可以看到对应的菜单项,后面会显示快捷键,如下图的打包工具 后面有个“F5”,就可以使用F5 来使用打包工具。

  • 使用格式如下
这里注意下面“示例 修饰符+快捷键” 示例和修饰+快捷键中间是有一个空格的
[MenuItem("测试菜单/示例 修饰符+快捷键")]
private static void ShiftExample()
{Debug.Log("快捷键触发");}

#书上说支持四种基础修饰符和F1到F12、箭头键、Home、End、PageUp、PageDown,但是我个人测试下来,四种基础修饰符和F1到F12、箭头键这三类是支持,而Home那些不知道是不是快捷键冲突,我这边无法使用。我搜到unity官方也是要求"菜单快捷键应使用字母键与基础修饰符组合,避免占用系统级功能键",所以,我们只介绍四种基础修饰符和字符组合。

  • 四种基础修饰符

修饰符名称对应按键使用说明
%Control/CommandWindows: Ctrl
macOS: Cmd
最常用的跨平台修饰符
#ShiftShift上档键,区分大小写
&Alt/OptionWindows: Alt
macOS: Option
注意可能和系统菜单快捷键冲突
_无修饰(功能键)无修饰符仅用于功能键(F1-F12),必须直接加在键名前(如 _F1)
  • 组合修饰符(由基础修饰符组合而成)

组合形式对应按键示例说明
%#Ctrl/Cmd + Shift%#s = Ctrl+Shift+S顺序无关(#%s 等效)
%&Ctrl/Cmd + Alt%&d = Ctrl+Alt+D-
#&Shift + Alt#&e = Shift+Alt+E-
%#&Ctrl/Cmd + Shift + Alt%#&r = 全修饰键+R跨平台行为一致
  • 特殊隐含修饰符

形式说明示例等效组合
大写字母自动包含 Shift 修饰符%G%#g
小写字母无 Shift 修饰符%g纯 Ctrl/Cmd+g

下面是使用脚本

using UnityEngine;
using UnityEditor;public class MenuItemExample
{[MenuItem("测试菜单/funtion1")]private static void Function1(){Debug.Log("Function 1 executed");}// 1. Shift 修饰符示例 (#)[MenuItem("测试菜单/Shift 示例 #s")]private static void ShiftExample(){Debug.Log("Shift + S 触发");// 其他可用组合: #a, #b, #c... (区分大小写)}// 2. Ctrl/Cmd 修饰符示例 (%) 这里windows用Ctrl, Mac用Cmd[MenuItem("测试菜单/Ctrl 示例 %t")]private static void CtrlExample(){Debug.Log("Ctrl/Cmd + T 触发");}// 3. Alt 修饰符示例 (&)[MenuItem("测试菜单/Alt 示例 &r")]private static void AltExample(){Debug.Log("Alt + R 触发");// 注意: macOS上是Option键}// 4. 组合键示例 (%# = Ctrl+Shift)[MenuItem("测试菜单/组合键示例 %#c")]private static void ComboExample(){Debug.Log("Ctrl+Shift+C 触发");// 其他组合: %& (Ctrl+Alt), #& (Shift+Alt), %#& (全修饰键)}// 5. 功能键 F1 示例 (_)[MenuItem("测试菜单/F1 示例 _F1")]private static void F1Example(){Debug.Log("F1 键触发");// 其他功能键: _F2, _F3..._F12 用法相同}// 6. 大小写敏感示例[MenuItem("测试菜单/大小写示例 %g")]  // 小写 gprivate static void LowercaseExample(){Debug.Log("Ctrl+G 触发");}[MenuItem("测试菜单/大小写示例 %G")]  // 大写 Gprivate static void UppercaseExample(){Debug.Log("Ctrl+Shift+G 触发 (自动包含Shift)");}[MenuItem("导航/向左移动 _LEFT")]private static void MoveLeft(){Debug.Log("← 左方向键触发");}[MenuItem("导航/End _End")]private static void End(){Debug.Log("End触发");}
}

效果图
在这里插入图片描述

总结

  1. 基础修饰符:4 种(%, #, &, _
  2. 组合修饰符:4 种(%#, %&, #&, %#&)(由基础修饰符组合而成)
  3. 隐含修饰符:大小写字母(自动处理 Shift 状态)
  4. 总计独立类型:4 种基础类型 + 大小写特殊处理

使用须知

  1. 所有修饰符仅适用于主菜单栏
  2. 功能键(F1-F12)必须使用 _ 前缀且不能与其他修饰符组合
  3. 不要使用系统功能键(Home/End/方向键等)
  4. 字母键区分大小写(%a ≠ %A
  • 最后一个点,就是这些选项的排序问题,它默认是按照首字符A-Z排序的,在[MenuItem]属性中,可以通过制定菜单项的优先级来控制其在菜单中的排序,可以通过设置 priority 参数来实现。优先级的默认值是 1000。格式是这样的[MenuItem(“xxx/yyy”, ture/false,优先级)] 例子是[MenuItem(“测试菜单/普通功能”, false, 1)],这里的[MenuItem] 的参数:
    • 第一个参数是菜单路径,用于定义菜单项的层级和名称。
    • 第二个参数是 isValidate,用于控制是否启用验证函数。如果设置为 false,则直接调用方法;如果设置为 true,则需要提供一个同名的 ValidateMenuItem 方法。
    • 第三个参数是 priority,用于定义菜单项的排序顺序。优先级越低,菜单项越靠前。
    优先级,好理解,一个数字直观显示优先级,关于第二个参数,介绍完优先级之后,再介绍。
    在这里插入图片描述这是设置好的代码
using UnityEngine;
using UnityEditor;public class MenuItemExample
{// 1. 功能键 F1 示例 (_)[MenuItem("测试菜单/F1 示例 _F1", false, 1)] // 设置优先级为 1private static void F1Example(){Debug.Log("F1 键触发");}// 2. 无快捷键示例(直接点击菜单项)[MenuItem("测试菜单/Function1", false, 2)] // 设置优先级为 2private static void Function1(){Debug.Log("Function 1 executed");}// 3. Shift 修饰符示例 (#)[MenuItem("测试菜单/Shift 示例 #s", false, 3)] // 设置优先级为 3private static void ShiftExample(){Debug.Log("Shift + S 触发");}// 4. Ctrl/Cmd 修饰符示例 (%)[MenuItem("测试菜单/Ctrl 示例 %t", false, 4)] // 设置优先级为 4private static void CtrlExample(){Debug.Log("Ctrl/Cmd + T 触发");}// 5. Alt 修饰符示例 (&)[MenuItem("测试菜单/Alt 示例 &r", false, 5)] // 设置优先级为 5private static void AltExample(){Debug.Log("Alt + R 触发");}// 6. 组合键示例 (%# = Ctrl+Shift)[MenuItem("测试菜单/组合键示例 %#c", false, 6)] // 设置优先级为 6private static void ComboExample(){Debug.Log("Ctrl+Shift+C 触发");}// 7. 大小写敏感示例[MenuItem("测试菜单/大小写示例 %g", false, 7)]  // 小写 gprivate static void LowercaseExample(){Debug.Log("Ctrl+G 触发");}[MenuItem("测试菜单/大小写示例 %G", false, 8)]  // 大写 Gprivate static void UppercaseExample(){Debug.Log("Ctrl+Shift+G 触发 (自动包含Shift)");}
}

这是设置好的效果图,如我们代码设置好的优先级排序
在这里插入图片描述
现在介绍一下
isValidate 参数用于控制是否启用验证函数。验证函数的作用是动态决定菜单项是否可用(是否被禁用或显示为灰色)。如果 isValidate 设置为 true,Unity 会尝试调用一个同名的 ValidateMenuItem 方法来判断菜单项是否应该被启用。下面举个代码例子

using UnityEngine;
using UnityEditor;public class MenuItemExample
{// 1. 普通菜单项(无验证)[MenuItem("测试菜单/普通功能", false, 1)]private static void NormalFunction(){Debug.Log("普通功能被执行");}// 2. 需要验证的菜单项(isValidate = true),并添加 F2 快捷键[MenuItem("测试菜单/需要验证的功能 _F2", true, 2)]private static void ValidatedFunction(){Debug.Log("需要验证的功能被执行");}// 3. 验证函数(必须与菜单项方法同名)[MenuItem("测试菜单/需要验证的功能 _F2", false, 2)]private static bool ValidateValidatedFunction(){// 返回 true 表示启用菜单项,返回 false 表示禁用菜单项// 这里我们根据某个条件来判断是否启用return SomeCondition();}// 4. 功能键 F1 示例(无验证)[MenuItem("测试菜单/F1 示例 _F1", false, 3)]private static void F1Example(){Debug.Log("F1 键触发");}// 模拟一个条件判断private static bool SomeCondition(){// 假设我们根据某个条件来判断是否启用菜单项// 这里我们简单地返回一个随机值来模拟return Random.value > 0.5f;}
}

普通菜单项(无验证)

  • 代码
    [MenuItem("测试菜单/普通功能", false, 1)]
    private static void NormalFunction()
    {Debug.Log("普通功能被执行");
    }
    
  • 解释isValidate 设置为 false,表示直接调用 NormalFunction 方法,不进行验证。
  • 行为:这个菜单项始终可用,点击后会输出 "普通功能被执行"

需要验证的菜单项

  • 代码
    [MenuItem("测试菜单/需要验证的功能 _F2", true, 2)]
    private static void ValidatedFunction()
    {Debug.Log("需要验证的功能被执行");
    }
    
  • 解释isValidate 设置为 true,表示需要调用验证函数。同时,通过 _F2 添加了快捷键 F2
  • 行为:当 SomeCondition 返回 true 时,菜单项可用,点击或按下 F2 键后会输出 "需要验证的功能被执行"。如果 SomeCondition 返回 false,菜单项被禁用(显示为灰色),无法点击,按下 F2 键也不会触发。

验证函数

  • 代码
    [MenuItem("测试菜单/需要验证的功能 _F2", false, 2)]
    private static bool ValidateValidatedFunction()
    {// 返回 true 表示启用菜单项,返回 false 表示禁用菜单项// 这里我们通过 SomeCondition 方法来模拟一个条件判断return SomeCondition();
    }
    
  • 解释:验证函数的名称必须与菜单项方法的名称一致,但返回值类型为 boolisValidate 设置为 false,表示这是验证函数。
  • 行为ValidateValidatedFunction 方法返回 true 表示启用菜单项,返回 false 表示禁用菜单项。在这个例子中,我们通过 SomeCondition 方法来模拟一个条件判断。如果条件满足(随机值大于 0.5),菜单项可用;否则,菜单项被禁用。

功能键 F1 示例(无验证)

  • 代码
    [MenuItem("测试菜单/F1 示例 _F1", false, 3)]
    private static void F1Example()
    {Debug.Log("F1 键触发");
    }
    
  • 解释isValidate 设置为 false,表示直接调用 F1Example 方法,不进行验证。通过 _F1 添加了快捷键 F1
  • 行为:这个菜单项始终可用,按下 F1 键后会输出 "F1 键触发"

运行效果

  • 普通功能:始终可用,点击后会输出 "普通功能被执行"
  • 需要验证的功能
    • 如果 SomeCondition 返回 true,菜单项可用,点击或按下 F2 键后会输出 "需要验证的功能被执行"
    • 如果 SomeCondition 返回 false,菜单项被禁用(显示为灰色),无法点击,按下 F2 键也不会触发。
  • F1 示例:始终可用,按下 F1 键后会输出 "F1 键触发"

总结

  • isValidate 参数
    • 设置为 true 时,需要提供一个同名的验证函数(返回值为 bool)。
    • 验证函数的名称必须与菜单项方法的名称一致,但返回值类型不同。
  • 功能键快捷键
    • 功能键(如 F1F2 等)在 [MenuItem] 中需要使用 _ 前缀,例如 _F1_F2 等。
    • 功能键不能与其他修饰符(如 %#&)组合。
  • 验证函数的作用
    • 动态控制菜单项的可用性,可以根据条件返回 truefalse

以下是根据 Unity 2022.3 中文官方文档整理的 MenuItem 属性完整笔记表格,也有后面要讲的东西,上文没涉及的:

Unity MenuItem 属性完整参考表

项目说明语法示例注意事项
基本语法
[MenuItem]创建自定义菜单项[MenuItem("Tools/My Tool")]必须放在 static 方法上
路径格式
主菜单路径使用 / 分隔多级菜单"Window/Submenu/Tool"最多支持7级菜单
上下文菜单路径使用 CONTEXT/[组件名] 格式"CONTEXT/Rigidbody/Reset"右键组件时显示
快捷键修饰符
%Ctrl(Win)/Cmd(Mac)%s → Ctrl/Cmd+S跨平台自动适配
#Shift#g → Shift+G区分大小写
&Alt&f → Alt+F避免与系统快捷键冲突
_无修饰键(仅功能键)_F1 → F1必须直接加在键名前
组合键
双键组合修饰符连续书写%#n → Ctrl/Cmd+Shift+N顺序无关 (#%n 等效)
三键组合全修饰键组合%#&d → Ctrl+Shift+Alt+DmacOS 需开启"辅助功能"权限
特殊参数
priority菜单项排序位置[MenuItem("Tools/Save", false, 10)]数值越小位置越靠上,差值≥10显示分割线
validate验证函数(返回bool)[MenuItem("Tools/Save", true)]true=验证方法,false=执行方法
键位支持
支持键位字母(A-Z)、数字(0-9)、功能键(F1-F12)_F5, %1字母区分大小写
最好别用的键位方向键、PageUp/Down、Home/End 等-需通过 Event 手动处理
使用限制
菜单类型仅限主菜单栏-不适用于右键菜单/上下文菜单
保留快捷键Unity 内置快捷键(如 %z=撤销)-冲突时自定义项会被禁用
平台差异macOS 需开启辅助功能权限-系统偏好设置→安全性与隐私→辅助功能

官方文档核心要点

  1. 路径命名空间

    • CONTEXT/ 专用于组件上下文菜单
    • GameObject/ 会出现在 GameObject 菜单底部
  2. 优先级规则

    优先级范围菜单位置
    0-999GameObject 菜单
    1000-1999Assets 菜单
    ≥2000自定义菜单区

完整文档参见:UnityEditor.MenuItem

http://www.xdnf.cn/news/1125649.html

相关文章:

  • 零售企业用户行为数据画像的授权边界界定:合规与风险防范
  • 16、鸿蒙Harmony Next开发:组件扩展
  • RAG实战指南 Day 16:向量数据库类型与选择指南
  • Django+Celery 进阶:动态定时任务的添加、修改与智能调度实战
  • 第三章 OB SQL 引擎高级技术
  • PostgreSQL 数据库中 ETL 操作的实战技巧
  • 深入探讨Hadoop YARN Federation:架构设计与实践应用
  • docker搭建freeswitch实现点对点视频,多人视频
  • 综合网络组网实验(机器人实验)
  • Java 避免空指针的方法及Optional最佳实践
  • 【Linux系统】命令行参数和环境变量
  • 【Java篇】IntelliJ IDEA 安装与基础配置指南
  • 网络安全职业指南:探索网络安全领域的各种角色
  • 蛋白质组学技术揭示超急性HIV-1感染的宿主反应机制
  • HR数字化转型:3大痛点解决方案与效率突破指南
  • 渭河SQL题库-- 来自渭河数据分析
  • 在 SymPy 中精确提取三角函数系数的深度分析
  • Spring Boot - Spring Boot 集成 MyBatis 分页实现 RowBounds
  • MySQL高级篇(二):深入理解数据库事务与MySQL锁机制
  • AutoGPT vs BabyAGI:自主任务执行框架对比与选型深度分析
  • 【PTA数据结构 | C语言版】二叉树层序序列化
  • TiD2025 | openKylin基础设施平台创新实践分享,构筑开源质量根基
  • ZYNQ千兆光通信实战:Tri Mode Ethernet MAC深度解析
  • 全面安装指南:在Linux、Windows和macOS上部署Apache Cassandra
  • 基于多智能体强化学习的医疗检索增强生成系统研究—MMOA-RAG架构设计与实现
  • wpf Canvas 动态增加右键菜单
  • Kafka与Flink打造流式数据采集方案:以二手房信息为例
  • 如何设计实现开发自助重启工具-01-设计篇
  • MIPI DSI(四) video 和 command 模式
  • npm install failed如何办?