使用上下文菜单事件、ContextualMenuManipulator 和 ContextualMenuPopulateEvent 可在用户执行某些操作(例如用户右键点击标签)时显示一组选项。
要启用上下文菜单,请将 ContextualMenuManipulator 附加到视觉元素。此操控器会在鼠标右键松开事件或菜单键松开事件后显示上下文菜单。ContextualMenuManipulator 操控器还会添加一个回调来响应 ContextualMenuPopulateEvent。
以下代码示例将上下文菜单添加到视觉元素。菜单只有一项。
void InstallManipulator(VisualElement element)
{
ContextualMenuManipulator m = new ContextualMenuManipulator(MyDelegate);
m.target = element;
}
void MyDelegate(ContextualMenuPopulateEvent event)
{
// Modify event.menu
event.menu.AppendAction("My action", DisplayProperties, DropdownMenu.MenuAction.AlwaysEnabled);
}
void DisplayProperties(DropdownMenu.MenuAction menuItem)
{
// ...
}
提供给 ContextualMenuManipulator 构造函数的回调在最后调用,以便子元素可以填充菜单。
操控器将发送传播到目标元素层级视图的 ContextualMenuPopulateEvent 事件。事件沿着传播路径移动:从视觉树的根到事件目标,再回到视觉树的根。沿着传播路径,具有 ContextualMenuPopulateEvent 事件回调的元素可以在上下文菜单中添加、删除或修改菜单项。
当元素收到 ContextualMenuPopulateEvent 时,它会调用 [DropdownMenu.InsertAction()](../ScriptReference/UIElements.DropdownMenu.InsertAction] 或 DropdownMenu.AppendAction(.html) 将菜单项添加到上下文菜单中。[`DropdownMenu.InsertAction()`](../ScriptReference/UIElements.DropdownMenu.InsertAction] 和 DropdownMenu.AppendAction(.html) 接受两个回调作为参数。用户在菜单中选择菜单项时,会执行第一个回调。第二个回调在显示菜单之前执行,还会检查菜单项是否已启用。
两个回调都接收一个 MenuAction 作为参数。MenuAction 代表菜单项,具有以下其他有用的属性:
MenuAction.userData 包含对用于 AppendAction() 或 InsertAction() 的用户数据的引用。MenuAction.eventInfo 包含有关显示上下文菜单的事件的信息。在响应事件的操作中,应使用 MenuAction.eventInfo。例如,可以使用鼠标位置根据所选的上下文菜单项创建和放置对象。以下示例将创建一个带有两个标签的自定义 Editor 窗口,并为每个标签添加上下文菜单。该示例演示了如何添加、删除和更新上下文菜单。
使用任何模板创建 Unity 项目。
在项目 (Project) 窗口中,创建名为 Editor 的文件夹。
在 Editor 文件夹中创建一个名为 ContextualMenuDemo 的 C# 脚本,并将其内容替换为以下代码:
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public class ContextualMenuDemo : EditorWindow
{
[MenuItem("Window/ContextualMenuDemo")]
public static void ShowExample()
{
ContextualMenuDemo wnd = GetWindow<ContextualMenuDemo>();
wnd.titleContent = new GUIContent("ContextualMenuDemo");
}
public void CreateGUI()
{
VisualElement root = rootVisualElement;
VisualElement label = new Label("Right click me!");
root.Add(label);
AddANewContextMenu(label);
InsertIntoAnExistingMenu(label);
VisualElement second = new Label("Click me also!");
root.Add(second);
AddANewContextMenu(second);
InsertIntoAnExistingMenu(second);
// Override the default behavior by clearing the menu.
ReplaceContextMenu(second);
}
void AddANewContextMenu(VisualElement element)
{
// The manipulator handles the right click and sends a ContextualMenuPopulateEvent to the target element.
// The callback argument passed to the constructor is automatically registered on the target element.
element.AddManipulator(new ContextualMenuManipulator((evt) =>
{
evt.menu.AppendAction("First menu item", (x) => Debug.Log("First!!!!"), DropdownMenuAction.AlwaysEnabled);
evt.menu.AppendAction("Second menu item", (x) => Debug.Log("Second!!!!"), DropdownMenuAction.AlwaysEnabled);
}));
}
void InsertIntoAnExistingMenu(VisualElement element)
{
element.RegisterCallback<ContextualMenuPopulateEvent>((evt) =>
{
evt.menu.AppendSeparator();
evt.menu.AppendAction("Another action", (x) => Debug.Log("Another Action!!!!"), DropdownMenuAction.AlwaysEnabled);
});
}
void ReplaceContextMenu(VisualElement element)
{
element.RegisterCallback<ContextualMenuPopulateEvent>((evt) =>
{
evt.menu.ClearItems();
evt.menu.AppendAction("The only action", (x) => Debug.Log("The only action!"), DropdownMenuAction.AlwaysEnabled);
});
}
}
要实时查看示例,请从菜单中选择窗口 (Window) > UI 工具箱 (UI Toolkit) > ContextualMenuDemo。