如何从脚本在 Unity 中创建 window 并将其附加到现有选项卡?

How to create a window in Unity from a script and attach it to an existing tab?

我正在尝试为 Unity 制作一个自定义编辑器脚本,但我被困在我认为很简单的步骤中。 使用 UnityEditor.GetWindow() 时,window 不会在主选项卡中打开,而是作为单独的 Window 打开。 The scene view is not attached to the main Unity window.

我尝试了一些解决方法,但 none 似乎有效:

我一直在 中收到错误,说它是一个变量而不是类型 (我也尝试使用 inspWndType.gettype 或转换它,但没有任何效果)。

TLDR:我希望能够使用 EditorWindow.GetWindow() 创建一个 window 并将其停靠在脚本中。

感谢任何可以帮助我的人。

首先 typeof 期望编译时常量类型不是动态变量。

所以如果有的话应该是例如

var inspWndType = typeof(UnityEditor.SceneView);

然而,第二个问题:你不能将它作为泛型类型参数。

你想要做的是假设你的编辑器window看起来像

public class YOURWINDOW : EditorWindow
{
    ...
}

那么应该是

var inspWndType = typeof(UnityEditor.SceneView);
var window = EditorWindow.GetWindow<YOURWINDOW>(inspWndType);

这里不需要反射,因为您不想处理任何运行时类型,而且 UnityEditor.SceneView 无论如何都是 public。


示例:

using System;
using UnityEditor;

public class ExampleWindow : EditorWindow
{
    [MenuItem("Examples/ExampleWindow")]
    private static void Init()
    {
        var inspWndType = typeof(SceneView);
        var window = GetWindow<ExampleWindow>(inspWndType);
    }

    private void OnGUI()
    {
        EditorGUILayout.LabelField("Tadaaaa!", EditorStyles.boldLabel);
    }
}


现在 如果 无论打开哪个选项卡,您实际上都希望将其停靠,您可以使用反射来查找 EditorWindow 的每个继承者并执行

using Linq;

...

var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).Where(type =>type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow))).ToArray();
// This kind of equals doing something like
//var typesList = new List<Type>();
//var assemblies = AppDomain.CurrentDomain.GetAssemblies();
//foreach(var assembly in assemblies)
//{
//    var allTypes = assembly.GetTypes();
//    foreach(var type in allTypes)
//    {
//        if(type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow)))
//        {
//            typesList.Add(type);
//        }
//    }
//}
//var types = typesList.ToArray();

var window = GetWindow<YOURWINDOW>(types);

请注意,由于顺序,ConsoleWindow 几乎是第一个条目,所以如果打开了控制台选项卡,它总是首先附加到该选项卡 ^^

你仍然可以添加你喜欢的,例如

var types = new List<Type>()
{ 
    // first add your preferences
    typeof(SceneView), 
    typeof(Editor).Assembly.GetType("UnityEditor.GameView"),
    typeof(Editor).Assembly.GetType("UnityEditor.SceneHierarchyWindow"),
    typeof(Editor).Assembly.GetType("UnityEditor.ConsoleWindow"), 
    typeof(Editor).Assembly.GetType("UnityEditor.ProjectBrowser"), 
    typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow")
};

// and then add all others as fallback (who cares about duplicates at this point ? ;) )
types.AddRange(AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).Where(type =>type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow))));
var window = GetWindow<YOURWINDOW>(types.ToArray());
 

因为它从字面上从头到尾遍历这个数组,并使用第一个匹配打开的 window 类型。