> 技术文档 > 第四章自定义编辑器窗口_创建and打开and自定义窗口(3/11)

第四章自定义编辑器窗口_创建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(); }}

第四章自定义编辑器窗口_创建and打开and自定义窗口(3/11)

4.1.2 定义编辑器窗口中的GUI内容

回调方法 触发时机 主要作用 OnEnable 窗口创建或重新聚焦时 初始化资源、注册事件、恢复状态 OnDisable 窗口失去焦点或被销毁时 保存配置、反注册事件、释放资源 OnDestroy 窗口关闭并从内存移除时 最终清理、持久化数据 OnGUI 每帧(Repaint 事件) 绘制界面、处理交互逻辑 Update 每帧(与游戏 Update 同步) 实时更新数据、刷新视图 OnSelectionChange 场景或 Project 视图选中对象变化时 同步显示当前选中内容 OnFocus / OnLostFocus 窗口获得 / 失去焦点时 启用/停用输入监听、更新标题栏 OnHierarchyChange 场景层级结构变化时 刷新节点列表、重新构建树形视图 OnProjectChange 资源导入 / 删除 / 移动时 重新加载资源列表、更新引用
using UnityEditor;using UnityEngine;/// /// 这个脚本演示了如何在编辑器窗口中使用OnGUI方法绘制UI控件 /// 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\"); }}

第四章自定义编辑器窗口_创建and打开and自定义窗口(3/11)

4.1.3 如何创建弹出窗口

  1. 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(\"弹出窗口已关闭\"); } }

效果
第四章自定义编辑器窗口_创建and打开and自定义窗口(3/11)

  1. 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(\"弹出窗口已关闭\"); }}

效果
第四章自定义编辑器窗口_创建and打开and自定义窗口(3/11)