在自定义 EditorWindow 中保存字符串变量,同时格式化为 TextArea
Saving string variables in a custom EditorWindow while formatted like a TextArea
基本上,我想弄清楚我该怎么做:
- 在自定义编辑器中保存字符串(或任何)变量window(继承
来自 EditorWindow) 当它们在 window.
中被更改时
- 以类似 TextArea 的格式显示字符串,同时仍然允许
如上所述保存更改。
- 按索引显示字符串数组中的字符串,而不是单独定义的字符串(我以前遇到过这个问题)
- 如果您也知道如何在自定义检查器中执行上述操作
(继承自 Editor,而非 EditorWindow),那也很棒。
我已经 运行 解决了这个问题几次,不同的 类 继承自编辑器,并且之前使用 PropertyField 而不是 TextArea/TextField 解决了这个问题,但现在已经解决了我想要的 TextArea 样式格式。
此外,从 EditorWindow 继承的 类 似乎不允许以相同的方式使用它(t = (script type)target;
不起作用,而 PropertyField 需要它)..?
我对自定义检查器和这些东西还很陌生,所以如果可能的话,代码示例会非常有用。
谢谢!
在开始一般性说明之前,因为您在问题中提到了它:
我强烈建议尽可能避免使用 target
!特别是不要直接设置任何字段。这使得诸如标记您的场景 direty 并因此保存更改和 Undo/Redo 功能变得非常复杂,因为您必须自己实现它!
而总是通过 SerializedProperty
combined with SerializedObject.Update
and SerializedObject.ApplyModifiedProperties
(示例将在下面)。这会处理所有这些东西,例如标记 dirty,从而自动为您保存场景更改和 Undo/Redo!
然后到TextArea。
假设您有一个 class 喜欢
public class Example : MonoBehaviour
{
[SerializeField] private string _exampleString;
public string AnotherExampleString;
}
基本上有三个主要选项。我将首先执行 Editor
(自定义检查器)脚本,因为您可以更灵活一些。
下面是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;
}
这看起来像这样
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();
}
}
结果看起来基本完全一样:
EditorGUILayout.TextField
使用 EditorGUILayout.TextArea
您可以将 any string
显示为多行文本区域。这也适用于 EditorWindow
.
再说一遍,我们没有标记 string
个字段
public class Example : MonoBehaviour
{
[SerializeField] private string _exampleString;
public string AnotherExampleString;
}
但是我们可以使用这个 Editor
脚本使它们像以前一样显示:
[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
中执行同样的操作。大多数时候,EditorWindow
通过 SerializedProperty
没有多大意义
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();
}
}
这导致
基本上,我想弄清楚我该怎么做:
- 在自定义编辑器中保存字符串(或任何)变量window(继承 来自 EditorWindow) 当它们在 window. 中被更改时
- 以类似 TextArea 的格式显示字符串,同时仍然允许 如上所述保存更改。
- 按索引显示字符串数组中的字符串,而不是单独定义的字符串(我以前遇到过这个问题)
- 如果您也知道如何在自定义检查器中执行上述操作 (继承自 Editor,而非 EditorWindow),那也很棒。
我已经 运行 解决了这个问题几次,不同的 类 继承自编辑器,并且之前使用 PropertyField 而不是 TextArea/TextField 解决了这个问题,但现在已经解决了我想要的 TextArea 样式格式。
此外,从 EditorWindow 继承的 类 似乎不允许以相同的方式使用它(t = (script type)target;
不起作用,而 PropertyField 需要它)..?
我对自定义检查器和这些东西还很陌生,所以如果可能的话,代码示例会非常有用。
谢谢!
在开始一般性说明之前,因为您在问题中提到了它:
我强烈建议尽可能避免使用 target
!特别是不要直接设置任何字段。这使得诸如标记您的场景 direty 并因此保存更改和 Undo/Redo 功能变得非常复杂,因为您必须自己实现它!
而总是通过 SerializedProperty
combined with SerializedObject.Update
and SerializedObject.ApplyModifiedProperties
(示例将在下面)。这会处理所有这些东西,例如标记 dirty,从而自动为您保存场景更改和 Undo/Redo!
然后到TextArea。
假设您有一个 class 喜欢
public class Example : MonoBehaviour
{
[SerializeField] private string _exampleString;
public string AnotherExampleString;
}
基本上有三个主要选项。我将首先执行 Editor
(自定义检查器)脚本,因为您可以更灵活一些。
下面是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;
}
这看起来像这样
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();
}
}
结果看起来基本完全一样:
EditorGUILayout.TextField
使用 EditorGUILayout.TextArea
您可以将 any string
显示为多行文本区域。这也适用于 EditorWindow
.
再说一遍,我们没有标记 string
个字段
public class Example : MonoBehaviour
{
[SerializeField] private string _exampleString;
public string AnotherExampleString;
}
但是我们可以使用这个 Editor
脚本使它们像以前一样显示:
[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
中执行同样的操作。大多数时候,EditorWindow
SerializedProperty
没有多大意义
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();
}
}
这导致