Search Unity

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

Discussion in 'Immediate Mode GUI (IMGUI)' started by GDelkos, May 21, 2016.

  1. GDelkos

    GDelkos

    Joined:
    May 21, 2016
    Posts:
    1
    why i am getting this here
    can anyone help? ty

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.IO;
    4.  
    5.  
    6. public class UserViewer : EditorWindow {
    7.  
    8.     [MenuItem("Window/UserViewer")]
    9.     public static void OpenEditor()
    10.     {
    11.         GetWindow<UserViewer>("UserViewer", true);
    12.     }
    13.  
    14.     [SerializeField]
    15.     private UsersData usersData = null;
    16.     [SerializeField]
    17.     private int numberOfUsers;
    18.     [SerializeField]
    19.     private int numberOfUsersToShow;
    20.     [SerializeField]
    21.     private int id;
    22.     [SerializeField]
    23.     private int index;
    24.     [SerializeField]
    25.     private string[] acountNames;
    26.     [SerializeField]
    27.     private string activeAcountInfo;
    28.     [SerializeField]
    29.     private static bool _isUserInfoDone = false;
    30.  
    31.     void OnGUI()
    32.     {
    33.        if(usersData == null)
    34.         {
    35.                 Init();
    36.         }
    37.         else
    38.         {
    39.             if (_isUserInfoDone == false)
    40.             {
    41.                 GetUserInfos();
    42.                 _isUserInfoDone = true;
    43.             }
    44.             MakeUserSelection();
    45.             if (GUILayout.Button("Show Selected User"))
    46.             {
    47.                 DisplayUsers(numberOfUsersToShow);
    48.             }
    49.             if (GUILayout.Button("Close"))
    50.                 Close();
    51.             if (GUI.changed)
    52.                 EditorUtility.SetDirty(usersData);
    53.         }
    54.     }
    55.  
    56.     public void MakeUserSelection()
    57.     {
    58.         EditorGUILayout.LabelField("User Selection");
    59.         numberOfUsers = usersData.userInfos.Count;
    60.         EditorGUILayout.TextField("Total Users Count", numberOfUsers.ToString());
    61.         index = EditorGUILayout.Popup(index, acountNames);
    62.         numberOfUsersToShow = index;
    63.         EditorGUILayout.LabelField("Acount Info");
    64.         activeAcountInfo = EditorGUILayout.TextField(usersData.userInfos[numberOfUsersToShow].userRFirstName + " - " + usersData.userInfos[numberOfUsersToShow].userRLastName + "    Email :" + usersData.userInfos[numberOfUsersToShow].userEmail + "    Coins :" + usersData.userInfos[numberOfUsersToShow].userCoins);
    65.     }
    66.  
    67.  
    68.  
    69.     public void Init()
    70.     {
    71.         usersData = ScriptableObject.CreateInstance<UsersData>();
    72.         if (!Directory.Exists(Application.dataPath + Path.DirectorySeparatorChar + "Resources"))
    73.             AssetDatabase.CreateFolder("Assets", "Resources");
    74.         if(File.Exists(Application.dataPath + Path.DirectorySeparatorChar + "Resources" + Path.DirectorySeparatorChar + "Users.asset"))
    75.         {
    76.             usersData = AssetDatabase.LoadAssetAtPath("Assets/Resources/Users.asset", typeof(UsersData)) as UsersData;
    77.         }
    78.         else
    79.         {
    80.             AssetDatabase.CreateAsset(usersData, "Assets/Resources/Users.asset");
    81.             AssetDatabase.SaveAssets();
    82.         }
    83.     }
    84.  
    85.     void GetUserInfos()
    86.     {
    87.         acountNames = new string[numberOfUsers];
    88.         for (int i = 0; i < numberOfUsers; i++)
    89.         {
    90.             acountNames = usersData.userInfos.userID.ToString() + " : " + usersData.userInfos.userAlias;
    91.         }
    92.     }
    93.  
    94.     public void DisplayUsers(int i)
    95.     {
    96.         EditorGUILayout.BeginVertical();
    97.         index = EditorGUILayout.Popup(index, acountNames);
    98.         numberOfUsersToShow = index;
    99.         usersData.userInfos.userAlias = EditorGUILayout.TextField("User Acount Name", usersData.userInfos.userAlias);
    100.         usersData.userInfos.userAvatar = (Texture2D)EditorGUILayout.ObjectField("Avatar", usersData.userInfos.userAvatar, typeof(Texture2D), false);
    101.         EditorGUILayout.LabelField("Color");
    102.         usersData.userInfos.userColor = EditorGUILayout.ColorField(usersData.userInfos.userColor);
    103.         EditorGUILayout.LabelField("Coins");
    104.         usersData.userInfos.userCoins = EditorGUILayout.IntField(usersData.userInfos.userCoins);
    105.         EditorGUILayout.LabelField("Acount is Active");
    106.         usersData.userInfos.userActive = EditorGUILayout.Toggle(usersData.userInfos.userActive);
    107.         EditorGUILayout.LabelField("Rank");
    108.         usersData.userInfos.userRank = EditorGUILayout.IntField(usersData.userInfos.userRank);
    109.         EditorGUILayout.LabelField("Real Balance");
    110.         usersData.userInfos.userBalance = EditorGUILayout.FloatField(usersData.userInfos.userBalance);
    111.         EditorGUILayout.LabelField("User Details");
    112.         usersData.userInfos.userRFirstName = EditorGUILayout.TextField("First Name", usersData.userInfos.userRFirstName);
    113.         usersData.userInfos.userRMiddleName = EditorGUILayout.TextField("Middle Name", usersData.userInfos.userRMiddleName);
    114.         usersData.userInfos.userRLastName = EditorGUILayout.TextField("Last Name", usersData.userInfos.userRLastName);
    115.         usersData.userInfos.userAddress1 = EditorGUILayout.TextField("Address 1", usersData.userInfos.userAddress1);
    116.         usersData.userInfos.userAddress2 = EditorGUILayout.TextField("Address 2", usersData.userInfos.userAddress2);
    117.         usersData.userInfos.userCity = EditorGUILayout.TextField("City", usersData.userInfos.userCity);
    118.         usersData.userInfos.userState = EditorGUILayout.TextField("State", usersData.userInfos.userState);
    119.         usersData.userInfos.userCountry = EditorGUILayout.TextField("Country", usersData.userInfos.userCountry);
    120.         usersData.userInfos.userPostalCode = EditorGUILayout.TextField("Postal Code", usersData.userInfos.userPostalCode);
    121.         usersData.userInfos.userEmail = EditorGUILayout.TextField("Email", usersData.userInfos.userEmail);
    122.         usersData.userInfos.userPhoneNumber = EditorGUILayout.TextField("Phone Number +", usersData.userInfos.userPhoneNumber);
    123.         EditorGUILayout.EndVertical();
    124.  
    125.         EditorGUILayout.Space();
    126.  
    127.         EditorGUILayout.BeginHorizontal();
    128.         EditorGUILayout.LabelField("Internal Account Info");
    129.         usersData.userInfos.isUserActiveNow = EditorGUILayout.Toggle("User Active Now ",usersData.userInfos[i].isUserActiveNow);
    130.         usersData.userInfos[i].isUserAuth = EditorGUILayout.Toggle("User Auth Now", usersData.userInfos[i].isUserAuth);
    131.         usersData.userInfos[i].isUserPremium = EditorGUILayout.Toggle("User Premium", usersData.userInfos[i].isUserPremium);
    132.         usersData.userInfos[i].isUserPrivate = EditorGUILayout.Toggle("User Private", usersData.userInfos[i].isUserPrivate);
    133.         usersData.userInfos[i].isUserAccAth = EditorGUILayout.Toggle("User Account Auth", usersData.userInfos[i].isUserAccAth);
    134.         EditorGUILayout.EndHorizontal();
    135.  
    136.         if (GUI.changed)
    137.         {
    138.             EditorUtility.SetDirty(usersData);
    139.         }
    140.         GUI.SetNextControlName("");
    141.     }
    142. }
     
    Last edited: May 25, 2016
  2. skalev

    skalev

    Joined:
    Feb 16, 2012
    Posts:
    264
    GDelkos likes this.
  3. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    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.
     
  4. crafTDev

    crafTDev

    Joined:
    Nov 5, 2008
    Posts:
    1,820
    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
     
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    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.

    Code (CSharp):
    1. void OnGUI {
    2.     if(Button(...)){
    3.         Label(...);
    4.     }
    5. }
    This is a better way to do it

    Code (CSharp):
    1. bool buttonPressed;
    2. bool displayLabel;
    3.  
    4. void Update {
    5.     displayLabel = buttonPressed;
    6.     buttonPressed = false;
    7. }
    8.  
    9. void OnGUI {
    10.     if(Button(...)){
    11.         buttonPressed = true;
    12.     }
    13.     if (displayLabel){
    14.         Label(...)
    15.     }
    16. }
    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.

    Code (CSharp):
    1. void OnGUI {
    2.     if(Button(...)){
    3.         // do something
    4.     } else {
    5.         Debug.Log("Hah, hah");
    6.     }
    7. }
    If you really want to get deep into OnGUI, check out this Unite video. Its old, but still applies.

     
  6. YannickTriqueneaux

    YannickTriqueneaux

    Joined:
    Apr 9, 2020
    Posts:
    4
    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.

    Code (CSharp):
    1. if(userData == null)
    2. {
    3.     //Display Nothing during the first call
    4. }
    5. else
    6. {
    7.     //Display things on second and later calls.
    8. }
    Is actually your problem here.


    The following code would work better.

    Code (CSharp):
    1. void OnGUI()
    2. {
    3.      //initialize your data if not initalized.
    4.      if(usersData == null)
    5.      {
    6.             Init();
    7.      }
    8.      if (_isUserInfoDone == false)
    9.      {
    10.            GetUserInfos();
    11.            _isUserInfoDone = true;
    12.      }
    13.  
    14.      //display it right after, without waiting for the next call.
    15.      MakeUserSelection();
    16.      if (GUILayout.Button("Show Selected User"))
    17.      {
    18.          DisplayUsers(numberOfUsersToShow);
    19.      }
    20.      if (GUILayout.Button("Close"))
    21.          Close();
    22.      if (GUI.changed)
    23.          EditorUtility.SetDirty(usersData);
    24. }
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,481
    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.
     
    YannickTriqueneaux likes this.
  8. YannickTriqueneaux

    YannickTriqueneaux

    Joined:
    Apr 9, 2020
    Posts:
    4
    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.