Slate 编辑器界面

自动关联目录:Slate 编辑器界面

Slate 语法基础见 Slate 实践;本篇只讲编辑器侧的窗口、菜单与 Tab 注册。

1. 定位

编辑器扩展的界面只有两条路:UMG(Editor Utility Widget)或 Slate。前者快、后者强。

一句话定位:能用 EUW 解决的就用 EUW;要自定义停靠窗口、菜单、复杂控件时才写 Slate。

2. 三条路的对比

方式成本能做不能做
Editor Utility Widget(UMG)最低工具面板、批处理 UI深度定制停靠行为
Slate 自定义窗口高完全控制、可停靠 Tab快
Detail 面板定制中改属性的编辑体验独立窗口

判断标准:需要"一个能用的工具界面"→ EUW;需要"长得像引擎原生的一部分"→ Slate。

3. 自定义窗口与 Tab

概念说明
SWindow顶层窗口
FTabManagerTab 管理器,注册后可从菜单打开
FTabSpawnerEntry一个可生成的 Tab
FGlobalTabmanager全局管理器
FWorkspaceItem菜单里的分组归属
FLevelEditorModule挂到关卡编辑器
// 注册一个可停靠的 Tab
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(
    MyTabName,
    FOnSpawnTab::CreateRaw(this, &FMyModule::OnSpawnTab))
    .SetDisplayName(FText::FromString("My Tool"))
    .SetMenuType(ETabSpawnerMenuType::Enabled);

// 生成
TSharedRef<SDockTab> FMyModule::OnSpawnTab(const FSpawnTabArgs& Args)
{
    return SNew(SDockTab).TabRole(ETabRole::NomadTab)
    [
        SNew(SMyWidget)
    ];
}

Nomad Tab 是可自由停靠的全局 Tab;ETabRole::NomadTab 是最常用的角色。

4. 菜单扩展

机制状态
UToolMenuUE5 的推荐方式
FExtender旧方式,仍有代码在用
FContentBrowserMenuExtender内容浏览器右键菜单
FLevelEditorModule::GetMenuExtensibilityManager关卡编辑器菜单

新代码一律用 UToolMenu——它是数据驱动的可扩展点,FExtender 是遗留机制。

5. 样式

项说明
FAppStyle / FEditorStyle取引擎内置图标与样式
FSlateIcon图标
自定义 FSlateStyleSet自己的图标与样式

用引擎内置样式能保证与编辑器风格一致——自己造的样式在不同版本/主题下容易走样。

6. 与运行时的区别

编辑器 Slate运行时 UI
目标编辑效率玩家体验
所在模块Editor 模块运行时模块
是否打包进游戏否是
对应笔记本篇UI / UMG 深入

编辑器 Slate 代码必须在 Editor 模块里(ModuleType.Editor),否则打包时会引用不存在的编辑器 API。详见 Editor Extension 的模块划分一节。

7. 代价与权衡

设计收益代价什么时候不该用
Slate 自定义窗口完全控制、与原生一致代码量大、要编译简单工具用 EUW
Nomad Tab可停靠、体验好注册与生命周期要管好一次性弹窗用 SWindow
UToolMenu数据驱动、可扩展概念较多老项目沿用 FExtender
自定义样式品牌化与版本主题脱节优先用 FAppStyle
Slate 做复杂布局强调试慢(无可视化编辑)UI 迭代频繁时用 UMG

8. 踩坑与排查

坑现象怎么验证
Slate 代码放运行时模块打包失败检查 .Build.cs 的 Type
Tab 注册了但菜单里没有未设 SetMenuType 或未注册到菜单项检查注册链路
在 StartupModule 时依赖还未就绪的模块启动崩见 引擎启动流程 的 LoadingPhase
自己造样式主题/版本下走样改用 FAppStyle
Slate 里访问 UObject 未加保护对象被 GC 后崩见 GC
编辑器操作不在游戏线程崩见 多线程
窗口关闭后资源未释放泄漏检查 TSharedPtr 持有关系

9. 排查顺序

1. 编译失败/打包失败? → 是否在 Editor 模块
2. Tab 不出现? → 注册链路与 SetMenuType
3. 启动崩? → LoadingPhase 与模块依赖顺序
4. 崩溃在控件里? → 是否访问了已销毁的 UObject/资源
5. 样式不对? → 是否用了自定义样式而非 FAppStyle

参考