作者最新更新

Unity3D热门教程

    游戏开发工具

    UnityEditor之MenuItem属性

    720

    95 次收藏2024-08-31 21:52:40发布

    MenuItem 属性用于向主菜单和检视面板上下文菜单添加菜单项。

    该 MenuItem 属性能够将任何静态函数转变为菜单命令,仅静态函数可使用 MenuItem 属性

    1、要创建热键

    您可以使用以下特殊字符:%(在 Windows 上为 ctrl,在 macOS 上为 cmd)、# (shift)、& (alt)。如果不需要特殊的修改键组合,该键可以在下划线后给出。例如,要创建一个带有热键 shift-alt-g 的菜单,可以使用“MyMenu/Do Something #&g”。要创建带有热键 g 而不按下修改键的菜单,则使用“MyMenu/Do Something _g”。

    2、一些特殊的键盘键可支持作为热键

    例如,“#LEFT”可映射到 shift-left。支持这一功能的键为:LEFT、RIGHT、UP、DOWN、F1 .. F12、HOME、END、PGUP 和 PGDN。

    热键文本前必须有一个空格字符(“MyMenu/Do_g”不能被解释为热键,而“MyMenu/Do _g”则可以被解释为热键)。

    3、子菜单结构

    将菜单项添加到“GameObject/”菜单,以在创建自定义游戏对象时,确保调用 GameObjectUtility.SetParentAndAlign,从而确保在发生上下文单击事件时, 对新的游戏对象进行正确地重定父级(请参阅以下示例)。您的函数也应该调用 Undo.RegisterCreatedObjectUndo,以使创建操作可撤销并将 Selection.activeObject 设置到新创建的对象上。另请注意,为了将“GameObject/”中的菜单项 传播到层级视图 Create 下拉菜单和层级视图上下文菜单,它必须与 其他游戏对象创建菜单项归为一组。

    4、菜单优先级

    这可以通过将其优先级 设为 10 来实现(请参阅以下示例)。请注意,对于“GameObject/Create Other” 中没有明确优先级设置且支持旧版项目的 MenuItem 来说,接收到的优先级为 10 而非默认的 1000, 我们建议使用比“Create Other”更具描述性的类别名称,并将优先级 显式设置为 10。


    一、MenuItem 属性

    1、itemName:菜单名称路径

    特殊路径:

    CONTEXT: 为组件添加菜单项

    Assets: 对应顶部菜单 Assets,并添加 Project 面板右键菜单

    GameObject: 对应顶部菜单 GameObject,priority 值在 149 时,添加 Hierarchy 面板右键菜单

    Component: 对应顶部菜单 Component,对应 Inspector 面板的 Add Component 窗口。但是不知道怎么用,用 AddComponentMenu吧。

    2、isValidateFunction:不写为 false,true 则点击菜单前就会调用

    3、priority:菜单项显示排序 默认 1000

    二、创建多级菜单
    [MenuItem("一级菜单/二级菜单上/三级菜单")]
    static void MenuOne()
    {
      //功能
    }
    
    [MenuItem("一级菜单/二级菜单下")]
    static void MenuTwo()
    {
      //功能
    }

    1.jpg

    三、创建带快捷键的菜单

    在 MenuItem 的双引号菜单路径最后 + 空格 + 快捷键字符

    快捷键可任意组合使用

    英文字母 :_字母 (不区分大小写)

    常用快捷键:

    符号字符
    %Ctr/Command
    #Shift
    &Alt
    LEFT/Right/UP/DOWN方向键
    F1-F2F 功能键
    _g字母 g

    4.jpg

    四、创建可被勾选的菜单
    //设置勾选状态
    //Menu.SetChecked(string menuPath, bool isChecked)
    //获取勾选状态
    //Menu.GetChecked(string menuPath)
    
    [MenuItem("一级菜单/二级菜单上 #_A")]
    static void MenuA()
    {
     string menuPath = "一级菜单/二级菜单上 #_A";
     bool isChecked = !Menu.GetChecked(menuPath);
     Menu.SetChecked(menuPath, isChecked);
    }
    
    [MenuItem("一级菜单/二级菜单中 %#_B")]
    static void MenuB()
    {
     string menuPath = "一级菜单/二级菜单中 %#_B";
     bool isChecked = !Menu.GetChecked(menuPath);
     Menu.SetChecked(menuPath, isChecked);
    }
    
    [MenuItem("一级菜单/二级菜单下 %&_C")]
    static void MenuC()
    {
     string menuPath = "一级菜单/二级菜单下 %&_C";
     bool isChecked = !Menu.GetChecked(menuPath);
     Menu.SetChecked(menuPath, isChecked);
    }

    五、检查菜单是否使用

    通过函数判断菜单是否可使用,操作如下所示:

    [MenuItem("菜单路径名")]
    static void 方法() { }
    
    [MenuItem("菜单路径名"),true]
    static void 验证方法()
    {
      return bool值; //返回true 改菜单启用
    }

    具体实现操作用例:

    [MenuItem("一级菜单/二级菜单上")]
    static void MenuA()
    {
       string menuPath = "一级菜单/二级菜单上";
       bool isChecked = !Menu.GetChecked(menuPath);
       Menu.SetChecked(menuPath, isChecked);
    }
    
    [MenuItem("一级菜单/二级菜单中")]
    static void MenuB()
    {
       string menuPath = "一级菜单/二级菜单中";
       bool isChecked = !Menu.GetChecked(menuPath);
       Menu.SetChecked(menuPath, isChecked);
    
       EditorPrefs.SetBool("MenuCValidate", isChecked);
    }
    
    [MenuItem("一级菜单/二级菜单下")]
    static void MenuC()
    {
       string menuPath = "一级菜单/二级菜单下";
       bool isChecked = !Menu.GetChecked(menuPath);
       Menu.SetChecked(menuPath, isChecked);
    }
    
    [MenuItem("一级菜单/二级菜单下", true)]
    static bool MenuCValidate()
    {
       bool flag = EditorPrefs.GetBool("MenuCValidate");
       Menu.SetChecked("一级菜单/二级菜单中", flag);
       return flag;
    }

    六、菜单排序

    在 priority 小的位置在上方 不配置默认为 1000

    当相邻两个菜单的 priority 值差距超过 10 时 就会分组 中间出现一条横线

    多级菜单的 priority 按照子级里面最小的 priority 算

    [MenuItem("一级菜单/二级菜单上", false, 3)]
    static void MenuA()
    {
    	string menuPath = "一级菜单/二级菜单上";
    	bool isChecked = !Menu.GetChecked(menuPath);
    	Menu.SetChecked(menuPath, isChecked);
    }
    
    [MenuItem("一级菜单/二级菜单中", false, 2)]
    static void MenuB()
    {
    	string menuPath = "一级菜单/二级菜单中";
    	bool isChecked = !Menu.GetChecked(menuPath);
    	Menu.SetChecked(menuPath, isChecked);
    }
    
    [MenuItem("一级菜单/二级菜单下", false, 1)]
    static void MenuC()
    {
    	string menuPath = "一级菜单/二级菜单下";
    	bool isChecked = !Menu.GetChecked(menuPath);
    	Menu.SetChecked(menuPath, isChecked);
    }

    七、Hierarchy 右键菜单

    Hierarchy 右键菜单是菜单栏的 GameObject 菜单栏下的菜单,并且 priority 在 149 范围内

    [MenuItem("GameObject/二级菜单", false, 1)]
    static void MenuA()
    {
    
    }

    八、Project 右键菜单

    Project 右键菜单是菜单栏的 Assets 菜单栏下的菜单

    [MenuItem("Assets/二级菜单", false, 1)]
    static void MenuA()
    {
    
    }

    九、Inspector 组件右键菜单

    组件右键菜单是使用特殊路径 CONTEXT 创建的

    MenuCommand 可以获取到该组件

    [MenuItem("CONTEXT/组件名/菜单名")]
    static void 方法名(MenuCommand cmd)
    {
    	//组件名 t = cmd.context as 组件名;
    	//对该组件进行操作
    }
    
    [MenuItem("CONTEXT/Transform/Reset功能")]
    static void ClearTransformMenu(MenuCommand cmd)
    {
    	Transform t = cmd.context as Transform;
    	t.position = Vector3.zero;
    	t.rotation = Quaternion.identity;
    	t.localScale = Vector3.zero;
    	GameObject obj = new GameObject();
    	obj.transform.parent = t.gameObject.transform;
    }

    十、AddComponentMenu 特性

    AddComponentMenu 直接加载类上,会自动将菜单加到 Component 下,并加在 Inspector 面板的 AddComponentMenu 里。

    AddComponentMenu(string menuName, int order)
    menuName:菜单名路径
    order:菜单项排序

    使用用例:

    [AddComponentMenu("自定义/Test", 1)]
    public class Test : MonoBehaviour
    {
    
    }


    十一、ContextMenu特性添加组件右键菜单

    ContextMenu(string itemName, bool isValidateFunction, int priority)

    itemName:菜单名称

    isValidateFunction:不写为false,true则点击菜单前就会调用 

    priority:菜单项显示排序 默认 1000000

    使用用例:

    [AddComponentMenu("自定义/Test", 1)]
    public class Test : MonoBehaviour
    {
        [ContextMenu("添加空物体")]
        public void AddGameObject()
        {
            transform.position = Vector3.zero;
            transform.rotation = Quaternion.identity;
            transform.localScale = Vector3.zero;
            GameObject obj = new GameObject();
            obj.transform.parent = transform;
        }
    }