UnityEditor研究學習之EditorWindow


在unity使用過程中,其實我們都是在各個不同功能的Window下工作。

比如在Scene窗口中操作物體,在Inspector中操作物體屬性,在Game視窗中觀察游戲狀態。

 

所以窗口是Unity的靈魂,這是唯一接口我們能夠通過它來制作游戲。

 

那么,我們想自定義一個自己的窗口,那該如何呢?今天我們就來學習下EditorWindow,由於這個類在UnityEdior下,所以要using UnityEditor;

 

using UnityEngine;
using System.Collections;
using UnityEditor;//注意要引用
public class MyWindow: EditorWindow
{
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        MyWindow myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", true);//創建窗口
        myWindow.Show();//展示
    }
}

 

這是個簡單的創建窗口的代碼,首先通過EditorWindow.GetWindow來取得窗口實例,然后展現,我們來看看官方的API說明。

 

GetWindow是個靜態方法,有三個參數:

第一個參數是窗口類型,注意是一定要繼承自EditorWindow。

第二個參數是窗口是否浮動,如果是就不能內嵌到unity其他窗口中去,如果不是就能嵌入其他窗口。(可以省略,默認為內嵌入式)

第三個參數是窗口的標題,如果為空的話就采用類的名稱來當標題。(可以省略,默認類的名稱)

 

可以看到第一個參數是必須的,其他參數可以省略。c#可選參數的特性。

 

回到Unity,在Window菜單下拉列表選擇MyWindow,可以看到彈出自己的窗口。好開心!

 

 

當然這個窗口里面什么東西都沒有,我們需要往里面添加各個功能組件,當然這個以后再慢慢詳談,貌似好像如飢似渴了!!=_=

 

接着,下面我們來學習下EditorWindow的各個屬性和方法:

fousedWindow(靜態變量):

注意到類型是EditorWindow,所以顧名思義這個是表示當我們聚焦到哪個窗口,那么這個靜態變量就是那個窗口。其實也就是記錄我們聚焦的窗口。

 

於是我做了個小實驗,功能也就是聚焦哪個窗口會打印這個窗口的信息。

void OnGUI()
    {
        EditorGUILayout.LabelField(EditorWindow.focusedWindow.ToString());
    }

 

 

 

mouseOverWindow(靜態變量):

 

與fouseWindow相似,這個是鼠標懸停在哪個Window,這個靜態變量就是那個窗口。

 

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    string move;
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        MyWindow myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show(true);
    }
    void OnGUI()
    {
        move = EditorWindow.mouseOverWindow ? EditorWindow.mouseOverWindow.ToString() : "Nothing";
        EditorGUILayout.LabelField(move);
    }
    void OnInspectorUpdate()
    {
        if (EditorWindow.mouseOverWindow)
            EditorWindow.mouseOverWindow.Focus();//就是當鼠標移到那個窗口,這個窗口就自動聚焦
        this.Repaint();//重畫MyWindow窗口,更新Label
    }
}

於是我又做了個小測試,功能很簡單,鼠標移動的哪個窗口,在MyWindow打印那個窗口的信息,並且自動聚焦到那個窗口。

反正我是成功了,你們可以自行測試。

 

EditorWindow.autoRepaintOnSceneChange

當這個變量為true時,如果unity編輯視窗(注意不只是scene視窗,其他窗口)只要有變動,就會重畫窗口,為false就不會。

當然我們做個小測試:

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    int i = 0;
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        MyWindow myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.autoRepaintOnSceneChange = true;
        myWindow.Show(true);
    }
    void OnGUI()
    {
        i++;
        EditorGUILayout.LabelField(i.ToString());
    }
}

這段代碼就是當我們變動unity編輯器時,label就會顯示i自增。

 

 

 

EditorWindow.maximized

 

 

當為true,就是當窗口是內嵌到其他窗口,也就是docked停靠的意思,窗口就能最大化。開上面,他說如果窗口沒有在停靠狀態,那么這個值永遠為false,並且設置無效。

 

測試的話,我們可以用toggle來改變這個bool值。

 

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        MyWindow myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.autoRepaintOnSceneChange = true;
        myWindow.Show(true);
    }
    void OnGUI()
    {
        maximized = EditorGUILayout.ToggleLeft("Max",maximized);
    }
}

  注意一定要是內嵌的狀態下,那么會觀察到點擊Max會最大化,再次點擊會回到原來。

 

maxSize,minSize,position這里我就不詳細介紹了,自己可以去改變着玩玩。

 

EditorWindow.titleContent

 這個變量是設置窗口的小圖標的,圖標的類型為GUIContent。

我們再來順便學習下GUIContent,看看他的API。

GUIContent.GUIContent

這里我們只看他的構造函數,因為我們只想要圖標,所以我們選擇public GUIContent(Texture image);這個構造函數

 

不知為何,unity現在沒有titleContent這個變量,那么我們也就不要管他了,影響不是很大。

EditorWindow.wantsMouseMove

也就是設置這個變量為true的時候,這個窗口會接收OnGUI里面的鼠標在窗口上面移動的事件。我們來測試一下:

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    static MyWindow myWindow;
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show(true);
    }
    void OnEnable()
    {
       
    }
    void OnGUI()
    {
        wantsMouseMove = EditorGUILayout.Toggle("receive mouseMove:", wantsMouseMove);//是否啟用接收鼠標移動事件監聽
        EditorGUILayout.LabelField("Mouse Position:", Event.current.mousePosition.ToString());
        if (Event.current.type == EventType.mouseMove && wantsMouseMove)//如果是鼠標移動的事件,就重畫窗口
        {                                              ///因為上面注意那里有講到:他不會自動調用repaint()方法
            Repaint();
        }
    }

 運行項目,可以看到,當勾選了recevive mouseMove選項后,label會實時更新鼠標的坐標。

 

--------------------------------------------------------------------------分隔符-------------------------------------------------------------------------------------------------------

講完了EditorWindow的所有變量之后,接下來我們來學習下他的一些有用的方法。

 

 

1.EditorWindow.BeginWindows

顧名思義,函數名為beginWindows,也就是說從這里開始會創建窗口。咦?這里有些童鞋有些疑惑了。EditorWindow本身就是個窗口,這里又有窗口。

 

那就好玩了,對的。其實也就是窗口中嵌入窗口,就跟我們game視窗,在OnGUI()里面,創建窗口是一個道理。

 

這里是EditorWindow中創建Gui.window,具體如上圖所示。

 

這個函數他是需要和EndWindows()配合使用,也就是begin之后必須要End。

 

具體可以看官方說明:他說GUI.Window內嵌game和editor視窗中表現有所不同。在game中GUI.Window是從你的屏幕中彈出,而在Editor中則是成為你editorwindow的子窗口。

 

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    static MyWindow myWindow;
    public Rect windowRect = new Rect(0, 0, 200, 200);//子窗口的大小和位置
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show(true);
    }
    void OnEnable()
    {
       
    }
    void OnGUI()
    {
        BeginWindows();//標記開始區域所有彈出式窗口
        windowRect = GUILayout.Window(1, windowRect, DoWindow, "子窗口");//創建內聯窗口,參數分別為id,大小位置,創建子窗口的組件的函數,標題
        EndWindows();//標記結束
    }
    void DoWindow(int unusedWindowID)
    {
        GUILayout.Button("按鈕");//創建button
        GUI.DragWindow();//畫出子窗口
    }
}

運行后,可以看到效果,並且這個窗口是可以移動的。

 OK,貌似很久沒有更新這篇博客,現在回過頭重新來學習下。

前面我們講到EditorWindow的BeginWindow開始子窗口的編寫,接着我們來看下他的Close()方法。

這個應該是十分簡單,就是我們呢調用Close()的時候,我們創建的窗體就銷毀。在官方API中這樣解釋的:

我們做下簡單的測試:

 

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    static MyWindow myWindow;
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show();
    }
    void OnEnable()
    {
       
    }
    void OnGUI()
    {
        if (GUILayout.Button("關閉窗口"))
        {
            myWindow.Close();
        }
    }
}

 

  就是我們點擊窗體里面的關閉窗體按鈕的時候,就調用close方法,然后我們創建的窗體就銷毀消失了。

OK,接着我們看下其他方法:

 

EditorWindow.Focus

 

窗體聚焦方法,也就是說調用這個方法,就自動聚焦到該窗體。

那么我們也來做個小實驗:

 

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    static MyWindow myWindow;
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show();
    }
    void OnEnable()
    {
       
    }
    void OnGUI()
    {
        EditorGUILayout.LabelField("聚焦窗體名字:"+EditorWindow.focusedWindow.ToString());
    }
    [MenuItem("Custom Editor/Focus Window")]
    static void FocusWindow()
    {
        myWindow.Focus();
    }  
}

也就是我們點擊Custom Editor菜單下面的Focus Window就會聚焦窗體到自己創建的窗體,然后利用EditorWindow的靜態FoursedWindow變量取得,打印在label中。

接着看下個方法:

 

EditorWindow.ShowNotification

 

這個方法是顯示消息提示的方法,我們看下官方的API解釋:

 

做事必須得親自動手試下才能明白他的原理,這里我們編寫下程序實驗下:

 

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    static MyWindow myWindow;
    string m_notification = "我是消息內容";
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show();
    }
    void OnEnable()
    {
       
    }
    void OnGUI()
    {
        m_notification = EditorGUILayout.TextField(m_notification);
        if (GUILayout.Button("顯示消息"))
        {
            myWindow.ShowNotification(new GUIContent(m_notification));
        }
        if (GUILayout.Button("不顯示消息"))
        {
            myWindow.RemoveNotification();
        }
    }
}

下個方法:

 

EditorWindow.SendEvent

 

這個方法就是傳遞事件的方法,什么意思,也就是說比如你想在Hierarchy窗口粘貼要復制的Cube,那么這個粘貼他是一個事件,那么正常我們是用鼠標操作粘貼,如果我們想要用代碼控制,就得使用該方法,直接傳遞粘貼事件給Hierarchy窗口就行了。

具體看下官方的解釋:

那么我們先要知道粘貼事件:

 

EditorGUIUtility.CommandEvent("Paste")

這個方法是通過事件名字取得事件,OK,我們來寫下代碼:

 

using UnityEngine;
using System.Collections;
using UnityEditor;
public class MyWindow: EditorWindow
{
    static MyWindow myWindow;
    [MenuItem("Window/MyWindow")]//在unity菜單Window下有MyWindow選項
    static void Init()
    {
        myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show();
    }
    void OnEnable()
    {
       
    }
    void OnGUI()
    {
        if (EditorWindow.focusedWindow.ToString().Trim() == "(UnityEditor.SceneHierarchyWindow)")
        {
            EditorWindow.focusedWindow.SendEvent(EditorGUIUtility.CommandEvent("Paste"));//傳遞粘貼的事件
        }
    }
}

 

  

 

這段代碼就是如果聚焦的窗口是Hierarchy窗口的話,那么就傳遞粘貼事件給Hierarchy窗口。

所以我們事先復制一個cube,點擊Asset/Copy。然后打開我們的MyWindow,然后點擊Cube,就會發現神奇的事情:

感覺篇幅有點過長,下節繼續。。。。。未完待續

ok,繼續回來,時隔這么久,先自己都快忘記了差不多,只能看之前自己寫的。

 

 

EditorWindow.OnHierarchyChange()

 

這個方法是當Hierarchy視窗改變的時候,會執行這個方法的邏輯。

 

那么什么時候Hierarchy視窗會改變呢?官方的解釋是這樣的:

 

Description

Called whenever the scene hierarchy has changed.

 

This is transform.parent changed, gameObject.name, creating a new game object, etc.

 

當Transform組件參數改變的時候,這里注意下你在視窗Scene中拖動坐標軸是不會監聽到,只有在Inspector視窗中手動改Transform的值才發生監聽

還有GameObject的名稱改變會有觸發事件監聽,還有創建,刪除,粘貼等等操作,都會被監聽到。

寫個小例子測試下:

 

using UnityEngine;
using UnityEditor;
using System.Collections;

public class MyWindow : EditorWindow
{
    static EditorWindow myWindow;
    [MenuItem("Window/MyWindow")]
    static void Init()
    {
        myWindow = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow), false, "MyWindow", false);
        myWindow.Show();
    }
    void OnHierarchyChange()
    {
        Debug.Log("Sync");
    }
} 

 

可以看到我創建和刪除都監聽到。

 

 

EditorWindow.OnProjectChange()

 

這個方法和上述類似,是Project視窗發生改變的時候,會執行該方法。

 

什么時候發生監聽,官方的解釋是:

 

Description

Called whenever the project has changed.

 

Typically after import, file moves, etc.

 

比如說導入文件,移動文件,等等,當然包括刪除文件。

這里我就不演示了,和上述類似。

 

 

EditorWindow.OnSelectionChange()

 

這個方法是當你選擇的物件發生變化(包括Scene,Project和Hierarchy視窗)的時候會執行該方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM