UE4 插件扩展引擎工具栏

  UE4 作为游戏引擎,已经提供了非常强大的游戏开发的API。作为游戏制作者来讲,我们需要一些专用的功能辅助我们更好的开发游戏,而不是仅仅从构建游戏逻辑出发。因此也就有了扩展编辑器功能的这个想法,还好 UE4 提供了许多编辑器的接口,便于我们给编辑器添加我们的功能。

  下面是一个扩展编辑器工具栏的例子,我们增加了一个自己的按钮。这个在新建插件,选择 Editor Standalone Window 就可以实现此效果。我这里新建一个空的插件,来实现这个效果,以便于理解。

  

  UE4 是以模块的功能构建项目,插件也是一种模块,便于移植更新,所以我们将代码以插件结构的形式呈现。

  首先,新建一个空白插件 ExtendedToolBarPlugin ,如红色方框内容

  

  ***.uplugin 是插件描述文件

{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "FriendlyName": "ExtendedToolBarPlugin",
    "Description": "",
    "Category": "Other",
    "CreatedBy": "Jqm",
    "CreatedByURL": "",
    "DocsURL": "",
    "MarketplaceURL": "",
    "SupportURL": "",
    "CanContainContent": true,
    "IsBetaVersion": false,
    "Installed": false,
    "Modules": [
        {
            "Name": "ExtendedToolBarPlugin",//插件的名字
            "Type": "Editor",//插件的类型,修改为Editor .
            "LoadingPhase": "Default"
        }
    ]
}

  ***.Build.cs 是插件中模块 ExtendedToolBarPlugin 的描述,定义了该模块的引用头文件信息,引用库信息,以及扩展依赖等。稍后,我们主要会在里面添加模块依赖,以便于我们引用编辑器的 API。

  ***.h 和 ***.cpp 定义了该模块和引擎的接口。

//***.hclass FExtendedToolBarPluginModule : public IModuleInterface
{
public:

    /** IModuleInterface implementation */

    //当模块被加载时调用
    virtual void StartupModule() override;

    //当模块被卸载时调用
    virtual void ShutdownModule() override;

  // 新增函数  void ButtonClicked();

   // 向工具栏中添加按钮
   void AddToolbarExtension(FToolBarBuilder& Builder);

  TSharedPtr<class FUICommandList> ButtonClickCommands;
};

void FExtendedToolBarPluginModule::AddToolbarExtension(FToolBarBuilder& Builder)


{
  Builder.AddToolBarButton(FWindowTestCommands::Get().
OpenPluginWindow);

}


  以上就是整个插件的结构,编译成功插件就行正常运行。但是仅仅是插件正常运行,并未加入任何功能。

  我们开始对 Editor Standalone Window 的分析,发现在模块初始化函数 StartupModule() 中,获取了编辑器模块 FLevelEditorModule& LevelEditorModule, 然后新增加了一个扩展 MakeShareable(new FExtender()) ,然后将新增加的扩展加入到编辑器的工具栏管理模块中。 重点是这个新增加的扩展,设置了一些属性,标记扩展的是编辑器的哪一部分,传递了一个命令,这个命令用来响应触发这个按钮的消息,相当于一个回调,等信息。

  首先,我们来构建这个扩展所需要的内容。

  我们第一步创建这个命令:在插件中新建一个类 FWindowTestCommands,该类继承至一个模板类TCommands,该模板类以自己的定义作为模板,并且提供了注册命令和卸载的一系列方法。所以我们继承它就可以实现编辑器所需要的命令。

 

// ***.h// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Framework/Commands/Commands.h"
#include "WindowTestStyle.h"

class FWindowTestCommands : public TCommands<FWindowTestCommands>
{
public:

    FWindowTestCommands()
        : TCommands<FWindowTestCommands>(TEXT("WindowTest"), NSLOCTEXT("Contexts", "WindowTest", "WindowTest Plugin"), NAME_None, FWindowTestStyle::GetStyleSetName())
    {
    }

    // TCommands<> interface
    virtual void RegisterCommands() override;

public:
    TSharedPtr< FUICommandInfo > OpenPluginWindow;
};
// ***.cpp// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "WindowTestCommands.h"

#define LOCTEXT_NAMESPACE "FWindowTestModule"

void FWindowTestCommands::RegisterCommands()
{
    UI_COMMAND(OpenPluginWindow, "WindowTest", "Bring up WindowTest window", EUserInterfaceActionType::Button, FInputGesture());
}

#undef LOCTEXT_NAMESPACE
 TCommands<FWindowTestCommands>(TEXT("WindowTest"), NSLOCTEXT("Contexts", "WindowTest", "WindowTest Plugin"), NAME_None, FWindowTestStyle::GetStyleSetName())传递了4个参数,分别是命令的名字,命令的描述,命令的的上下级,命令的风格。
 RegisterCommands()将命令进行注册。

命令的风格。再 RegisterCommands()注册编辑器的时候,有个枚举类型 EUserInterfaceActionType::Button ,说明是个按钮,那么这个风格说的就是响应按钮的这个风格,因此,我们在构造命令是也传入的一个风格。现在我们新建一个风格,传入给命令。

在插件中新建一个类 FWindowTestStyle ,这个类全是静态函数。它提供了风格的创建,销毁等方法。
// ***.h// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Styling/SlateStyle.h"

/**  */
class FWindowTestStyle
{
public:

    static void Initialize();

    static void Shutdown();

    /** reloads textures used by slate renderer */
    static void ReloadTextures();

    /** @return The Slate style set for the Shooter game */
    static const ISlateStyle& Get();

    static FName GetStyleSetName();

private:

    static TSharedRef< class FSlateStyleSet > Create();

private:

    static TSharedPtr< class FSlateStyleSet > StyleInstance;
};

在创建风格时,他寻找了插件下面的资源图片作为自己的Icon。

// ***.cpp// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "WindowTestStyle.h"
#include "Styling/SlateStyleRegistry.h"
#include "Framework/Application/SlateApplication.h"
#include "SlateGameResources.h"
#include "IPluginManager.h"

TSharedPtr< FSlateStyleSet > FWindowTestStyle::StyleInstance = NULL;

void FWindowTestStyle::Initialize()
{
    if (!StyleInstance.IsValid())
    {
        StyleInstance = Create();
        FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance);
    }
}

void FWindowTestStyle::Shutdown()
{
    FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance);
    ensure(StyleInstance.IsUnique());
    StyleInstance.Reset();
}

FName FWindowTestStyle::GetStyleSetName()
{
    static FName StyleSetName(TEXT("ExtendedToolBarStyle"));
    return StyleSetName;
}

#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
#define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
#define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
#define TTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".ttf") ), __VA_ARGS__ )
#define OTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".otf") ), __VA_ARGS__ )

const FVector2D Icon16x16(16.0f, 16.0f);
const FVector2D Icon20x20(20.0f, 20.0f);
const FVector2D Icon40x40(40.0f, 40.0f);

TSharedRef< FSlateStyleSet > FWindowTestStyle::Create()
{
    TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("ExtendedToolBarStyle"));
    Style->SetContentRoot(IPluginManager::Get().FindPlugin("ExtendedToolBarPlugin")->GetBaseDir() / TEXT("Resources"));

    Style->Set("ExtendedToolBarPlugin.ButtonClick", new IMAGE_BRUSH(TEXT("ButtonIcon_40x"), Icon40x40));

    return Style;
}

#undef IMAGE_BRUSH
#undef BOX_BRUSH
#undef BORDER_BRUSH
#undef TTF_FONT
#undef OTF_FONT

void FWindowTestStyle::ReloadTextures()
{
    if (FSlateApplication::IsInitialized())
    {
        FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
    }
}

const ISlateStyle& FWindowTestStyle::Get()
{
    return *StyleInstance;
}

  现在,基本上所有资源都准备完毕,就下来就开始写逻辑,将整个流程实现。

  在 ExtendedToolBarPlugin 模块中,初始化模块阶段,也就是 StartupModule() 函数中,我们开始创建风格和命令:

    // 注册编辑器插件风格
    FWindowTestStyle::Initialize();
    FWindowTestStyle::ReloadTextures();

    // 注册编辑器插件命令
    FWindowTestCommands::Register();

  创建插件命令 ExtendedToolBarCommands,这个在模块类定义,

// 创建插件编辑器命令
    ExtendedToolBarCommands = MakeShareable(new FUICommandList);
    ExtendedToolBarCommands->MapAction(FWindowTestCommands::Get().OpenPluginWindow, FExecuteAction::CreateRaw(this, &FExtendedToolBarPluginModule::ButtonClicked), FCanExecuteAction());

  然后,加入到编辑器中,

  AddToolBarExtension 第一个参数:是指添加到 工具栏的 Settings 部分;

  第二个参数是在这个部分的位置,前面,后面或第一个;

  第三个参数,是前面创建的命令,传递进去;

  第四个参数,是添加到编辑器的按钮;

    FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
    {
        TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
        ToolbarExtender->AddToolBarExtension("Settings", EExtensionHook::After, JqmToolsEditorCommands, FToolBarExtensionDelegate::CreateRaw(this, &FExtendedToolBarModule::AddToolbarExtension));

        LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
    }

  到此,整个流程走完。

  总结一下,按照顺序,应该是初始化模块入口函数里:

  1.创建风格

  2.创建命令

  3.绑定命令

  4.创建工具栏扩展

  5.添加的到工具栏

  

  
 
 

原文地址:https://www.cnblogs.com/jqm304775992/p/8996470.html

时间: 2024-10-18 19:12:27

UE4 插件扩展引擎工具栏的相关文章

UE4插件

翻译的有点烂,有错误的地方欢迎大家指出,原文请查看UE4官方插件文档 这篇文章讲述了如何使用UE tools 和runtime开发自己的插件. 许多UE子系统都是可扩展的,允许你添加新的功能,修改内置的功能而不需要修改引擎代码.你可以添加新的文件类型,添加新的菜单项和工具栏命令到编辑器中,甚至添加新功能和编辑器子模式. 如果你现在就想试着使用插件,可以直接观看Plugin Examples部分 Plugins Editor UI Anatomy of a Plugin插件剖析 Plugin Fo

最值得收藏优秀推荐的 Google Chrome 谷歌浏览器插件扩展推荐列表

由于 Chrome 已经不允许用户安装非应用商店的第三方 .crx 扩展了,所以这里只提供了 Google Webstore 应用商店的官方下载地址.因为众所周知的原因,国内访问可能需要使用各种「番·羽·士·啬·工·具」才行,这里不多做讨论,大家各显神通吧…… Chrome App 浏览器应用: ARC Welder:谷歌官方推出的安卓模拟器,可以在 Win/Mac/Linux 的 Chrome 浏览器上运行安卓应用 Vysor:在电脑上通过 USB 数据线直接远程操作 Android 手机,并

JQuery时间格式化插件--扩展JQuery

(function($){ $.formatDate = function(pattern,date){ //如果不设置,默认为当前时间 if(!date) date = new Date(); if(typeof(date) ==="string"){ if(date=="") date = new Date(); else date = new Date(date.replace(/-/g,"/")); } /*补00*/ var toFix

jQuery的noConflict以及插件扩展

一.noConflict函数 JavaScript有很多插件,如果jQuery对象的$与其他插件冲突,我们可以使用noConflict()方法去掉$或者使用其他的符号代替 注:noConflict()函数不能调用两次,上面代码是方便向读者展示 二.jQuery的插件扩展 jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法. jQuery 的全局函数就是属于jQuery命名空间的函数,另一种是对象级别的插件开发,即给jQu

QML插件扩展2(基于C++的插件扩展)

上一节介绍了纯QML的插件扩展方式,这种扩展方式基本满足大部分的扩展需求,下面开始介绍比较小众的基于C++的扩展 (一)更新插件工程 1.更新MyPlugin工程下的qmldir文件,加入plugin MyPlugin, 其中MyPlugin是插件的动态库名称,在windows下对应MyPlugin.dll,在linux下多月MyPlugin.so 2.编译MyPlugin插件,生成MyPlugin.dll,这里工程没有copy配置,所以默认dll不会拷贝到E:/T/QMLPlugin/QMLP

QML插件扩展(一)

准备分两节来介绍QML扩展插件,分别为 (一)基于QML文件的扩展方式 (二)基于C++的插件扩展 这篇先介绍基于QML的插件扩展. 先介绍几个基本概念: qmldir: 用于组织自定义的QML插件,qmldir的具体写法可参考 .qmltypes:qml插件的解释文件,用于QtCreator语法高亮.可通过Qt提供的工具qmlplugindump自动生成 QML_IMPORT_PATH: 导入插件路径,以支持插件的语法高亮.个人理解是如果纯QML文件的扩展,没有封装到C++中,则直接导入路径,

【干货】Chrome插件(扩展)开发全攻略

[干货]Chrome插件(扩展)开发全攻略 http://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html

AppCan Widget插件扩展机制

AppCan Widget插件扩展机制,通过AppCan平台生成的应用,可以理解为一个Widget包(即在IDE创建项目是看到的'phone'文件夹),和一个AppCan平台中间件组成的.通常的情况下,一个应用是由一个Widget+AppCan构成,那么,有没有可能说'n个Widget+AppCan'的机制呢,答应是肯定的,这就是Widget 插件机制,是针对主widget以及普通widget的一种增强性的扩展机制,可以将具有特定功能的widget封装成一个单独的widget包存放到plugin

[UE4插件使用-问题合集-02] error C4458: declaration of &#39;ModuleIndex&#39; hides class member 函数参数使用的参数名字与所在类中的某个变量名字重名了

error C4458 函数参数名与所在类的变量名重名 问题描述: 解决过程: 我这边报错的那行是宏定义,所以要找到宏定义处,是放到另一文件中的,可以看到这个宏定义是定义了函数的: 可以看到这个函数形参有一个是"ModuleIndex",没错,就是它与类中某个变量同名的.类中的那个同名变量我这里就不找了,你们知道就行了.实际上这样的C++语法是没有问题的,内层作用域中与外层作用域中同名的变量会隐藏外层的同名变量,但可能同样是版本的原因,新版本的UE4(我这里是4.24)对于这种情况视为