第四章自定义编辑器窗口_创建and打开and自定义窗口(3/11)
前言
书本里的这章节主要介绍了自定义窗口,涉及到EditorWindow,PopupWindow,GenericMenus和ScriptsWizard类。还介绍了扩展默认窗口
下面是对他们的一些比较介绍
类名 | 最佳用途 | 生命周期 | 交互复杂度 |
---|---|---|---|
EditorWindow | 长期使用的工具面板 | 持久化(手动关闭) | 高(完整 UI) |
PopupWindow | 临时浮层控件 | 短暂(自动关闭) | 中(轻量控件) |
GenericMenu | 动态右键/下拉菜单 | 瞬时(点击后消失) | 低(纯文本) |
ScriptableWizard | 旧版向导流程(已不推荐) | 中等(任务驱动) | 中(分页表单) |
Unity 版本 | EditorWindow | PopupWindow | GenericMenu | ScriptableWizard |
---|---|---|---|---|
2017.x | ✅ 完整支持 | ✅ 完整支持 | ✅ 完整支持 | ⚠️ 部分支持 |
2019.x | ✅ 完整支持 | ✅ 完整支持 | ✅ 完整支持 | ❌ 已弃用 |
2020.x+ | ✅ 完整支持 | ✅ 完整支持 | ✅ 完整支持 | ❌ 已移除 |
4.1 如何创建新的编辑器窗口
Unity 的使用是在不同的编辑器窗口中进行的,例如Scene、Game、Project、HierarchyInspector、Console 等,除了这些默认的编辑器窗口,开发者可以创建新的编辑器窗口并定义其中的内容,创建的新的编辑器窗口类需要继承EditorWindow。(这是原文)
4.1.1 打开新创建的编辑器窗口
打开编辑器窗口需要一个菜单路径,例如打开控制台窗口的菜单路径为WindGenera/Console,所以首先要为新创建的编辑器窗口使用Menultem 提供一个窗口入口。调用 EditorWindow 类中的静态方法 GetWindowO可以获取指定类型的窗口实例。
using UnityEngine;
using UnityEditor;public class MyEditorWindow : EditorWindow
{[MenuItem("Example/My Editor Window")]public static void ShowWindow(){// 创建或显示编辑器窗口MyEditorWindow window = GetWindow<MyEditorWindow>("窗口标题");window.minSize = new Vector2(300, 200); // 设置最小窗口大小window.maxSize = new Vector2(1920, 1080); // 设置最大窗口大小window.Show();}
}
4.1.2 定义编辑器窗口中的GUI内容
回调方法 | 触发时机 | 主要作用 |
---|---|---|
OnEnable | 窗口创建或重新聚焦时 | 初始化资源、注册事件、恢复状态 |
OnDisable | 窗口失去焦点或被销毁时 | 保存配置、反注册事件、释放资源 |
OnDestroy | 窗口关闭并从内存移除时 | 最终清理、持久化数据 |
OnGUI | 每帧(Repaint 事件) | 绘制界面、处理交互逻辑 |
Update | 每帧(与游戏 Update 同步) | 实时更新数据、刷新视图 |
OnSelectionChange | 场景或 Project 视图选中对象变化时 | 同步显示当前选中内容 |
OnFocus / OnLostFocus | 窗口获得 / 失去焦点时 | 启用/停用输入监听、更新标题栏 |
OnHierarchyChange | 场景层级结构变化时 | 刷新节点列表、重新构建树形视图 |
OnProjectChange | 资源导入 / 删除 / 移动时 | 重新加载资源列表、更新引用 |
using UnityEditor;
using UnityEngine;/// <summary>
/// 这个脚本演示了如何在编辑器窗口中使用OnGUI方法绘制UI控件
/// </summary>
public class MyEditorWindow_CustomOnGUI : EditorWindow
{[MenuItem("Example/Show Editor Window CustomeOnGUI")]public static void ShowWindow(){// 创建或显示编辑器窗口MyEditorWindow_CustomOnGUI window = GetWindow<MyEditorWindow_CustomOnGUI>("使用OnGUI绘制UI控件");window.minSize = new Vector2(300, 300); // 设置最小窗口大小window.maxSize = new Vector2(1920, 1080); // 设置最大窗口大小window.Show();}private void OnGUI(){GUILayout.Button("按钮");}private void OnFocus(){Debug.Log("OnFocus");}private void OnLostFocus(){Debug.Log("OnLostFocus");}private void OnHierarchyChange(){Debug.Log("OnHierarchyChang");}private void OnInspectorUpdate(){Debug.Log("OnInspecotrUpdate");}private void OnProjectChange(){Debug.Log("OnProjectChang");}private void OnSelectionChange(){Debug.Log("OnSelectionChang");}private void OnValidate(){Debug.Log("OnValidate");}private void OnDisable(){Debug.Log("OnDisable");}private void OnDestroy(){Debug.Log("OnDestroy");}
}
4.1.3 如何创建弹出窗口
- PopupWindow
PopupWindow 弹出窗口不可以被拖动,也无法调节大小,并且还会在失去焦点时自动关闭。打开弹出窗口需要调用 PopupWindow中的静态方法Show,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;public class MyEditorWindow_PopupWindow : EditorWindow
{[MenuItem("Example/MyEditorWindow_PopupWindow")]public static void Open(){MyEditorWindow_PopupWindow window = GetWindow<MyEditorWindow_PopupWindow>();window.titleContent = new GUIContent("窗口标题");window.minSize = new Vector2(300f, 300f);window.maxSize = new Vector2(1920f, 1080f);window.Show();}private Rect examplePopuWindowRect;private void OnGUI(){// 绘制一个按钮,点击后弹出窗口if (GUILayout.Button("打开弹出窗口")){PopupWindow.Show(new Rect(100, 100, 200, 200),new ExamplePopupWindowContent(new Vector2(position.width -6f,100f)));}if (Event.current.type == EventType.Repaint){examplePopuWindowRect = GUILayoutUtility.GetLastRect();}}
}public class ExamplePopupWindowContent : PopupWindowContent
{//窗口尺寸private Vector2 windowSize;//滚动值private Vector2 scroll;public ExamplePopupWindowContent(Vector2 windowSize){this.windowSize = windowSize;}public override Vector2 GetWindowSize(){return new Vector2(200f, 200f);}public override void OnGUI(Rect rect){// 在弹出窗口中绘制内容GUILayout.Label("这是一个弹出窗口");if (GUILayout.Button("关闭")){editorWindow.Close();}}public override void OnOpen(){base.OnOpen();Debug.Log("弹出窗口已打开");}public override void OnClose(){base.OnClose();Debug.Log("弹出窗口已关闭");}
}
效果
- GenericMenu
使用 GencricMcnu 同样可以创建一个弹出窗口,与 PopupWindow 的区别在于,以在弹出窗口内开启水平或垂直布局,创建各类型的交互控件,还可以灵活地绘制编素、而前者弹出的窗口只是一个下拉菜单,它包含的公共方法。
方法签名 | 作用描述 | 参数说明 | 使用示例 |
---|---|---|---|
AddItem(GUIContent content, bool on, GenericMenu.MenuFunction func) | 添加可点击菜单项 | content : 菜单项显示内容on : 是否显示选中标记func : 点击回调方法 | menu.AddItem(new GUIContent("保存"), false, Save) |
AddItem(GUIContent content, bool on, GenericMenu.MenuFunction2 func, object userData) | 添加带参数的菜单项 | userData : 传递给回调的自定义数据 | menu.AddItem(new GUIContent("删除"), false, (data) => Delete(data), obj) |
AddDisabledItem(GUIContent content, bool on) | 添加禁用菜单项 | content : 菜单项显示内容on : 是否显示选中标记 | menu.AddDisabledItem(new GUIContent("需要专业版")) |
AddSeparator(string path) | 添加菜单分隔符 | path : 分隔符位置路径 | menu.AddSeparator("编辑/") |
ShowAsContext() | 在鼠标位置显示菜单 | 无参数 | menu.ShowAsContext() |
DropDown(Rect rect) | 在指定位置显示菜单 | rect : 显示位置的矩形区域 | menu.DropDown(buttonRect) |
allowDuplicateNames | 允许重复菜单项名 | 布尔值属性 | menu.allowDuplicateNames = true |
示例代码 |
using UnityEditor;
using UnityEngine;public class MyEditorWindow_PopupWindow_GerericMenu : EditorWindow
{[MenuItem("Example/MyEditorWindow_PopupWindow_GerericMenu")]public static void Open(){MyEditorWindow_PopupWindow_GerericMenu window = GetWindow<MyEditorWindow_PopupWindow_GerericMenu>();window.titleContent = new GUIContent("窗口标题");window.minSize = new Vector2(300f, 300f);window.maxSize = new Vector2(1920f, 1080f);window.Show();}private Rect examplePopuWindowRect;private void OnGUI(){// 绘制一个按钮,点击后弹出窗口if (GUILayout.Button("打开弹出窗口")){PopupWindow.Show(new Rect(100, 100, 200, 200),new ExamplePopupWindowContent(new Vector2(position.width - 6f, 100f)));}if (Event.current.type == EventType.Repaint){examplePopuWindowRect = GUILayoutUtility.GetLastRect();}if (GUILayout.Button("Button")){GenericMenu gm = new GenericMenu();//添加菜单项gm.AddItem(new GUIContent("菜单项1"), false, () => Debug.Log("菜单项1被点击"));//添加分隔符 参数传空字符串表示在一级菜单中添加分隔符gm.AddSeparator(string.Empty);//添加不可交互菜单项gm.AddDisabledItem(new GUIContent("Memu2"));//通过'/'可添加子菜单项gm.AddItem(new GUIContent("Menu3/SubMenu1"), false,() => Debug.Log("Select SubMenu1"));//在子菜单中添加分隔符gm.AddSeparator("Menu3/");gm.AddItem(new GUIContent("Menu3/SubMenu2"), false,() => Debug.Log("Select SubMenu2"));//显示菜单gm.ShowAsContext();}}
}public class ExamplePopupWindowContent_1 : PopupWindowContent
{//窗口尺寸private Vector2 windowSize;//滚动值private Vector2 scroll;public ExamplePopupWindowContent_1(Vector2 windowSize){this.windowSize = windowSize;}public override Vector2 GetWindowSize(){return new Vector2(200f, 200f);}public override void OnGUI(Rect rect){// 在弹出窗口中绘制内容GUILayout.Label("这是一个弹出窗口");if (GUILayout.Button("关闭")){editorWindow.Close();}}public override void OnOpen(){base.OnOpen();Debug.Log("弹出窗口已打开");}public override void OnClose(){base.OnClose();Debug.Log("弹出窗口已关闭");}
}
效果