平衡EditorWindow OnGUI方法内部的调用导致问题

时间:2019-05-24 19:54:36

标签: c# user-interface unity3d balance

我正在制作一个系统来平衡EditorWindow的OnGUI方法内部的调用。 我正在执行以下操作:

        public void Update()
        {
            Repaint();
        }

在我的OnGUI方法中,我正在调用此Balancer。我有一个带有回调的列表(列表)。 所以想法很简单,一些callvaxc 我将跳过具有完整GUI的回调的一些重绘框架,并为其他回调(例如,选取框标签或令人讨厌的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 个答案:

答案 0 :(得分:1)

好的,OnGui(IMGui)很难使用。如果您没有将其用于编辑器脚本,请改用新的4.6 UI(UGui)。

现在。问题。

OnGui至少被称为 twice every frame。其中一种是计算布局,另一种是实际绘制东西(“重新绘制”)。

如果在这两次调用之间事物的数量,事物的大小或其他任何事物发生变化,那么Unity将错误显示“在重新绘制时,在只有0个控件的组中获得控件0的位置”。

也就是说,您不能在Layout之后和Repaint之前的任何时间更改IMGui系统中的UI状态。

仅在Event.current == EventType.Repaint期间,仅 更改状态(以及绘制对象的方式),并且仅更改 只能 更改下一帧的状态(或者,在Event.current == EventType.Layout期间进行更改,条件是该相同的新状态将在重绘期间导致相同的代码路径)。在任何情况下,请勿在重绘期间进行以前的版式中不存在的更改。