Getting control 1's position in a group with only 1 controls when doing repaint (Unity)

302
09 января 2022, 22:00

Стал сталкиваться с такой вот ошибкой:

ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint
    Aborting

Это не критично но хотелось бы,её убрать. Она возникает из-за:

OnGUI вызывается несколько раз за кадр, и если вы рисуете разное количество элементов управления в одном из тех, которые вызываются в одном и том же кадре, вы можете получить это сообщение об ошибке.

Тут я нашёл это пояснение. Но не понял как это пофиксить.

Мой код :

   Rect FooterSection;
   void OnGUI()
    {
        EditorGUI.BeginChangeCheck();
        string[] tabs = { "Объекты", "Назначение/Просмотр DATA у Terrain", "Настройки" };
        // selectedTab = GUILayout.Toolbar(selectedTab, tabs, tabStyle);
        selectedTab = GUILayout.Toolbar(selectedTab, tabs);
        switch (selectedTab)
        {
            case 0:
                DrawLayouts();
                DrawHeader();
                DrawLeft();
                DrawRight(true);
                DrawFooter();
                break;
            case 1:
                DrawListTerrain();
                break;
            case 2:
                DrawTabSettings();
                break;
        }
        EditorGUI.EndChangeCheck();
    }
    void DrawTabSettings()
    {
        EditorGUI.BeginChangeCheck();
        string[] tabsSettings = { "Общие настройки", "Добавление/Удаление объекта" };
        selectedTabSettings = GUILayout.Toolbar(selectedTabSettings, tabsSettings);
        switch (selectedTabSettings)
        {
            case 0:
                DrawSettings();
                break;
            case 1:
                DrawAddDeleteObj();
                break;
        }
        EditorGUI.EndChangeCheck();
    }
    void OnEnable()
    {
        ...
        InitTextures();
        ...
    }
    void DrawSettings()
    {
        moduleSettings settTerr = new moduleSettings();
        if (GUILayout.Button("Удалить размещённые деревья"))
        {
            settTerr.DeletTrees();
        }
        if (GUILayout.Button("TreeDistance=12000"))
        {
            settTerr.TreeDistance();
        }
        if (GUILayout.Button("TerrainTexturing"))//ошибка
        {
            // settTerr.TerrainTexturing();
            _thread = new Thread(() => settTerr.TerrainTexturing()); //ошибка
            _progress = 0;
            _thread.Start();
            pressedbool = true;
        }
        if (pressedbool)//ошибка
        {
            drawProgressBarOnGUI(FooterSection, 4);
            Dispatcher.Instance.InvokePending();
        }
        if (GUILayout.Button("Вывести в консоль количество деревьев на Terrain"))
        {
            settTerr.Showtreesname();
        }

        tempPrefab = (UnityEngine.Object)EditorGUILayout.ObjectField("Prefab для редакитования объектов:", tempPrefab, typeof(UnityEngine.Object), true);
        if (tempPrefab != null)
        {
            EditorGUI.BeginChangeCheck();
            prefabEditingBool = EditorGUILayout.ToggleLeft("Вкл./выкл. режим редактирования объектов.", prefabEditingBool);
            if (EditorGUI.EndChangeCheck())
            {
                string stringtoggle = "UPDATE Setting SET EditModeBool=" + prefabEditingBool + " ";
                Debug.Log(stringtoggle);
                ObjectDataBase.UpdateSELECTObj(stringtoggle);
            }
        }
        else
        {
            prefabEditingBool = false;
        }

        EditorGUILayout.BeginHorizontal();
        stringObjfileURL = GUILayout.TextField(stringObjfileURL);
        if (GUILayout.Button("Обзор..."))
        {
            stringObjfileURL = EditorUtility.OpenFilePanel("All obj files", "", "obj");
            // objtojsonConvert();
            // trimLink();
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.BeginVertical();
        mapoffsetx = EditorGUILayout.FloatField("map offset x:", mapoffsetx);
        mapoffsetz = EditorGUILayout.FloatField("map offset z:", mapoffsetz);
        EditorGUILayout.EndVertical();
        if (GUILayout.Button("Сохранить настройки"))
        {
            string path = "";
            if (tempPrefab != null)
            {
                path = AssetDatabase.GetAssetPath(tempPrefab);
            }
            else
            {
                path = "";
            }
            string stringtoggle;
            if (path != "")
            {
                stringtoggle = "UPDATE Setting SET EditModeBool=" + prefabEditingBool + ", PrefabForEditing='" + path + "', mapoffsetx='" + (double)mapoffsetx + "', mapoffsetz='" + (double)mapoffsetz + "', ObjfileURL = '" + stringObjfileURL + "' ";
            }
            else
            {
                stringtoggle = "UPDATE Setting SET EditModeBool=" + prefabEditingBool + ", PrefabForEditing='yesnull', mapoffsetx='" + (double)mapoffsetx + "', mapoffsetz='" + (double)mapoffsetz + "', ObjfileURL = '" + stringObjfileURL + "' ";
            }
            Debug.Log(stringtoggle);
            ObjectDataBase.UpdateSELECTObj(stringtoggle);
        }
    }
    void InitTextures()
    {
        HeaderSectionTexture = new Texture2D(1, 1);
        HeaderSectionTexture.SetPixel(0, 0, HeaderSectionColor);
        HeaderSectionTexture.Apply();
        LeftSectionTexture = new Texture2D(1, 1);
        LeftSectionTexture.SetPixel(0, 0, LeftSectionColor);
        LeftSectionTexture.Apply();
        RightSectionTexture = new Texture2D(1, 1);
        RightSectionTexture.SetPixel(0, 0, RightSectionColor);
        RightSectionTexture.Apply();
        FooterSectionTexture = new Texture2D(1, 1);
        FooterSectionTexture.SetPixel(0, 0, FooterSectionColor);
        FooterSectionTexture.Apply();
    }
    void DrawLayouts()
    {
        HeaderSection.x = 0;
        HeaderSection.y = 20f;
        HeaderSection.width = Screen.width;
        HeaderSection.height = Screen.height / 7f - 20f;
        LeftSection.x = 0;
        LeftSection.y = Screen.height / 7f + 20f;
        LeftSection.width = Screen.width / 2f;
        LeftSection.height = Screen.height * 5f / 7f - 15f;
        RightSection.x = Screen.width / 2f;
        RightSection.y = Screen.height / 7f + 20f;
        RightSection.width = Screen.width / 2f;
        RightSection.height = Screen.height * 5f / 7f - 15f;
        FooterSection.x = 0;
        FooterSection.y = (Screen.height * 6f) / 7f;
        FooterSection.width = Screen.width;
        FooterSection.height = Screen.height / 7f + 15f;
        DeleteSection.x = 0;
        DeleteSection.y = Screen.height / 7f + 20f;
        DeleteSection.width = Screen.width;
        DeleteSection.height = Screen.height * 5f / 7f - 15f;
        GUI.DrawTexture(HeaderSection, HeaderSectionTexture);
        GUI.DrawTexture(LeftSection, LeftSectionTexture);
        GUI.DrawTexture(RightSection, RightSectionTexture);
        GUI.DrawTexture(FooterSection, FooterSectionTexture);
    }
public void drawProgressBarOnGUI(Rect widthRect, int y = 1)
{
    EditorGUI.ProgressBar(new Rect(0, (widthRect.height / 2) * y, widthRect.width, 20), _progress / 100.0f, "progress: " + _progress + "%");
}

Что надо написать в условиях или как выполнить задачу в отдельном потоке, чтоб этого не возникало?

Answer 1

В IMGUI есть много событий, но все они вы вызываются после события Layout, например:

Layout -> Repaint
Layout -> MouseDown  
Layout -> ScrollWheel

Важно в здесь именно то, что события всегда происходят попарно и каждому событию всегда предшествует Layout.

При всем этом ничто не мешает написать такой код:

if(Event.current.type == EventType.Repaint){
    EditorGUILayout.LabelField("Label");
}

И такой, к примеру, код как раз вызовет ошибку:

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

Почему это и как оно произошло?

На этапе Layout регистрируются все Rect будущих элементов, совершенно не важно, где они находятся и какого они размера. Этот этап нужен именно для регистрации вхождений элементов в верстку.

На этапе Repaint в примере выше мы пытаемся написать строку через автоматическую верстку, предварительно не зарегистрировав его на этапе Layout. От чего в псевдо-массиве верстки в данном случае 0 вхождений, а строка в if пытается получить следующий, т.е. вхождение с индексом 0 в массиве с размером 0.

Как это исправить?

Без полного кода не понять, но скорее всего есть какой-то if, который что-то внутри себя рисует в окне. Лучше менять все меняющие GUI переменные внутри события Repaint в конце метода OnGUI, либо делать все то же самое в самом начале метода OnGUI внутри события Layout. Возможно, это не самое элегантное решение, но такое изменение гарантирует, что следующий или текущий Layout получит "свежие" данные для верстки. Да и по кастомным разработкам редактора очень мало статей и в целом примеров, так что это единственное, что лично я смог придумать.

P.S.

"Внутри события" - это так:

if(Event.current.type == EventType.Repaint){}
Answer 2

Может кому пригодится. Ошибку можно вылечить, если пропустить отрисовку GUI при срабатывании if. Надо не сразу рисовать GUI, а запустить счетчик, и рисовать когда он дойдет до 2. Глазом незаметно. Не знаю как конкретно, но работает. :)

Answer 3

В моем случае:

  1. помог счетчик, апдейтю его в обычном Update, в OnGUI жду пока счетчик не поднимется до 0.1 сек, для глаза приемлемо
  2. OnGUI срабатывает дважды за фрейм, так что лучше ждать не количество прошедших фреймов, а промежуток времени.
Answer 4

В данном случае в Canvas была анимированная кнопка и анимированная строка. Выбивало ошибку ТС. Достаточно было ввести статичную панель, к ней дочкой привязать бегущую строку и ОШИБКА ПРОПАЛА )))

READ ALSO
Как отправить изображение вместе с Html в C#

Как отправить изображение вместе с Html в C#

У меня есть WEB-сервер, созданный на C#, он основан на TcpListener и выглядит всё это так(работа с клиентом)

166
Как в Юнити 2D менять изображение?

Как в Юнити 2D менять изображение?

Во первых стоит сказать что я не очень хорош в C# и поэтому не исключаю что ответ довольно простойТем не менее, в игре которую я делаю, я хочу...

142
Несколько CheckBox MVC

Несколько CheckBox MVC

Нужен выбор нескольких книг на форме

60