GUIUtility.hotControl

IMGUI中每个可点击(交互)的控件都会有一个controlID, 一般在mouseDown的时候设置, mouseUp的时候清除。

动画2

 

public class TestHotControlIdWindow : EditorWindow
{
    [MenuItem("MyTools/TestHotControlIdWindow")]
    public static void ShowWindow()
    {
        EditorWindow.GetWindow<TestHotControlIdWindow>(false, "TestHotControlIdWindow", true).Show();
    }

    private void OnEnable()
    {
        SceneView.duringSceneGui -= OnMySceneGUI;
        SceneView.duringSceneGui += OnMySceneGUI;
    }

    private void OnDisable()
    {
        SceneView.duringSceneGui -= OnMySceneGUI;
    }

    private void OnMySceneGUI(SceneView sceneView)
    {
        var curEvt = Event.current;

        var hotControl1 = GUIUtility.hotControl;
        var evtType1 = curEvt.type;

        GUILayout.BeginArea(new Rect(60, 60, 200, 300), "test");
        GUILayout.Button("Button");
        EditorGUILayout.SelectableLabel("Label Text");
        GUILayout.EndArea();

        if (evtType1 == EventType.MouseMove)
        {
            curEvt.Use(); //Event.type设为Used
        }

        var hotControl2 = GUIUtility.hotControl;
        var evtType2 = curEvt.type;

        switch (evtType1)
        {
            case EventType.MouseDown:
                Debug.Log($"hotControl ctrl1: {hotControl1}, ctrl2: {hotControl2}; evtType: {evtType1}, {evtType2}");
                break;
            case EventType.MouseUp:
                Debug.Log($"hotControl ctrl1: {hotControl1}, ctrl2: {hotControl2}; evtType: {evtType1}, {evtType2}");
                break;
        }
    }

}

 

什么时候需要用到hotControl?

一般是自定义控件的时候用到

private static readonly int s_MyButtonHash = "MyButton".GetHashCode();

public static bool MyButton(Rect drawRect, GUIContent content, GUIStyle style)
{
    int ctrlId = GUIUtility.GetControlID(s_MyButtonHash, FocusType.Passive, drawRect);
    var curEvt = Event.current;
    switch (curEvt.GetTypeForControl(ctrlId))
    {
        case EventType.MouseDown:
        {
            if (drawRect.Contains(curEvt.mousePosition))
            {
                GUIUtility.hotControl = ctrlId;
                curEvt.Use(); //将Event.type设为Used, 事件consume掉
            }
            return false;
        }
        case EventType.MouseUp:
        {
            if (GUIUtility.hotControl == ctrlId)
            {
                GUIUtility.hotControl = 0;
                curEvt.Use();

                if (drawRect.Contains(curEvt.mousePosition)) //在按钮范围内抬起才算点击
                    return true;
            }
            return false;
        }
        case EventType.Repaint:
        {
            style.Draw(drawRect, content, ctrlId);
            break;
        }

        case EventType.Ignore:
            Debug.Log($"MyButton evtType:{curEvt.type}");
            break;
    }

    return false;
}

 

private GUIContent m_MyButtonContent = new GUIContent("点击");

private void OnMySceneGUI(SceneView sceneView)
{
    GUILayout.BeginArea(new Rect(60, 60, 200, 300), "test");

    var myButtonDrawRect = GUILayoutUtility.GetRect(m_MyButtonContent, GUI.skin.button);
    GUI.BeginClip(myButtonDrawRect);
    {
        var myButtonLocalDrawRect = new Rect(2, 2, myButtonDrawRect.width, myButtonDrawRect.height);
        if (MyButton(myButtonLocalDrawRect, m_MyButtonContent, GUI.skin.button))
            Debug.Log("点击");
    }
    GUI.EndClip();

    GUILayout.EndArea();
}

 

为啥用curEvt.GetTypeForControl(ctrlId)来获取事件类型?

不能用curEvt.type来获取吗?

    不能,特别是有GUI.BeginClip的情况,在按钮上点下,然后移到Clip区域外再抬起,如果用GetTypeForControl得到的是MouseUp,如果是curEvt.type得到的是Ignore,这将导致按钮的点击触发逻辑不对。

GetTypeForControl做了什么?

    hotControl匹配的时候,返回rawType;否则返回type。

 

ControlId是如何确定的?

WndHash + 布局嵌套深度 + 当前布局深度的控件序号 + focusType

void OnGUI()
{
    GUILayout.BeginVertical();
    {
        // Button 1: depth=1, seqIdx=0
        if (GUILayout.Button("Click Me"))
            Debug.Log("Clicked!");

        GUILayout.BeginHorizontal();
        {
            // Button 2: depth=2, seqIdx=0
            if (GUILayout.Button("Button 2"))
                Debug.Log("Button 2");

            // Button 3: depth=2, seqIdx=1
            if (GUILayout.Button("Button 3"))
                Debug.Log("Button 3");
        }
        GUILayout.EndHorizontal();
    }
    GUILayout.EndVertical();
}

 

posted @ 2023-10-19 23:46  yanghui01  阅读(134)  评论(0)    收藏  举报