为什么在EditorWindow脚本的OnGUI中看不到TextField?

时间:2019-03-18 15:18:28

标签: c# unity3d

using UnityEngine;
using UnityEditor;

public class SearchableWindow : EditorWindow
{
    string searchString = "";

    [MenuItem("Tools/Searching")]
    private static void Searching()
    {
        const int width = 340;
        const int height = 420;

        var x = (Screen.currentResolution.width - width) / 2;
        var y = (Screen.currentResolution.height - height) / 2;

        GetWindow<SearchableWindow>().position = new Rect(x, y, width, height);
    }


    void OnGUI()
    {
        GUILayout.BeginHorizontal(EditorStyles.toolbar);
        GUILayout.FlexibleSpace();
        searchString = GUILayout.TextField(searchString, EditorStyles.toolbarTextField);
        GUILayout.EndHorizontal();

        var items = Selection.gameObjects;
        // Do comparison here. For example
        for (int i = 0; i < items.Length; i++)
        {
            if (items[i].name.Contains(searchString))
            {
                GUILayout.Label(items[i].name);
            }
        }
    }
}

在运行正常之前,但是现在一切都很缓慢,而且我也看不到TextField,并且在Hierarchy中选择GameObject时,要花费近5秒钟才能在Editor窗口中显示它。

在此之前,一切很快,并在“编辑器”窗口中显示了整个层次结构。

现在它是空的:

Searchable window

我从以下问题中得到了答案:

Searchable

1 个答案:

答案 0 :(得分:2)

OnGUI仅在鼠标(在移动/单击)相应窗口上时被调用->它不会占用almost 5 seconds,而是直到再次将鼠标移到窗口上。

为了解决此问题,您可以实施EditorWindow.OnSelectionChange并强制使用EditorWindow.Repaint,以便每次Selection更改时刷新窗口。

private void OnSelectionChange()
{
    Repaint();
}

第二期如下:

GUILayout.TextFieldGUILayout.FlexibleSpace(如果未定义)一起自动使用插入文本的宽度->由于开始时的文本为空,因此宽度几乎为 0。 ..实际上,您可以看到那里的TextField非常薄,并且随着它的填充它会变大:

enter image description here

使用EditorGUILayout中的抽屉可以解决此问题:

EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
GUILayout.FlexibleSpace();
searchString = EditorGUILayout.TextField(searchString, EditorStyles.toolbarTextField);
EditorGUILayout.EndHorizontal();

var items = Selection.gameObjects;
// Do comparison here. For example
foreach (var selectedObject in selected)
{
    if (selectedObject .name.Contains(searchString))
    {
        EditorGUILayout.LabelField(selectedObject.name);
    }
}

提示(如果替换)

EditorGUILayout.LabelField(items[i].name);

使用

if (GUILayout.Button(selectedObject.name, EditorStyles.label))
{
    EditorGUIUtility.PingObject(selectedObject);
}

您可以单击名称,然后在层级中“ ping”相应的GameObject!


更新,因为已在评论中询问

如果要包括选择递归的所有子项,可以执行类似的操作(可能会有更好的方法,但这就是我在10分钟之内得出的结论)

private static IEnumerable<GameObject> GetChildrenRecursive(GameObject root)
{
    var output = new List<GameObject>();

    //add the root object itself
    output.Add(root);

    // iterate over direct children
    foreach (Transform child in root.transform)
    {
        // add the child itslef
        output.Add(child.gameObject);

        // Recursion here: Get all subchilds of this child
        var childsOfchild = GetChildrenRecursive(child.gameObject);
        output.AddRange(childsOfchild);
    }

    return output;
}

private static IEnumerable<GameObject> GetChildrenRecursive(IEnumerable<GameObject> rootObjects)
{
    var output = new List<GameObject>();


    foreach (var root in rootObjects)
    {
        output.AddRange(GetChildrenRecursive(root));
    }

    // remove duplicates
    return output.Distinct().ToList();
}

并使用

var selected = GetChildrenRecursive(Selection.gameObjects);

另一个更新

由于这可能不是很有效,您可能应该将其移至Searching,而不是像这样在selected中刷新OnSelectionChange

public class SearchableWindow : EditorWindow
{
    private string searchString = "";
    private List<GameObject> selected;

    [MenuItem("Tools/Searching")]
    private static void Searching()
    {
        const int width = 340;
        const int height = 420;

        var x = (Screen.currentResolution.width - width) / 2;
        var y = (Screen.currentResolution.height - height) / 2;

        var window = GetWindow<SearchableWindow>();
        window.position = new Rect(x, y, width, height);

        window.selected = GetChildrenRecursive(Selection.gameObjects).ToList();
    }

    private void OnSelectionChange()
    {
        selected = GetChildrenRecursive(Selection.gameObjects).ToList();
        Repaint();
    }

    private void OnGUI()
    {
        EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
        GUILayout.FlexibleSpace();
        searchString = EditorGUILayout.TextField(searchString, EditorStyles.toolbarTextField);
        EditorGUILayout.EndHorizontal();

        // only as fallback
        if (selected == null)
        {
            selected = GetChildrenRecursive(Selection.gameObjects).ToList();
        }

        // Do comparison here. For example
        foreach (var selectedObject in selected)
        {
            if (selectedObject.name.Contains(searchString))
            {
                if (GUILayout.Button(selectedObject.name, EditorStyles.label))
                {
                    EditorGUIUtility.PingObject(selectedObject);
                }
            }
        }
    }

    private static IEnumerable<GameObject> GetChildrenRecursive(GameObject root)
    {
        var output = new List<GameObject>();

        //add the root object itself
        output.Add(root);

        // iterate over direct children
        foreach (Transform child in root.transform)
        {
            // add the children themselves
            output.Add(child.gameObject);

            var childsOfchild = GetChildrenRecursive(child.gameObject);
            output.AddRange(childsOfchild);
        }



        return output;
    }

    private static IEnumerable<GameObject> GetChildrenRecursive(IEnumerable<GameObject> rootObjects)
    {
        var output = new List<GameObject>();

        foreach (var root in rootObjects)
        {
            output.AddRange(GetChildrenRecursive(root));
        }

        // remove any duplicates that would e.g. appear if you select a parent and its child
        return output.Distinct();
    }
}

enter image description here