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

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(); }

浙公网安备 33010602011771号