Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question EditorWindow initialization?

Discussion in 'Scripting' started by Noblauch, Feb 23, 2021.

  1. Noblauch

    Noblauch

    Joined:
    May 23, 2017
    Posts:
    256
    I'm always running into issues with editor windows. How to properly manage their life cycle?
    We have these three methods:


    [MenuItem("Window/My Window")]
    ShowWindow()
    Awake()
    OnEnable()


    ShowWindow() is only called if the window is opened via the menu, so this is not usable to initialize the window.

    Awake() is also only called if the window is opened or unity is launched with this window open. So this is better but still not usable.

    Last: OnEnable() this is als called after recompile. As we know windows lose their S*** when recompiling, so I always need to reinitialize everything. But still, this doesn't seem to work as expected.
    Example:
    Code (CSharp):
    1.         private static DisplayUnit _displayUnit;
    2.         private void OnEnable()
    3.         {
    4.             _displayUnit = new DisplayUnit();
    5.         }
    6.  
    7.         private void OnGUI()
    8.         {
    9.             _displayUnit.OnGUI();
    10.         }
    This will work the first time the window is opened, but after code changes and a recompile the window is broken and I get spammed with null pointers. I usually implement some kind of delay and reinitialize inside an async tasks or jokes like that.

    But there must be a correct way, how do you do it?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,753
    Since most editor-ish-thingy-windows are driven from OnGUI or OnInspectorGUI, I usually just put the check at the beginning of those functions.

    You could even wrap it all up in an
    InitializeIfNeeded()
    method, then you could just call that at the start of any method (such as OnGUI()) to make sure you have everything operating.
     
    Noblauch likes this.
  3. simiel7

    simiel7

    Joined:
    Dec 18, 2020
    Posts:
    7
    What worked for me is putting the Window related setup into the ShowWindow, like window size, title, icon, etc. and Show() call that will opens up the window.
    OnEnable holds every initialization that needs to be done, list initialization, tabs, etc. that mostly data related.
    OnGUI holds the layout BeginHorizontal, Space, Toolbar, Button, Label, and so on. And because it does not hold any data related info, only the GUI, it can be called in every frame without any problem.


    What helped me a lot is to checking how Unity do it.
    Search for a good reference, for example LightingWindow in https://github.com/Unity-Technologi...ditor/Mono/SceneModeWindows/LightingWindow.cs.
    And in the Editor you can find this window in Window > Rendering > Lighting.

    You can also check out the License for Unity here, if it matters to you.
    https://unity3d.com/legal/licenses/Unity_Reference_Only_License
     
  4. Noblauch

    Noblauch

    Joined:
    May 23, 2017
    Posts:
    256
    Thanks for your insight. I actually did that somewhere I think. I'm just starting a new window and used you method now, I don't really like it, but its very stable, which in contrast I really like :p

    Nice sources, thanks! Going to look into it ;)
     
    Kurt-Dekker likes this.
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,528
    I'm not sure why you think OnEnable is unreliable? EditorWindows are just ScriptableObjects (the EditorWindow class is actually derived from ScriptableObject) and OnEnable is called when the object is created or recreated / loaded again.

    Note that during an assembly reload, Unity will actually serialize and restore even private variables as long as the type of the variable is serializable. So depending on what kind of data you have "stored" in your EditorWindow instance you may not need to reinitialize it at all.

    Generally you would just use field initializers or Awake to initialize variables that can be serialized by Unity. That way the fields should be initialized properly when the window is loaded (after a restart of the Unity editor or after opening your window). You can use OnEnable / OnDisable for things that can not be serialized.

    Do you have a concrete example where you got a null reference exception after an assembly reload?
     
  6. Noblauch

    Noblauch

    Joined:
    May 23, 2017
    Posts:
    256
    Interesting. So adding [SerializedField] attributes on my references would keep the data from the first awake until the editor window is closed?

    Well the code snippet from my original post up there gives me null pointers, after recompiling code. I separated multiple editor windows into one, and just instantiate their content as normal classes there, and call their OnGui() methods in the master window. Even this simple reference causes this. And yes, the null pointer comes from _displayUnit being null.
     
  7. Surreal

    Surreal

    Joined:
    Dec 10, 2011
    Posts:
    29
    Having a really hard time doing something that appears to be simple -- updating an Editor Window label's GUIContent

    We're generating several docked windows together -- and want to highlight the one that's currently chosen. Touching one of the tabs (like dragging it a bit) -- repaints the row of tabs and achieves the desired affect. But there seems to be no programmatic way to get Unity to repaint the tab -- not using focus, not using repaint (which updates the insides but not the tab, not using OnGui or Update or anything else I've tried so far -- almost to the point of writing a script to generate a pseudo drag using mouse events)