I’m attempting to create a custom SCompoundWidget
which will act as an easy to use drop down menu within Slate UI. I’m doing this in c++.
As it stands, the project compiles and runs. It shows the drop down menu normally enough at first. The issue is that when I click one of the options displayed within the drop down menu, it appears to create a new drop down and stack it on top of the old.
For example, suppose I have the following items within my drop down:
Example
Test
p1
The drop down will open with Example as it is the first and default item within the list. The drop down menu appears with AutoWidth()
so it is only as wide as it needs to be. Notice how ‘Example’ is the longest (width wise) item within our drop down menu.
If I then click the drop down, the menu will appear as normal.
Once I select one of the options, say ‘Test’, it looks like a new drop down menu appears stacked on top of the previous menu. It appears stacked because the width of this new menu is shorter as ‘Test’ is shorter width-wise than ‘Example’.
I cannot interact with the previous menu, and in fact, when using the Unreal Engine ‘Widget Inspector’ tool, there is truly only one SComboButton on my widget even though two seem to be there.
The same is true if I then open the drop down and select ‘p1’ which is shorter than ‘Test’. Now it appears that there are three drop down menus stacked on top of each other.
Any help would be appreciated. Below is my code:
/* SDropDown.h */
#pragma once
#include "CoreMinimal.h"
// Represents a single entry within a dropdown menu
struct FMenuEntry
{
FMenuEntry(FText Label, TFunction<void()> Action = (), FText Tooltip = FText.GetEmpty(), FSlateIcon Icon = FSlateIcon())
{
this->Label = Label;
this->Action = Action;
this->Tooltip = Tooltip;
this->Icon = Icon;
}
// The text that appears within the drop down menu entry
FText Label;
// An optional function to fire when the user selects the given entry
TFunction<void()> Action;
// An optional tooltip that appears upon hover
FText Tooltip;
// An optional icon to appear to the left
FSlateIcon Icon;
};
class MYPROJ_API SDropDown : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SDropDown) :
_MenuEntries(TArray<FMenuEntry>())
{ }
SLATE_ARGUMENT(TArray<FMenuEntry>, MenuEntries)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
virtual bool SupportsKeyboardFocus() const override { return true; }
private:
// Represents all entries within the drop down menu. Passed in via SLATE_ARGUMENT
TArray<FMenuEntry> MenuEntries;
// This is the text shown on the drop down button
FText FeaturedItem;
// This is the drop down menu slate widget
TSharedPtr<SComboButton> ComboButton;
// This function is for binding the ComboButtons Button Text to the FeaturedItem
FText GetFeaturedItem() const;
};
/* SDropDown.cpp */
#include "SDropDown.h"
void SDropDown::Construct(const FArguments& InArgs)
{
// Bind the arguments to member variable
this->MenuEntries = InArgs._MenuEntries;
if(!MenuEntries.Num())
{
UE_LOG(LogSlate, Fatal, TEXT("You didn't include any menu entries within your menu. Enter at least one..."));
return;
}
// Set the default value of the drop down menu to the first item in the list
FeaturedItem = MenuEntries[0].Label;
FMenuBuilder Menu(true, nullptr);
for(const FMenuEntry Entry : MenuEntries)
{
// Add a menu entry for every item in MenuEntries
Menu.AddMenuEntry(Entry.Label, Entry.Tooltip, Entry.Icon, FUIAction(FExecuteAction::CreateLambda( [this, Entry] ()
{
// Set the FeaturedItem to the clicked on Label
// This changes because we bind the ButtonContent STextBlock Text to be whatever FeaturedItem is
if(ComboButton.IsValid())
{
FeaturedItem = Entry.Label;
}
// Execute whatever other function was passed in
if(Entry.Action)
{
Entry.Action();
}
}
)));
}
ChildSlot
[
SAssignNew(ComboButton, SComboButton)
.ButtonContent()
[
SNew(STextBlock)
.Text(this, &SDropDown::GetFeaturedItem) // This line binds the FeaturedItem to this text so whenever the variable changes, so does this text
]
.MenuContent()
[
Menu.MakeWidget()
]
];
}
FText SDropDown::GetFeaturedItem() const
{
return FeaturedItem;
}