UEDL4-3——窗口事件传递、坐标转换

本章代码关键字

1
2
3
4
5
6
7
8
9
EditorGUIUtility.CommandEvent()            //生成一个命令事件,需要传入事件名
editorWindow.SendEvent() //向窗口发送消息
Event.current.type //获取当前事件的类型
EventType.ExecuteCommand //事件类型为执行命令
Event.current.commandName //获取当前的事件名,可用于确认是否是监听事件
EditorGUIUtility.GUIToScreenPoint() //将点从GUI位置转换为屏幕空间
EditorGUIUtility.GUIToScreenRect() //将rect从GUI位置转换为屏幕空间
EditorGUIUtility.ScreenToGUIPoint() //将点从屏幕空间转换为GUI位置
EditorGUIUtility.ScreenToGUIRect() //将rect从屏幕空间转换为GUI位置

窗口事件传递

编辑器窗口可以向特定的编辑器窗口发送消息SendEvent​,窗口在监听到接收的消息后可以执行对应逻辑

首先需要使用EditorGUIUtility.CommandEvent​来获取一个命令事件,需要传入事件名,然后使用SendEvent​对目标窗口发送消息
窗口需要监听当前事件类型是否是EventType.ExecuteCommand​的,并判断名字是否是传入到CommandEvent()​内的名字,如果是即可执行监听逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using UnityEditor;
using UnityEngine;

public class Lesson12 : EditorWindow
{
private void OnGUI()
{
if (GUILayout.Button("传递事件"))
{
Event e = EditorGUIUtility.CommandEvent("唐老狮的事件");
Lesson12 win = EditorWindow.GetWindow<Lesson12>();
win.SendEvent(e);
}

if (Event.current.type == EventType.ExecuteCommand)
{
if (Event.current.commandName == "唐老狮的事件")
{
Debug.Log($"{nameof(Lesson12)}: 收到唐老狮的事件");
}
}
}
}

点击“事件传递”按钮效果:

image

该方法可用于其他窗口,将消息发送到对应窗口即可,如果窗口有对应监听逻辑,可以根据事件名执行逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using UnityEditor;
using UnityEngine;

public class Lesson12 : EditorWindow
{
private void OnGUI()
{
if (GUILayout.Button("传递事件"))
{
Event e = EditorGUIUtility.CommandEvent("唐老狮的事件");
Lesson12 win = EditorWindow.GetWindow<Lesson12>();
win.SendEvent(e);
Lesson3 winL3 = EditorWindow.GetWindow<Lesson3>();
winL3.SendEvent(e);
}

if (Event.current.type == EventType.ExecuteCommand)
{
if (Event.current.commandName == "唐老狮的事件")
{
Debug.Log($"{nameof(Lesson12)}: 收到唐老狮的事件");
}
}
}
}


public class Lesson3 : EditorWindow
{
private void OnGUI()
{
if (Event.current.type == EventType.ExecuteCommand)
{
if (Event.current.commandName == "唐老狮的事件")
{
Debug.Log($"{nameof(Lesson3)}: 收到唐老狮的事件");
}
}
}
}

点击“传递事件”后效果:(Lesson3窗口弹出,Lesson12和Lesson3都输出消息)

image

坐标转换

  • 屏幕坐标系:原点为屏幕左上角(下图是部分屏幕)

    image

  • GUI坐标系:原点为当前窗口左上角

    image

具体转换方法:

  • GUIToScreenPoint()​:将点从GUI位置转换为屏幕空间

    假设要将当前GUI坐标系的(10, 10)的位置转换为屏幕空间的位置

    1
    2
    3
    4
    5
    6
    if (GUILayout.Button("坐标转换测试"))
    {
    Vector2 v = new Vector2(10, 10);
    Vector2 screenPos = EditorGUIUtility.GUIToScreenPoint(v);
    Debug.Log($"GUI坐标:{v}, 屏幕坐标:{screenPos}");
    }

    点击“坐标转换测试”输出结果:image

    值得一提的是,这里的转换函数如果被包裹在布局的方法里则转换的值是会到布局的影响的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    private void OnGUI()
    {
    if (GUILayout.Button("坐标转换测试"))
    {
    Vector2 v = new Vector2(10, 10);
    Vector2 screenPos = EditorGUIUtility.GUIToScreenPoint(v);
    Debug.Log($"GUI坐标:{v}, 屏幕坐标:{screenPos}");
    }

    if (GUILayout.Button("受到布局影响的坐标转换测试"))
    {
    Vector2 v = new Vector2(10, 10);
    GUI.BeginGroup(new Rect(10, 10, 100, 100));
    Vector2 screenPos = EditorGUIUtility.GUIToScreenPoint(v);
    GUI.EndGroup();
    Debug.Log($"受到布局影响的转换的屏幕坐标:{screenPos}");
    }
    }

    依次点击两个按钮后的输出结果:image

    可见,受到布局影响的转换加上了(10,10)

  • GUIToScreenRect()​:将rect​从GUI位置转换为屏幕空间

    假设要将当前GUI坐标系的Rect​(10, 20, 100, 150)转换为屏幕空间的Rect

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private void OnGUI()
    {
    if (GUILayout.Button("Rect转换测试"))
    {
    var guiRect = new Rect(10, 20, 100, 150);
    var screenRect = EditorGUIUtility.GUIToScreenRect(guiRect);
    Debug.Log($"GUIRect:{guiRect}, 屏幕GUIRect:{screenRect}");
    }
    }

    测试转换结果:image

    可见,转换Rect​只会影响前两个有关位置值,而不会影响后两个与尺寸相关的值

  • ScreenToGUIPoint()​:将点从屏幕空间转换为GUI位置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private void OnGUI()
    {
    if (GUILayout.Button("屏幕坐标转换测试"))
    {
    var screenPos = new Vector2(800, 600);
    var guiPos = EditorGUIUtility.ScreenToGUIPoint(screenPos);
    Debug.Log($"屏幕坐标:{screenPos},GUI坐标:{guiPos}, ");
    }
    }

    测试转换结果:​image

  • ScreenToGUIRect()​:将rect​从屏幕空间转换为GUI位置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private void OnGUI()
    {
    if (GUILayout.Button("屏幕Rect转换测试"))
    {
    var screenRect = new Rect(800, 600, 200, 250);
    var guiRect = EditorGUIUtility.ScreenToGUIRect(screenRect);
    Debug.Log($"屏幕GUIRect:{screenRect},GUIRect:{guiRect}");
    }
    }

    测试转换结果:image

    同样的,转换Rect​只会影响前两个有关位置值,而不会影响后两个与尺寸相关的值