Slate Editor Window Quickstart Guide

Build a simple editor window using Slate.

Choose your operating system:

Windows

macOS

Linux

This is a step-by-step guide on how to create a simple editor window that responds to user input using Slate, Unreal Engine's UI framework. This page does not provide a comprehensive guide on how Slate interacts with other systems. Rather, it focuses on the fundamentals of how Slate's syntax relates to the layout of your UI, and the basics of making your UI respond to events.

1. Project Setup

This guide uses a new project called SlateQuickstartGame with the following settings:

  • Template: Third-Person Project

  • C++ Project

You can also follow this guide using an existing project. This project does not depend on any specific target platform, as it focuses on editor functionality.

2. Creating a Window Plugin

To get started on your new editor window quickly, open the Edit > Plugins window, then click the + Add button to create a new plugin. Choose Editor Standalone Window as the plugin type, then call it SlateQuickstartWindow. Click Create Plugin to finish.

Click to enlarge image.

This automatically creates the Plugin module with the necessary C++ classes to support a basic editor window. Close the editor and recompile your project, then open the project again. You can find your new editor window under the Window dropdown.

Click to enlarge image.

When you initially view this window, it will display placeholder text but no interactive elements.

Understanding the Window's Code

Before continuing to build your menu, you should review the code in SlateQuickstartWindowModule.cpp for a quick preview of how to use Slate's declarative syntax. The Slate code is contained in the OnSpawnPluginTab function. When you initially view it, the function reads as follows:

TSharedRef<SDockTab> FSlateQuickstartWindowModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)

{
    FText WidgetText = FText::Format(

        LOCTEXT("WindowWidgetText", "Add code to {0} in {1} to override this window's contents"),
        FText::FromString(TEXT("FSlateQuickstartWindowModule::OnSpawnPluginTab")),
        FText::FromString(TEXT("SlateQuickstartWindow.cpp"))

        );

    return SNew(SDockTab)
    .TabRole(ETabRole::NomadTab)
    [
        // Put your tab content here!

        SNew(SBox)
        .HAlign(HAlign_Center)
        .VAlign(VAlign_Center)
        [
            SNew(STextBlock)
            .Text(WidgetText)
        ]
    ];

}

This function performs the following steps:

  1. Builds a string called WidgetText using FText::Format to combine several strings.

  2. Defines a new SDockTab using the SNew function. This represents the dockable window.

  3. Fills the SDockTab with an SBox element which can contain content. This box has HAlign and VAlign parameters that align it to the center of the window.

  4. Adds a new STextBlock to the SBox and sets its text to the value of WidgetText.

  5. Returns the SDockTab containing all these UI elements.

The best way to understand how this works is to think of how you would create a similar user interface in UMG. To re-create this in UMG, you would drag a box widget onto the stage as the root UI element, then place a Text widget inside of it and change its alignment to center. The stage and hierarchy would resemble the following image.

Click to enlarge image.

In the case of the SlateQuickstartWindow, the viewport stage is replaced with the SDockTab widget. When you review the code, the square brackets define what elements are nested inside a given widget, while periods set the value of the parameters you would see in the Details panel.

For more information about Slate's declarative syntax, refer to the Slate Overview.

3. Creating a Slate Widget For the Menu

You can add Slate widgets directly to the FSlateQuickstartWindowModule class generated by the Plugin wizard. However, there are some limitations to how you can handle your widgets' callbacks if you do this. Therefore, you should create a dedicated Slate widget to hold the menu's contents, then add that widget to the FSlateQuickstartWindowModule class.

  1. In the Content Drawer, click the C++ Classes folder, then right-click and click New C++ Class.

    Click to enlarge image.

  2. In the Add C++ Class window, select Slate Widget, then click Next.

  3. Change your new C++ class's settings as follows:

    Click to enlarge image.

    • Class Type: Public

    • Name: QuickStartWindowMenu

    • Module: SlateQuickstartWindow (Editor)

    Click Create Class to finish.

Make sure you set the Module drop-down to the SlateQuickstartWindow module before you click Create Class. This adds the class to your plugin's code. If you don't do this, the wizard will put it in your game's code, and your Slate widget will not be visible to the plugin.

The wizard creates a new C++ class called SQuickStartWindowMenu in your plugin's Source folder, then regenerates your project's Visual Studio solution.

4. Populating Your Menu With Widgets

To add Slate widgets to your menu, open SQuickStartWindowMenu.cpp and add them to the Construct function. When you initially view this function, it reads as follows:

void SQuickStartWindowMenu::Construct(const FArguments& InArgs)
{
    /*
    ChildSlot
    [
        // Populate the widget
    ];
    */
}

Follow these steps to populate the window:

  1. Delete the commented-out code inside the Construct function.

  2. Inside the Construct function, add a new SVerticalBox with the SNew function. Follow that with two +SVerticalBox::Slot() elements. Give both slots the .AutoHeight() property.

  3. Inside the first Vertical Box slot, add a SHorizontalBox with two slots. Give both slots the .VAlign(VAlign_Top) property.

    SNew(SHorizontalBox)
    +SHorizontalBox::Slot()
    .VAlign(VAlign_Top)
    [
    ]
    +SHorizontalBox::Slot()
    .VAlign(VAlign_Top)
    [
    ]

This will nest the horizontal box inside the vertical box, effectively dividing this first slot into two columns.

  1. In the first horizontal slot, add a new STextBlock widget. Set the .Text to FText::FromString("Test Button").

    SNew(STextBlock)
    .Text(FText::FromString("Test Button"))

Whenever you display user-facing text, you should use FText instead of FString or other methods of displaying text, as it provides support for localization. For more information, refer to Text Localization.

  1. In the second horizontal slot, add a new SButton widget. Set its .Text to FText::FromString("Press Me").

    SNew(SButton)
    .Text(FText::FromString("Press Me"))
  2. In the second Vertical Box slot, create another Horizontal Box with two slots. Give the first horizontal slot a STextBlock widget that reads "Test Checkbox", then add a SCheckBox widget to the second horizontal slot.

    SNew(SHorizontalBox)
    +SHorizontalBox::Slot()
    .VAlign(VAlign_Top)
    [
        SNew(STextBlock)
        .Text(FText::FromString("Test Checkbox"))
    ]
    +SHorizontalBox::Slot()
    .VAlign(VAlign_Top)
    [
        SNew(SCheckBox)
    ]
  3. The full definition of your Slate window should now read as follows:

    SNew(SVerticalBox)
    +SVerticalBox::Slot()
    .AutoHeight()
    [
        SNew(SHorizontalBox)
        +SHorizontalBox::Slot()
        .VAlign(VAlign_Top)
        [
            SNew(STextBlock)
            .Text(FText::FromString("Test Button"))
        ]
        +SHorizontalBox::Slot()
        .VAlign(VAlign_Top)
        [
            SNew(SButton)
            .Text(FText::FromString("Press Me"))
        ]
    ]
    +SVerticalBox::Slot()
    .AutoHeight()
    [
        SNew(SHorizontalBox)
        +SHorizontalBox::Slot()
        .VAlign(VAlign_Top)
        [
            SNew(STextBlock)
            .Text(FText::FromString("Test Checkbox"))
        ]
        + SHorizontalBox::Slot()
        .VAlign(VAlign_Top)
        [
            SNew(SCheckBox)
        ]
    ]
  4. Save and compile your code, then open your project in Unreal Editor and open your window.

    You can't compile Slate windows while Live Coding is active and your project is open in Unreal Editor. Make sure to close Unreal Editor before trying to compile your code.

    When you open your window, it should look like this:

    Preview of the test window

    Neither the button or the checkbox do anything yet, but you will add functionality to them in the next section.

5. Binding Events to Interactive Widgets

Interactive Slate widgets use events to respond to interactions like clicking or toggling. In this section, you will create several delegates to drive the interaction for the checkbox and button from the previous section.

  1. Open SQuickStartWindowMenu.h and declare the following functions and variables:

    public: 
    FReply OnTestButtonClicked();
    void OnTestCheckboxStateChanged(ECheckBoxState NewState);
    ECheckBoxState IsTestBoxChecked() const;
    
    protected:
    bool bIsTestBoxChecked;

    The functions will contain the logic that runs when you click the test button and test checkbox. The checkbox will use the IsTestBoxChecked function to determine what state it should display, and bIsTestBoxChecked will cache that state.

  2. In SQuickStartWindowMenu.cpp, provide the following implementations for the checkbox's functions:

    void SQuickStartWindowMenu::OnTestCheckboxStateChanged(ECheckBoxState NewState)
    {
        bIsTestBoxChecked = NewState == ECheckBoxState::Checked ? true : false;
    }
    
    ECheckBoxState SQuickStartWindowMenu::IsTestBoxChecked() const
    {
        return bIsTestBoxChecked ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
    }

    These provide a getter and setter for the checkbox's current state. The OnTestCheckboxStateChanged function will set the value of bIsTestBoxChecked depending on what the user changes the checkbox's state to. Meanwhile, the IsTestBoxChecked function will read that variable and translate it back into an ECheckBoxState.

  3. Add the .OnCheckStateChanged parameter to the SCheckBox widget, and provide a reference to the FSlateQuickstartModule::OnTestCheckboxStateChanged function. Then, add the IsChecked parameter, and provide a reference to the SQuickStartWindowMenu::IsTestBoxChecked function.

    +SHorizontalBox::Slot()
    .VAlign(VAlign_Top)
    [
        SNew(SCheckBox)
        .OnCheckStateChanged(FOnCheckStateChanged::CreateSP(this, &SQuickStartWindowMenu::OnTestCheckboxStateChanged))
        .IsChecked(FIsChecked::CreateSP(this, &SQuickStartWindowMenu::IsTestBoxChecked))
    ]

    You now have a mechanism to track when the user checks and unchecks the SCheckBox widget.

  4. Provide the following implementation for the OnTestButtonClicked function:

    FReply SQuickStartWindowMenu::OnTestButtonClicked()
    {
        UE_LOG(LogTemp, Warning, TEXT("Hello, world! The checkbox is %s."), (bIsTestBoxChecked ? TEXT("checked") : TEXT("unchecked")));
        return FReply::Handled();
    }

    This function outputs a short message to the output log stating whether the checkbox is checked.

  5. Add the .OnClicked parameter to the SButton, then provide a reference to the SQuickStartWindowMenu::OnTestButtonClicked function.

    +SHorizontalBox::Slot()
    .VAlign(VAlign_Top)
    [
        SNew(SButton)
        .Text(FText::FromString("Press Me"))
        .OnClicked(FOnClicked::CreateSP(this, &SQuickStartWindowMenu::OnTestButtonClicked))
    ]

6. Adding Your Menu to the Window

Finally, you need to add the Slate widget you created to the menu tab's code.

  1. Open SlateQuickstartWindowModule.cpp and delete the contents of the SDockTab. Its code should now read as follows:

  2. Add your SQuickStartWindowMenu widget inside the SDockTab.

    SNew(SQuickStartWindowMenu)

Save and compile your code, then open Unreal Editor and test your window.

Final Result

When you click the test button, your console log should print the message "Hello, world! The checkbox is unchecked." If you check the check box, it should print the message "Hello, world! The checkbox is checked." This provides a basic working example of a Slate window which you can expand on to create custom editor windows.

On Your Own

For examples of different Slate widgets and the many ways they can bind delegates, refer to STestSuite.cpp. You can find this in your engine's install directory under Source\Runtime\AppFramework\Private\Widgets\Testing. You can experiment with these widgets to create different layouts and interactive elements. You can also experiment with using Slate UI elements to interact with assets or data in your project, or the World in the level editor.

Tags
This page was written for a previous version of Unreal Engine and has not been updated for the current Unreal Engine 5.1 release.