Сохранение строковых переменных в пользовательском EditorWindow при форматировании как TextArea - PullRequest
0 голосов
/ 25 марта 2020

По сути, я хочу выяснить, как я могу:

  1. Сохранить строковые (или любые) переменные в пользовательском окне редактора (наследуя от EditorWindow), когда они изменяются в этом окне. .
  2. Отображение строк в формате, подобном TextArea, при этом сохраняя возможность сохранения изменений, как указано выше.
  3. Отображение строк из массива строк по индексу вместо отдельных строк (у меня были проблемы с этим раньше)
  4. Если вы знаете, как выполнить вышеизложенное и в настраиваемом инспекторе (наследуя от Editor, а не EditorWindow), это тоже отлично.

Я сталкивался с этой проблемой несколько раз, когда различные классы наследовали от редактора, и ранее решались с помощью PropertyField, а не TextArea / TextField, но это избавляет от TextArea-стиль форматирования, который я хочу. Кроме того, классы, наследуемые от EditorWindow, по-видимому, не допускают его таким же образом (t = (script type)target; не работает, а PropertyField нуждается в этом) ..?

Я довольно новичок в пользовательских инспекторах, и это вещи, так что примеры кода будут очень полезны, если это возможно.

Спасибо!

1 Ответ

1 голос
/ 25 марта 2020

Прежде чем начать общее примечание, потому что вы упомянули его в своем вопросе:

По возможности, я настоятельно рекомендую вообще не использовать target! В частности, не устанавливайте поля напрямую. это делает такие вещи, как маркировка вашей сцены direty и, таким образом, сохранение изменений, а также функциональность Undo / Redo довольно сложной, поскольку вам придется реализовать ее самостоятельно!

Скорее всегда go - SerializedProperty в сочетании с SerializedObject.Update и SerializedObject.ApplyModifiedProperties (примеры будут приведены ниже). Это обрабатывает все такие вещи, как маркировка dirty и, таким образом, сохранение изменений сцены и автоматического отмены / возврата для вас!


Затем в TextArea.

Позволяет сказать у вас есть такой класс, как

public class Example : MonoBehaviour
{
    [SerializeField] private string _exampleString;
    public string AnotherExampleString;
}

В основном есть три основных варианта. Сначала я сделаю скрипт Editor (custom Inspector), так как вы немного более гибки.

Ниже будет EditorWindow.


Атрибут редактора [TextArea]

На самом деле вам даже не понадобится Editor скрипт вообще! Просто пометьте соответствующие поля как [TextArea] следующим образом:

public class Example : MonoBehaviour
{
    [SerializeField] [TextArea] private string _exampleString;
    // You can also directly configure the min and max line count here as well
    // By default it is 3 lines
    [TextAre(3,7)] public string AnotherExampleString;
}

Это уже выглядит следующим образом

enter image description here


EditorGUILayout.PropertyField

Затем Если Вам все еще нужен сценарий Editor, то хорошая вещь о EditorGUILayout.PropertyField автоматически использует правильный ящик для соответствующего типа ... и также применяет все атрибуты редактора ! Разве это не здорово?

Так просто иметь и Editor как

[CustomEditor(typeof(Example))]
public class ExampleEditor : Editor
{
    private SerializedProperty _exampleString;
    private SerializedProperty AnotherExampleString;

    private void OnEnable()
    {
        // Link in the serialized properties to their according fields
        _exampleString = serializedObject.FindProperty("_exampleString");
        AnotherExampleString = serializedObject.FindProperty("AnotherExampleString");
    }

    public override void OnInspectorGUI()
    {
        DrawScriptField();

        // load the real target values into the serialized properties
        serializedObject.Update();

        EditorGUILayout.PropertyField(_exampleString);
        EditorGUILayout.PropertyField(AnotherExampleString);

        // write back the changed properties into the real target
        serializedObject.ApplyModifiedProperties();
    }

    // Little bonus from my side so you have the script field on top
    private void DrawScriptField()
    {
        EditorGUI.BeginDisabledGroup(true);
        EditorGUILayout.ObjectField("Script", MonoScript.FromMonoBehaviour((Example)target), typeof(Example), false);
        EditorGUILayout.Space();
        EditorGUI.EndDisabledGroup();
    }
}

Результат выглядит в основном точно так же:

enter image description here

EditorGUILayout.TextField

Используя EditorGUILayout.TextArea, вы можете отобразить любой string как мульти текстовая область Это также относится к EditorWindow.

Скажем еще раз, что мы не пометили наши string поля

public class Example : MonoBehaviour
{
    [SerializeField] private string _exampleString;
    public string AnotherExampleString;
}

Но мы можем заставить их отображаться так же, как и до этого Editor script:

[CustomEditor(typeof(Example))]
public class ExampleEditor : Editor
{
    private SerializedProperty _exampleString;
    private SerializedProperty AnotherExampleString;

    private Vector2 scroll1;
    private Vector2 scroll2;

    private void OnEnable()
    {
        // Link in the serialized properties to their according fields
        _exampleString = serializedObject.FindProperty("_exampleString");
        AnotherExampleString = serializedObject.FindProperty("AnotherExampleString");
    }

    public override void OnInspectorGUI()
    {
        DrawScriptField();

        // load the real target values into the serialized properties
        serializedObject.Update();

        EditorGUILayout.PrefixLabel(_exampleString.displayName);
        scroll1 = EditorGUILayout.BeginScrollView(scroll1,GUILayout.MaxHeight(3 * EditorGUIUtility.singleLineHeight));
        _exampleString.stringValue = EditorGUILayout.TextArea(_exampleString.stringValue, EditorStyles.textArea);
        EditorGUILayout.EndScrollView();

        EditorGUILayout.PrefixLabel(AnotherExampleString.displayName);
        scroll2 = EditorGUILayout.BeginScrollView(scroll2, GUILayout.MaxHeight(7 * EditorGUIUtility.singleLineHeight));
        AnotherExampleString.stringValue = EditorGUILayout.TextArea(AnotherExampleString.stringValue);
        EditorGUILayout.EndScrollView();

        // write back the changed properties into the real target
        serializedObject.ApplyModifiedProperties();
    }

    // Little bonus from my side so you have the script field on top
    private void DrawScriptField()
    {
        EditorGUI.BeginDisabledGroup(true);
        EditorGUILayout.ObjectField("Script", MonoScript.FromMonoBehaviour((Example)target), typeof(Example), false);
        EditorGUILayout.Space();
        EditorGUI.EndDisabledGroup();
    }
}

Хотя вы можете видеть, что нам уже пришлось немного подделать его, используя дополнительные EditorGUILayout.BeginScrollView


Это то же самое, что вы можете также сделать в EditorWindow. В большинстве случаев не имеет смысла go - SerializedProperty для EditorWindow

public class ExampleWindow : EditorWindow
{
    private string exampleString;
    private Vector2 scroll;

    [MenuItem("Example/Show ExampleWindow")]
    private static void Initialize()
    {
        var window = GetWindow<ExampleWindow>();
        window.Show();
    }

    private void OnGUI()
    {
        EditorGUILayout.PrefixLabel("Example String");
        scroll = EditorGUILayout.BeginScrollView(scroll,GUILayout.MaxHeight(3 * EditorGUIUtility.singleLineHeight));
        exampleString = EditorGUILayout.TextArea(exampleString, EditorStyles.textArea);
        EditorGUILayout.EndScrollView();
    }
}

, что приводит к

enter image description here

...