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 | 顶层窗口 |
FTabManager | Tab 管理器,注册后可从菜单打开 |
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. 菜单扩展
| 机制 | 状态 |
|---|---|
UToolMenu | UE5 的推荐方式 |
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参考
- Slate 实践(语法基础) · Editor Extension(模块划分)
- Editor 工具与 Utility · 模块与 Subsystem · 引擎启动流程
- GC 与对象生命周期 · 多线程与 Task Graph
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/9bbc8715.html
更新于:2026年10月10日