Getting control 0's position in a group with only 0 controls when doing Repaint

why i am getting this here
can anyone help? ty

using UnityEngine;
using UnityEditor;
using System.IO;


public class UserViewer : EditorWindow {

    [MenuItem("Window/UserViewer")]
    public static void OpenEditor()
    {
        GetWindow<UserViewer>("UserViewer", true);
    }

    [SerializeField]
    private UsersData usersData = null;
    [SerializeField]
    private int numberOfUsers;
    [SerializeField]
    private int numberOfUsersToShow;
    [SerializeField]
    private int id;
    [SerializeField]
    private int index;
    [SerializeField]
    private string[] acountNames;
    [SerializeField]
    private string activeAcountInfo;
    [SerializeField]
    private static bool _isUserInfoDone = false;

    void OnGUI()
    {
       if(usersData == null)
        {
                Init();
        }
        else
        {
            if (_isUserInfoDone == false)
            {
                GetUserInfos();
                _isUserInfoDone = true;
            }
            MakeUserSelection();
            if (GUILayout.Button("Show Selected User"))
            {
                DisplayUsers(numberOfUsersToShow);
            }
            if (GUILayout.Button("Close"))
                Close();
            if (GUI.changed)
                EditorUtility.SetDirty(usersData);
        }
    }

    public void MakeUserSelection()
    {
        EditorGUILayout.LabelField("User Selection");
        numberOfUsers = usersData.userInfos.Count;
        EditorGUILayout.TextField("Total Users Count", numberOfUsers.ToString());
        index = EditorGUILayout.Popup(index, acountNames);
        numberOfUsersToShow = index;
        EditorGUILayout.LabelField("Acount Info");
        activeAcountInfo = EditorGUILayout.TextField(usersData.userInfos[numberOfUsersToShow].userRFirstName + " - " + usersData.userInfos[numberOfUsersToShow].userRLastName + "    Email :" + usersData.userInfos[numberOfUsersToShow].userEmail + "    Coins :" + usersData.userInfos[numberOfUsersToShow].userCoins);
    }



    public void Init()
    {
        usersData = ScriptableObject.CreateInstance<UsersData>();
        if (!Directory.Exists(Application.dataPath + Path.DirectorySeparatorChar + "Resources"))
            AssetDatabase.CreateFolder("Assets", "Resources");
        if(File.Exists(Application.dataPath + Path.DirectorySeparatorChar + "Resources" + Path.DirectorySeparatorChar + "Users.asset"))
        {
            usersData = AssetDatabase.LoadAssetAtPath("Assets/Resources/Users.asset", typeof(UsersData)) as UsersData;
        }
        else
        {
            AssetDatabase.CreateAsset(usersData, "Assets/Resources/Users.asset");
            AssetDatabase.SaveAssets();
        }
    }

    void GetUserInfos()
    {
        acountNames = new string[numberOfUsers];
        for (int i = 0; i < numberOfUsers; i++)
        {
            acountNames = usersData.userInfos.userID.ToString() + " : " + usersData.userInfos.userAlias;
        }
    }

    public void DisplayUsers(int i)
    {
        EditorGUILayout.BeginVertical();
        index = EditorGUILayout.Popup(index, acountNames);
        numberOfUsersToShow = index;
        usersData.userInfos.userAlias = EditorGUILayout.TextField("User Acount Name", usersData.userInfos.userAlias);
        usersData.userInfos.userAvatar = (Texture2D)EditorGUILayout.ObjectField("Avatar", usersData.userInfos.userAvatar, typeof(Texture2D), false);
        EditorGUILayout.LabelField("Color");
        usersData.userInfos.userColor = EditorGUILayout.ColorField(usersData.userInfos.userColor);
        EditorGUILayout.LabelField("Coins");
        usersData.userInfos.userCoins = EditorGUILayout.IntField(usersData.userInfos.userCoins);
        EditorGUILayout.LabelField("Acount is Active");
        usersData.userInfos.userActive = EditorGUILayout.Toggle(usersData.userInfos.userActive);
        EditorGUILayout.LabelField("Rank");
        usersData.userInfos.userRank = EditorGUILayout.IntField(usersData.userInfos.userRank);
        EditorGUILayout.LabelField("Real Balance");
        usersData.userInfos.userBalance = EditorGUILayout.FloatField(usersData.userInfos.userBalance);
        EditorGUILayout.LabelField("User Details");
        usersData.userInfos.userRFirstName = EditorGUILayout.TextField("First Name", usersData.userInfos.userRFirstName);
        usersData.userInfos.userRMiddleName = EditorGUILayout.TextField("Middle Name", usersData.userInfos.userRMiddleName);
        usersData.userInfos.userRLastName = EditorGUILayout.TextField("Last Name", usersData.userInfos.userRLastName);
        usersData.userInfos.userAddress1 = EditorGUILayout.TextField("Address 1", usersData.userInfos.userAddress1);
        usersData.userInfos.userAddress2 = EditorGUILayout.TextField("Address 2", usersData.userInfos.userAddress2);
        usersData.userInfos.userCity = EditorGUILayout.TextField("City", usersData.userInfos.userCity);
        usersData.userInfos.userState = EditorGUILayout.TextField("State", usersData.userInfos.userState);
        usersData.userInfos.userCountry = EditorGUILayout.TextField("Country", usersData.userInfos.userCountry);
        usersData.userInfos.userPostalCode = EditorGUILayout.TextField("Postal Code", usersData.userInfos.userPostalCode);
        usersData.userInfos.userEmail = EditorGUILayout.TextField("Email", usersData.userInfos.userEmail);
        usersData.userInfos.userPhoneNumber = EditorGUILayout.TextField("Phone Number +", usersData.userInfos.userPhoneNumber);
        EditorGUILayout.EndVertical();

        EditorGUILayout.Space();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Internal Account Info");
        usersData.userInfos.isUserActiveNow = EditorGUILayout.Toggle("User Active Now ",usersData.userInfos[i].isUserActiveNow);
        usersData.userInfos[i].isUserAuth = EditorGUILayout.Toggle("User Auth Now", usersData.userInfos[i].isUserAuth);
        usersData.userInfos[i].isUserPremium = EditorGUILayout.Toggle("User Premium", usersData.userInfos[i].isUserPremium);
        usersData.userInfos[i].isUserPrivate = EditorGUILayout.Toggle("User Private", usersData.userInfos[i].isUserPrivate);
        usersData.userInfos[i].isUserAccAth = EditorGUILayout.Toggle("User Account Auth", usersData.userInfos[i].isUserAccAth);
        EditorGUILayout.EndHorizontal();

        if (GUI.changed)
        {
            EditorUtility.SetDirty(usersData);
        }
        GUI.SetNextControlName("");
    }
}

Please! Using code tags properly - Unity Engine - Unity Discussions

Use code tags. No one is going to spend time reading your code if it hurts their eyes.

1 Like

This error comes from changing things between events in OnGUI.

First question to ask is do you need OnGUI at all. If this is for production code, then switch over to the new UI. If you are doing editor scripting continue reading.

OnGUI gets called multiple times per event. The first call is a layout event, designed to figure out what to render. If you change the data in OnGUI between the events then the system gets confused and throws this error.

Hello,

This question is posted all over the internet but what is never answered is how to debug this to know which code is causing the error, since Unity is very ambiguous when this error is thrown. Also with tons of lines of code, who knows what line caused it.

Any insight on how to backtrace the issue?

Thanks,
jrDev

The error is going to be thrown by the imGUI system during the second call to OnGUI. That’s literally about all the detail you are likely to get.

The easiest solution is to simply abandon imGUI. Use the 4.6 UI system for in game UI, and use UIElements for inspector UI. However if that is not an option, this is best dealt with by OnGUI best practices, rather than specific debugging.

Keep the amount of code in OnGUI to an absolute minimum. OnGUI should be getting your input from the UI. It shouldn’t be doing anything with it.

Don’t change the UI layout based on something that happens in OnGUI. This is bad and will probably throw the error every time the button is pressed.

void OnGUI {
    if(Button(...)){
        Label(...);
    }
}

This is a better way to do it

bool buttonPressed;
bool displayLabel;

void Update {
    displayLabel = buttonPressed;
    buttonPressed = false;
}

void OnGUI {
    if(Button(...)){
        buttonPressed = true;
    }
    if (displayLabel){
        Label(...)
    }
}

This example is somewhat contrived, but you get the idea. Don’t use the result of a button press directly to display or hide UI elements. Instead record the input and then make the changes to the UI in update. That way the UI layout stays the same on every pass through OnGUI.

You’ll also note that I avoided using else in OnGUI. That’s because OnGUI gets called multiple times per frame with different initial conditions. From memory its twice per UI event, but I’d have to look that up to be sure. So in this (bad) example, the else clause will always trigger. Regardless of the button state, “Hah, hah” will be printed at least once per frame.

void OnGUI {
    if(Button(...)){
        // do something
    } else {
        Debug.Log("Hah, hah");
    }
}

If you really want to get deep into OnGUI, check out this Unite video. Its old, but still applies.

The exception occurs mainly during the first OnGUI calls. GUI will call this functions multiple times for different reason at first. So each of these calls must display the exact controls as the previous call.

if(userData == null)
{
    //Display Nothing during the first call
}
else
{
    //Display things on second and later calls.
}

Is actually your problem here.

The following code would work better.

void OnGUI()
{
     //initialize your data if not initalized.
     if(usersData == null)
     {
            Init();
     }
     if (_isUserInfoDone == false)
     {
           GetUserInfos();
           _isUserInfoDone = true;
     }

     //display it right after, without waiting for the next call.
     MakeUserSelection();
     if (GUILayout.Button("Show Selected User"))
     {
         DisplayUsers(numberOfUsersToShow);
     }
     if (GUILayout.Button("Close"))
         Close();
     if (GUI.changed)
         EditorUtility.SetDirty(usersData);
}

Please note, the post is 6 years old. The OP made a single post on the forum too.

Anyway, I’ll move this post to the IMGUI forum.

1 Like

Well it’s still the one we find first when searching on Google for the error message.
So I felt it might be good giving an extra answer here, instead of any other place.