TextArea does not work text dissapears. Solution is provided.

***NOTICE: This post was being written as I was still trying to get the example code to behave properly. I’m posting it anyway for future Unity newbs like my self so maybe it will save them some brain cells. The initial post is inside the -BEGIN- -END- marks. After the -END- mark I have written down my thoughts about unity in general and the solution to my own problem for posterity’s sake. ***


-BEGIN-

I’m getting aggravated at unity’s wacky way of doing things related to gui coding.

I’m using unity (free) 3.5.1f2, and I am still a newb to unity as I have just begun to start working with it. I’m coming into unity as a programmer. I’ve listed my test code below.

Here is the problem. Add the code to your unity project. You should have a new Menu item “CBX” select “testwin” from the drop down and you get the test window. No problem so far. Now type some text into the TextArea control and click in a scene view or anywhere in unity so that the testwin window losses focus. POOF! The text in the TextArea control disappears. WTH? Now click back on the testwin window and presto the text you typed into the TextArea control is now displayed again. ?!?!

To make matters worse type text into the TextArea and drag the testwin tab and doc it to another unity window. Brzzzt! All text in the TextArea control is gone!

This is driving me insane trying to track down just what the heck is going on here. I can’t even get simple things like make a single window with a TextArea in it to work.

To make matters worse and even more confrusing! Change the line of code from …

private string scriptText = string.Empty;

… to …

private string scriptText;

Now repeat the steps of typing text into the TextArea control and clicking the window and clicking out of the window. But be sure to have unity’s console window visible while doing this. You will see the TextArea control visible and being created when the window does not have focus (No console errors when unfocused). And when the testwin window is focused you get errors in the console ala …

NullReferenceException: Object reference not set to an instance of an object
UnityEngine.TextEditor.ClampPos () (at C:/BuildAgent/work/b0bcff80449a48aa/Runtime/Export/TextEditor.cs:1144)
UnityEditor.EditorGUI.DoTextField (UnityEditor.RecycledTextEditor editor, Int32 id, Rect position, System.String text, UnityEngine.GUIStyle style, System.String allowedletters, System.Boolean& changed, Boolean reset, Boolean multiline, Boolean passwordField) (at C:/BuildAgent/work/b0bcff80449a48aa/Editor/MonoGenerated/Editor/EditorGUI.cs:353)
UnityEditor.EditorGUI.TextArea (Rect position, System.String text, UnityEngine.GUIStyle style) (at C:/BuildAgent/work/b0bcff80449a48aa/Editor/MonoGenerated/Editor/EditorGUI.cs:927)
UnityEditor.EditorGUILayout.TextArea (System.String text, UnityEngine.GUIStyle style, UnityEngine.GUILayoutOption[] options) (at C:/BuildAgent/work/b0bcff80449a48aa/Editor/MonoGenerated/Editor/EditorGUI.cs:3302)
UnityEditor.EditorGUILayout.TextArea (System.String text, UnityEngine.GUILayoutOption[] options) (at C:/BuildAgent/work/b0bcff80449a48aa/Editor/MonoGenerated/Editor/EditorGUI.cs:3299)
TestWindow.OnGUI () (at Assets/Editor/CBX.Unity.Editors/TestWindow.cs:22)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

Again flabbergasting. Why throw out console errors when the window is focused but not when un-focused. It clearly appears to be working when un-focused as the TextArea is being created and displayed! /frown


 using UnityEngine;
using UnityEditor;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

public class TestWindow : EditorWindow
{

    // script text
    private string scriptText = string.Empty;
    
    // position of scroll view
    private Vector2 scrollPos;
 
    void OnGUI()
    {
		// start the scroll view
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);

        // show the script field
        EditorGUILayout.TextArea(this.scriptText);
        
        // close the scroll view
        EditorGUILayout.EndScrollView(); 
    }

    [MenuItem("CBX/testwin")]
    static void Init()
    {
        // get the window, show it, and hand it focus
        try
        {
			var window = EditorWindow.GetWindow<TestWindow>();
            window.title = "testwin";
            window.Show();
            window.Focus();
			window.Repaint();
        }
        catch (System.Exception ex)
        {
            Debug.LogError(ex.Message);
        }
    } 
}

-END-

So. What seems to be the magical solution to this problem? Change line …

EditorGUILayout.TextArea(this.scriptText);

… to read …

this.scriptText = EditorGUILayout.TextArea(this.scriptText);

… somehow this seems to work.

At the time of this writing I still don’t quite grasp what difference it makes performing that change.

During this 2+ hour long battle royal with unity’s gui coding style and searching around the net as usual I ended up solving my own problem. During this time a few four letter words were uttered.

Off the top of my head I can’t recall using a gui system like unity’s going back to Borlands Turbo Pascal Turbo Vision for DOS! Every gui system I’ve used over my programming history has been object based. There is a structure too them. There typically object based with numerous properties/methods/events on them. This is true of XAML, .NET winform controls, even asp.net etc, MVVM patterns etc.

Why unity decided to go this route, … sigh … I kind of understand the abstraction aspect that unity seems to try and achieve, but clearly it has thrown me for a loop. I’ve been conditioned to expect a certain structure and pattern when working with gui systems. And I find unity’s departure from this historical pattern questionable.

If you just had read this page, you wouldn’t have lost your time.

Back to the design choice. This way provides more flexibility and is less prone to unfortunate side-effects.

Firstly, in C# to pass a reference to a value-type, you need the ref keyword. But this keyword cannot be used with properties. Therefore a strict object version would not allow the use of properties.

Secondly, this allows you to check the value (and even process it) before actually changing the target variable. Think of this:

float newFloat = EditorGUILayout.FloatField( myClass.floatField );
if( CheckValue( newFloat) )
{
    myClass.floatField = newFloat;
}

Thus more flexibility.