一、EditorWindow是什麼?
EditorWindow是Unity引擎中的一個可自定義彈出窗口,可以用來作為拓展編輯器界面的工具。在Window菜單下可以找到自定義的EditorWindow。
相對於Inspector面板,EditorWindow提供了更高自由度的自定義操作。一個EditorWindow可以用來做各種各樣的編輯器任務,包括顯示自定義UI、手動讓用戶輸入信息以及執行多步驟的編輯和操作。
下面是一個快速的EditorWindow例子。
using UnityEngine;
using UnityEditor;
public class ExampleEditorWindow : EditorWindow
{
string myString = "Hello, World!";
[MenuItem("Window/Example")]
public static void ShowWindow()
{
EditorWindow.GetWindow("Example");
}
private void OnGUI()
{
GUILayout.Label("This is an example EditorWindow", EditorStyles.boldLabel);
myString = EditorGUILayout.TextField("Text Field", myString);
if (GUILayout.Button("Say Hello"))
{
Debug.Log(myString);
}
}
}
二、EditorWindow分類
在Unity中,通常情況下,可以根據窗口的打開方式對EditorWindow進行分類。
1. 手動打開窗口
手動打開窗口方式是就是通過Unity Editor菜單中的Window選項進行打開。通過在EditorWindow腳本中添加MenuItem特性,可以將自己構建的EditorWindow添加到Window菜單中。示例代碼中,通過添加MenuItem特性將ExampleEditorWindow添加到Window菜單中。
[MenuItem("Window/Example")]
public static void ShowWindow()
{
EditorWindow.GetWindow("Example");
}
2. 在特定場合打開窗口
除以上的手動打開窗口之外,還有一些特定場合下會自動打開窗口。例如通過組合鍵打開FirstPassProfiler窗口,或者是添加此類代碼:
[UnityEditor.Callbacks.OnOpenAssetAttribute(1)]
public static bool OpenAsset(int instanceID, int line)
{
Object obj = EditorUtility.InstanceIDToObject(instanceID);
if (instanceID != 0 && obj is GameObject)
{
var window = EditorWindow.GetWindow(typeof(ExampleEditorWindow));
window.Show();
return true;
}
return false; // let the system open the asset
}
三、常用EditorWindow API
1. public static T GetWindow(string title, [Type type], [bool utility]);
表示根據類型T或者類型type來查找已經打開的EditorWindow實例,如果沒有找到就創建一個新的並返回。
ExampleEditorWindow window = (ExampleEditorWindow)EditorWindow.GetWindow(typeof(ExampleEditorWindow));
2. public void Focus();
表示將窗口設置為焦點,在用戶輸入時將不會和Inspector或其他窗口爭奪焦點。
void OnEnable() {
EditorWindow.GetWindow(「 」).Focus ();
}
3. public object GetService(Type serviceType);
獲取EditorWindow所依賴的接口或對象。
public void OnGUI()
{
if (Selection.activeObject)
assetPath = AssetDatabase.GetAssetPath(Selection.activeObject.GetInstanceID());
else
assetPath = "";
EditorGUI.TextField(new Rect(3, 3, position.width - 6, 20), "Selected Asset:", assetPath);
IPreviewWrapper preview = (IPreviewWrapper)this.GetService(typeof(IPreviewWrapper));
}
4. public void ShowUtility();
表示打開一個工具窗口,不會在任何任何面板標籤之間顯示,並且不會在場景視圖上出現背景遮罩。
[MenuItem("Window/Example")]
static void Open()
{
ExampleWindow window = CreateInstance<ExampleWindow>();
window.ShowUtility();
}
5. 處理Event事件
在EditorWindow子類中,可以通過繼承於OnGUI函數的Event類,實現處理一些常用Event事件,例如鍵盤事件和鼠標移動事件。
void OnGUI()
{
if (Event.current.type == EventType.KeyDown)
{
Debug.Log("Detected key code: " + Event.current.keyCode);
}
}
四、常見UI控件使用
EditorWindow中使用一些常見的UI控件方式和在普通的GUI界面中幾乎一樣,主要是利用EditorGUILayout函數、GUILayout函數和GUILayoutOption類作為參數來構建UI。
1. GUILayout.Label(string text, params GUILayoutOption[] options);
表示創建一個標籤。
void OnGUI()
{
GUILayout.Label("這是一個標籤",GUILayout.Width(100));
}
2. GUILayout.Button(Texture image, [style], [options]);
創建一個按鈕。
void OnGUI()
{
if (GUILayout.Button("按鈕"))
Debug.Log("按鈕被點擊");
}
3. GUILayout.TextField(string text, [style], [options]);
創建一個可編輯的單行文本控件。
void OnGUI()
{
myString = GUILayout.TextField(myString, 25);
}
4. GUILayout.TextArea(string text, [options]);
創建一個可編輯的多行文本控件。
void OnGUI()
{
myString = EditorGUILayout.TextArea(myString);
}
5. GUILayout.HorizontalSlider(float value, float leftValue, float rightValue, [style], [slider], [thumb], [options]);
創建一個水平的滑動條。
void OnGUI()
{
sliderValue = GUILayout.HorizontalSlider(sliderValue, 0.0f, 10.0f);
}
五、EditorWindow Best Practices
1. 記得手動釋放EditorWindow對象和資源
EditorWindow需要手動釋放對象和資源,雖然在EditorWindow關閉時,資源和內存會被自動清理,但是最好手動釋放防止內存泄漏。
void OnDestroy(){
if (textureX && !EditorUtility.IsPersistent(textureX))
DestroyImmediate(textureX, false);
}
2. 需要並發運行的編寫
由於EditorWindow可能會被並發顯示,因此,對於全局數據或變量,需要加鎖處理,應該注意防止資源競爭和線程安全!
static void ButtonCallBack() {
Debug.Log("Button " + TextB);
}
private void OnGUI() {
GUILayout.Label("Enter Text : ", EditorStyles.boldLabel);
TextA = GUILayout.TextField(TextA);
TextB = GUILayout.TextField(TextB);
if(GUILayout.Button("Get Text From button")) {
showText = TextA;
EditorApplication.delayCall += ButtonCallBack;
}
GUILayout.Label("Show Text : "+showText, EditorStyles.boldLabel);
}
3. 對空引用空引用的判斷
在EditorWindow中,如果需要引用Unity Editor中的一個GameObject,可以在OnDestroy函數中判斷空引用並進行釋放。
private void OnDestroy()
{
if (m_mesh != null)
GameObject.DestroyImmediate(m_mesh);
}
六、結語
本文從EditorWindow基本介紹,EditorWindow分類,常用API,常見UI控件及其最佳實踐進行了詳細分析。EditorWindow的擴展性給編程帶來了全新的廣闊空間和發展方向,可以用其優秀的自由度、靈活性和多樣性不斷構建自己的實用工具。
原創文章,作者:KMQKJ,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/370986.html