作者最新更新

Unity3D热门教程

    游戏开发工具

    UnityEditor之GenericMenu弹出式菜单

    218

    51 次收藏2024-08-31 23:12:17发布

    GenericMenu 允许您创建自定义上下文菜单和下拉菜单。

    一、弹出式菜单前言

    下面的示例打开了一个带有按钮的编辑器窗口。单击该按钮可显示上下文菜单,您可以通过该菜单更改应用于窗口中 GUI 的颜色。将示例的内容复制到名为 GenericMenuExample.cs 的脚本中,然后将其置于您项目中的 Editor 文件夹内。

    1.jpg

    using UnityEngine;
    using UnityEditor;
    
    public class GenericMenuExample : EditorWindow
    {
      // open the window from the menu item Example -> GUI Color
      [MenuItem("Example/GUI Color")]
      static void Init()
      {
         EditorWindow window = GetWindow<GenericMenuExample>();
         window.position = new Rect(50f, 50f, 200f, 24f);
         window.Show();
      }
    
      //serialize field on window so its value will be saved when Unity recompiles
      [SerializeField]
      Color m_Color = Color.white;
    
      void OnEnable()
      {
        titleContent = new GUIContent("GUI Color");
      }
    
      //a method to simplify adding menu items
      void AddMenuItemForColor(GenericMenu menu, string menuPath, Color color)
      {
        //the menu item is marked as selected if it matches 
        //the current value of m_Color
        menu.AddItem(new GUIContent(menuPath), m_Color.Equals(color), OnColorSelected, color);
      }
    
      //the GenericMenu.MenuFunction2 event handler for when a menu item is selected
      void OnColorSelected(object color)
      {
        m_Color = (Color)color;
      }
    
      void OnGUI()
      {
        //set the GUI to use the color stored in m_Color
        GUI.color = m_Color;
    
        //display the GenericMenu when pressing a button
        if(GUILayout.Button("Select GUI Color"))
        {
          //create the menu and add items to it
          GenericMenu menu = new GenericMenu();
    
          //forward slashes nest menu items under submenus
          AddMenuItemForColor(menu, "RGB/Red", Color.red);
          AddMenuItemForColor(menu, "RGB/Green", Color.green);
          AddMenuItemForColor(menu, "RGB/Blue", Color.blue);
    
          //an empty string will create a separator at the top level
          menu.AddSeparator("");
    
          AddMenuItemForColor(menu, "CMYK/Cyan", Color.cyan);
          AddMenuItemForColor(menu, "CMYK/Yellow", Color.yellow);
          AddMenuItemForColor(menu, "CMYK/Magenta", Color.magenta);
          //a trailing slash will nest a separator in a submenu
          menu.AddSeparator("CMYK/");
          AddMenuItemForColor(menu, "CMYK/Black", Color.black);
    
          menu.AddSeparator("");
    
          AddMenuItemForColor(menu, "White", Color.white);
    
          // display the menu
          menu.ShowAsContext();
        }
      }
    }
    二、GenericMenu菜单简介

    GenericMenu 是 Unity 中的一个强大的类,用于创建和管理自定义上下文菜单(也称为弹出菜单)。可以使用 GenericMenu 来为编辑器中的不同场合或场景元素创建自定义右键单击菜单,以提供各种操作选项。

    using UnityEngine;
    
    namespace UnityEditor
    {
      //
      //摘要:
      //GenericMenu lets you create custom context menus and dropdown menus.
      public sealed class GenericMenu
      {
        public GenericMenu();
    
        //
        //Allow the menu to have multiple items with the same name.
        public bool allowDuplicateNames { get; set; }
    
        //
        //摘要:
        // Add a disabled item to the menu.
        //
        //参数:
        // content:
        // The GUIContent to display as a disabled menu item.
        public void AddDisabledItem(GUIContent content);
        //
        //摘要:
        //     Add a disabled item to the menu.
        //
        //参数:
        // content:
        // The GUIContent to display as a disabled menu item.
        //
        // on:
        // Specifies whether to show that the item is currently activated 
        //  (i.e. a tick next to the item in the menu).
        public void AddDisabledItem(GUIContent content, bool on);
        public void AddItem(GUIContent content, bool on, MenuFunction func);
        public void AddItem(GUIContent content, bool on, MenuFunction2 func, object userData);
        //
        //摘要:
        // Add a seperator item to the menu.
        //
        //参数:
        // path:
        // The path to the submenu, if adding a separator to a submenu. 
        //  When adding a separator to the top level of a menu, use an empty 
        //  string as the path.
        public void AddSeparator(string path);
        //
        //摘要:
        // Show the menu at the given screen rect.
        //
        //参数:
        // position:
        // The position at which to show the menu.
        public void DropDown(Rect position);
        //
        //摘要:
        // Get number of items in the menu.
        //
        //返回结果:
        // The number of items in the menu.
        public int GetItemCount();
        //
        //摘要:
        // Show the menu under the mouse when right-clicked.
        public void ShowAsContext();
    
        //
        //摘要:
        // Callback function, called when a menu item is selected.
        public delegate void MenuFunction();
        //
        //摘要:
        // Callback function with user data, called when a menu item is selected.
        //
        //参数:
        // userData:
        // The data to pass through to the callback function.
        public delegate void MenuFunction2(object userData);
      }
    }
    方法描述
    allowDuplicateNames允许菜单具有多个同名的菜单项。
    AddDisabledItem向菜单添加已禁用的项。
    AddItem向菜单添加一个项。
    AddSeparator向菜单添加一个分隔符项。
    DropDown在给定屏幕矩形中显示菜单。
    GetItemCount获取菜单中的项数。
    ShowAsContext右键单击时在鼠标下显示菜单。
    MenuFunction回调函数,菜单项选中时调用。
    MenuFunction2带有用户数据的回调函数,菜单项选中时调用。


    三、一个GenericMenu菜单例子

    GenericMenu使用简介:

    // 创建一个通用菜单
    GenericMenu menu = new GenericMenu();
    
    //添加一个不可用并且勾选的菜单项RGB/Blue
    menu.AddDisabledItem(new GUIContent("RGB/Blue"), true);
    
    //添加一个菜单项RGB/Red,并且传入一个有参回调
    menu.AddItem(new GUIContent("RGB/Red"), false, OnColorSelected, Color.red);
    
    //添加一个菜单项RGB/Green,并且传入一个无参回调
    menu.AddItem(new GUIContent("RGB/Green"), true, OnColorSelected);
    
    //添加一个分割线
    menu.AddSeparator("");
    
    //允许重命名
    menu.allowDuplicateNames = true;
    
    //添加两个名称一样的菜单项
    menu.AddItem(new GUIContent("CMYK"), true, OnColorSelected);
    menu.AddItem(new GUIContent("CMYK"), true, OnColorSelected);
    
    // 以右键菜单的形式展示菜单
    menu.ShowAsContext();

    一个GenericMenu菜单例子:

    using UnityEngine;
    using UnityEditor;
    
    public class GenericMenuExample : EditorWindow
    {
      [MenuItem("Example/GUI Color")]
      static void Init()
      {
        EditorWindow window = GetWindow<GenericMenuExample>();
        window.position = new Rect(50f, 50f, 200f, 24f);
        window.Show();
      }
    
      [SerializeField]
      Color m_Color = Color.white;
    
      void OnEnable()
      {
        titleContent = new GUIContent("GUI Color");
      }
    
      void AddMenuItemForColor(GenericMenu menu, string menuPath, Color color)
      {
        menu.AddItem(new GUIContent(menuPath), m_Color.Equals(color), OnColorSelected, color);
      }
    
      void OnColorSelected(object color)
      {
        m_Color = (Color)color;
      }
    
      void OnGUI()
      {
        GUI.color = m_Color;
        if (GUILayout.Button("Select GUI Color"))
        {
           GenericMenu menu = new GenericMenu();
    
           AddMenuItemForColor(menu, "RGB/Red", Color.red);
           AddMenuItemForColor(menu, "RGB/Green", Color.green);
           AddMenuItemForColor(menu, "RGB/Blue", Color.blue);
    
           menu.AddSeparator("");
    
           AddMenuItemForColor(menu, "CMYK/Cyan", Color.cyan);
           AddMenuItemForColor(menu, "CMYK/Yellow", Color.yellow);
           AddMenuItemForColor(menu, "CMYK/Magenta", Color.magenta);
           menu.AddSeparator("CMYK/");
           AddMenuItemForColor(menu, "CMYK/Black", Color.black);
    
           menu.AddSeparator("");
    
           AddMenuItemForColor(menu, "White", Color.white);
    
           menu.ShowAsContext();
         }
      }
    }

    2.jpg

    四、Hierarchy 视图添加自定义菜单

    通过 EditorApplication.hierarchyWindowItemOnGUI 来注册 OnHierarchyGUI 方法作为 Hierarchy 视图中的每个项的 GUI 回调函数。当右键点击 Hierarchy 视图中的 GameObject 时,将创建一个包含 “Option 1” 和 “Option 2” 两个选项的 GenericMenu 菜单,并在点击时触发相应的方法。

    using UnityEditor;
    using UnityEngine;
    
    public class TestGenericMenu : MonoBehaviour
    {
        [InitializeOnLoadMethod]
        private static void SceneViewExtensions()
        {
            // 注册 hierarchyWindowItemOnGUI 的回调函数
            EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI;
        }
    
        private static void OnHierarchyGUI(int instanceID, Rect selectionRect)
        {
            if(Event.current != null && 
    		   selectionRect.Contains(Event.current.mousePosition) && 
    		   Event.current.button == 1 && Event.current.type <= EventType.MouseUp)
            {
                GameObject selectedGameObject = 
    				EditorUtility.InstanceIDToObject(instanceID) as GameObject;
                if (selectedGameObject)
                {
                    // 创建 GenericMenu
                    GenericMenu menu = new GenericMenu();
                    menu.AddItem(new GUIContent("Option 1"), 
    							 false, 
    							 Option1Selected, 
    							 selectedGameObject);
                    menu.AddItem(new GUIContent("Option 2"), 
    						     false, 
    							 Option2Selected, 
    							 selectedGameObject);
    
                    // 在鼠标位置显示菜单
                    menu.ShowAsContext();
                    Event.current.Use();
                }
            }
        }
    
        private static void Option1Selected(object obj)
        {
            GameObject selectedObject = obj as GameObject;
            Debug.Log("Option 1 selected for: " + selectedObject.name);
        }
    
        private static void Option2Selected(object obj)
        {
            GameObject selectedObject = obj as GameObject;
            Debug.Log("Option 2 selected for: " + selectedObject.name);
        }
    }

    五、Project 视图添加自定义菜单

    通注册一个回调函数 OnProjectGUI 到 EditorApplication.projectWindowItemOnGUI 事件中。当在 Project 视图中右键点击资源项时,将检测鼠标事件类型是否为右键点击,并且鼠标位置是否在资源项区域内。如果是,则会获取当前资源的路径,并创建一个包含 “Option 1” 和 “Option 2” 两个选项的 GenericMenu 菜单。

    using UnityEditor;
    using UnityEngine;
    
    public class TestGenericMenu : MonoBehaviour
    {
        [InitializeOnLoadMethod]
        private static void SceneViewExtensions()
        {
            // 注册 projectWindowItemOnGUI 的回调函数
            EditorApplication.projectWindowItemOnGUI += OnProjectOnGUI;
        }
    
        private static void OnProjectOnGUI(string guid, Rect selectionRect)
        {
            if (Event.current != null && 
    		    selectionRect.Contains(Event.current.mousePosition) && 
    			Event.current.type == EventType.ContextClick)
            {
                // 获取当前右键点击的资源路径
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                // 创建 GenericMenu
                GenericMenu menu = new GenericMenu();
                menu.AddItem(new GUIContent("Option 1"), 
    						 false, 
    						 Resource1Selected, 
    						 assetPath);
                menu.AddItem(new GUIContent("Option 2"), 
    			             false, 
    						 Resource2Selected, 
    						 assetPath);
    
                // 在鼠标位置显示菜单
                menu.ShowAsContext();
                Event.current.Use();
            }
        }
    
        private static void Resource1Selected(object obj)
        {
            string assetPath = obj as string;
            Debug.Log("Option 1 selected for: " + assetPath);
        }
    
        private static void Resource2Selected(object obj)
        {
            string assetPath = obj as string;
            Debug.Log("Option 2 selected for: " + assetPath);
        }
    }

    六、Game 视图添加自定义菜单

    通注册一个回调函数 OnProjectGUI 到 EditorApplication.projectWindowItemOnGUI 事件中。当在 Project 视图中右键点击资源项时,将检测鼠标事件类型是否为右键点击,并且鼠标位置是否在资源项区域内。如果是,则会获取当前资源的路径,并创建一个包含 “Option 1” 和 “Option 2” 两个选项的 GenericMenu 菜单。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;
    
    #if UNITY_EDITOR
    [ExecuteInEditMode]
    public class TestGenericMenu : MonoBehaviour
    {
        private void OnGUI()
        {
            // 在 Game 视图中的鼠标位置创建 GenericMenu
            if (Event.current !=null && 
    		    Event.current.type ==EventType.ContextClick) 
            {// 通过鼠标右键触发菜单
                Debug.Log("1");
                Vector2 mousePosition = Event.current.mousePosition;
    
                GenericMenu menu = new GenericMenu();
                menu.AddItem(new GUIContent("Option 1"), 
    						 false, 
    						 Option1Selected);
                menu.AddItem(new GUIContent("Option 2"), 
    						 false, 
    						 Option2Selected);
    
                menu.ShowAsContext(); // 以上下文菜单方式显示
                Event.current.Use(); // 标记事件已被处理
            }
        }
    
        private static void Option1Selected()
        {
            Debug.Log("Option 1 selected!");
        }
    
        private static void Option2Selected()
        {
            Debug.Log("Option 2 selected!");
        }
    }
    #endif