Балансировка вызовов внутри метода EditorWindow OnGUI, вызывающая проблемы - PullRequest
0 голосов
/ 24 мая 2019

Я создаю систему для балансировки вызовов внутри метода OnGUI окна EditorWindow. Я делаю следующее:

        public void Update()
        {
            Repaint();
        }

Внутри моего метода OnGUI я вызываю этот Балансер. У меня есть один список с обратными вызовами (список). Так что идея проста, некоторые callvaxc Я пропускаю некоторые рамки перерисовки для обратного вызова с полным графическим интерфейсом и вызываю каждый перерисовку для других обратных вызовов (например, метки выделения или отображающих gif-файлов).

По какой-то причине эта ошибка происходит «Получение элемента управления 0 в группе только с 0 элементами управления при выполнении перерисовки»

        private int m_repaintCounter;

        public void Draw()
        {
            Event e = Event.current;
            try
            {
                foreach (var action in m_actions)
                {
                    try
                    {

                            // Test 1
                            // MainAction is a class that inherits from Action (class MainAction : Action)
                            if (action is MainAction)
                            {
                                bool isDesignedType = e.rawType == EventType.Repaint || e.rawType == EventType.Layout;

                                if (isDesignedType)
                                    ++m_repaintCounter;

                                if (!(m_repaintCounter == 20 && isDesignedType))
                                    continue;
                                else
                                    m_repaintCounter = 0;
                            }

                            // Test 2
                            action.Value();
                    }
                    catch (Exception ex)
                    {
                        Debug.LogException(ex);
                    }
                }
            }
            catch
            {
                // Due to recompile the collection will modified, so we need to avoid the exception
            }
        }

Но если я прокомментирую "Тест 1", все будет хорошо.

В ctor класса нам нужно указать обратный вызов метода GUI, например:

        public Balancer(Action drawAction)
        {
            m_actions = new List<Action>();
            m_actions.Add(drawAction);
        }

Так что мы могли бы легко (внутри EditorWindow):

    private Balancer m_balancer;

    public void OnEnable() 
    {
        m_balancer = new Balancer(Draw);
    }

    public void Draw() 
    {
        // This block will be called every 20 repaints as specified on the if statment
        GUILayout.BeginHorizontal("box");
        {
            GUILayout.Button("I'm the first button");
            GUILayout.Button("I'm to the right");

            // This marquee will be called on each repaint
            m_balancer.AddAction(() => CustomClass.DisplayMarquee("example"));
        }
        GUILayout.EndHorizontal();
    }
// Inside of the Balancer class we have
// We use System.Linq.Expressions to identify actions that were added already

private HashSet<string> m_alreadyAddedActions = new HashSet<string>();

public void AddAction(Expression<Action> callback) 
{
    if(!m_alreadyAddedActions.Add(callback.ToString()))
        return;

    m_actions.Add(callback.Compile());
}

Я не могу понять это. Я не мог найти информацию в интернете. Кто-нибудь может мне помочь?

1 Ответ

1 голос
/ 24 мая 2019

Хорошо, так что OnGui (IMGui) ужасно работать. Если вы не используете его для сценария редактирования, используйте вместо него новый пользовательский интерфейс 4.6 (UGui).

Теперь тогда. Проблема.

OnGui называется как минимум дважды за каждый кадр . Одним из них является вычисление макетов, а другим - рисование («перекраска»).

Если между этими двумя вызовами меняется число вещей, размер вещей или что-либо еще , тогда Unity выдаст ошибку «Получение позиции 0 в группе с только 0 элементами управления при выполнении перерисовки».

То есть: вы не можете изменить состояние пользовательского интерфейса в системе IMGui в любой точке после Макет и до Перекрас .

Только, только только изменить состояние (и, следовательно, какие объекты рисуются) в течение Event.current == EventType.Repaint и только, только только изменить состояние для следующего кадра (или сделать изменения во время Event.current == EventType.Layout, при условии, что это же новое состояние приведет к тому же пути кода во время перерисовки). Ни при каких обстоятельствах не вносите изменения во время перекраски, которые не присутствовали во время предыдущего макета.

...