How do I set focus on SButton

I have tried my best to figure this out but my lack of experience with slate and my inability to find related questions or forum posts has left me needing help. The best learning resource I found was Reuben Wards youtube tutorial on designing a UI using slate. I have also gone though all related header files and available Unreal Documentation.

My UI looks and works exactly as intended after writing it in slate, and I understand what the code is doing. I just don’t know how to manually set focus on a SButton either at creation or when a button is pressed on either keyboard or gamepad with slate, something I can do with UButton in c++ with no issue.

I can see that in SWidget there is a boolean bIsHovered but I don’t know how to access the SButton after creating it in the ChildSlot. Here’s my not working attempt.

    	ChildSlot
        [
            SNew(SOverlay)
            + SOverlay::Slot()
            .HAlign(HAlign_Fill)
            .VAlign(VAlign_Fill)
            [
                SNew(SConstraintCanvas)
                + SConstraintCanvas::Slot()
                .Anchors(FAnchors(0.05f, 0.05f, .9f, .35f))
                .AutoSize(true)
                .Alignment(FVector2D(5.f,.5f))
                [
                    SNew(SScaleBox)
                    .HAlign(HAlign_Center)
                    .VAlign(VAlign_Center)
                    .Stretch(EStretch::ScaleToFill)
                    [
                        SNew(STextBlock)
                        .ColorAndOpacity(FColor::White)
                        .Font(TitleTextStyle)
                        .Margin(FMargin(12.f))
                        .Text(TitleText)
                        .Justification(ETextJustify::Left)
                    ]
                ]
                // PlayButton
                + SConstraintCanvas::Slot()
                .Anchors(FAnchors(.1f, .4f, .3f, .55f))
                [
                    SNew(SScaleBox)
                    .HAlign(HAlign_Fill)
                    .VAlign(VAlign_Fill)
                    .Stretch(EStretch::ScaleToFit)
                    [
                        SNew(SButton)
                        .ButtonColorAndOpacity(Transparency)
                        .OnClicked(this, &SMainMenuWidget::OnPlayClicked)
                        [
                            SNew(STextBlock)
                            .ColorAndOpacity(FLinearColor(1,1,1,1))
                            .Font(ButtonTextStyle)
                            .Text(PlayText)
                            .Justification(ETextJustify::Left)
                        ]
                    ]
                ]
            ];

        TSharedPtr<SWidget, ESPMode::NotThreadSafe> ActiveButton = ChildSlot.GetChildAt(2);
        UWidget* ActiveWidget = Cast<UWidget>(ActiveButton.Get());
        if(!ActiveWidget){UE_LOG(LogTemp, Error, TEXT("ActiveWidget Cast Failed!!")); return;}
        ActiveWidget->SetFocus();

Removing the last 4 lines results in a successful compile. If more of my code is needed please let me know, I just didn’t want to make this too long as I’m sure that someone that knows slate will have no issue explaining how to do this.

If anyone can show me how to make a SButton hovered by code I would greatly appreciate it!

You can store pointer to widget created in Construct function by using SAssignNew instead of SNew.

1 Like

Thanks so much! I will see how that goes and post my results!

I have updated the code as follows.

Widget header

 TSharedPtr<SButton> PlayButton;
 TSharedPtr<SButton> SettingsButton;
 TSharedPtr<SButton> CustomiseButton;
 TSharedPtr<SButton> QuitButton;

Widget impplementation

ChildSlot
     [
         SNew(SOverlay) ......
         ....// PlayButton
             + SConstraintCanvas::Slot()
             .Anchors(FAnchors(.1f, .4f, .3f, .55f))
             [
                 SNew(SScaleBox)
                 .HAlign(HAlign_Fill)
                 .VAlign(VAlign_Fill)
                 .Stretch(EStretch::ScaleToFit)
                 [
                     SAssignNew(PlayButton, SButton)
                     .ButtonColorAndOpacity(Transparency)
                     .OnClicked(this, &SMainMenuWidget::OnPlayClicked)
                     [
                         SNew(STextBlock)
                         .ColorAndOpacity(FLinearColor(1,1,1,1))
                         .Font(ButtonTextStyle)
                         .Text(PlayText)
                         .Justification(ETextJustify::Left)
                     ]
                 ]
             ]    
     ....
 ];

Accessing the SButton is MUCH easier, thank you so much! I will use SAssignNew to declare widgets that I want future access to.

I just need to work out how to set it to have keyboard focus with code now.

You can make your Slate widgets accept focus by overriding these functions in your widget class and making them returning true:

	virtual bool IsInteractable() const override {return true;}
	virtual bool SupportsKeyboardFocus() const override {return true;}

That is, if you have created a custom widget class.
Then, to bring focus to a widget you can do this:

FSlateApplication::Get().SetKeyboardFocus( MyWidgetPtr.ToSharedRef() );
1 Like

Thank you so much!

I was missing the IsInteractable() override and have added that, I don’t think that would have been an easy find for me!

I was also trying to have the following code run in the widget constructor after creating the ChildSlot, this doesn’t work.

    FSlateApplication::Get().SetKeyboardFocus(PlayButton.ToSharedRef());

A way that does work is to store a reference to the menu widget when its created and then do the following (just in case anyone stumbles across this in search for help on a similar topic)

FSlateApplication::Get().SetKeyboardFocus(MainMenuWidget->PlayButton.ToSharedRef());

This is exactly what I needed, thank you so much!

Now the last piece of the puzzle… I thought OnHover and OnUnhover would work the same as OnClicked but it needs a FSimpleDelegate and I can’t find any examples on either OnHover or OnUnhover, are you able to point me in the right direction for that also?

Maybe this helps

Slate/UMG hover handling - Development Discussion / C++ Gameplay Programming - Unreal Engine Forums

1 Like

Thanks for the link! I’m not 100% sure on what they did to resolve this, did they write a custom button and override OnMouseEnter? Is there still no straightforward way of handling widgets hovering?

At the bottom of the post they say that “it’s in the master branch, should be in 4.11 as well I think”. Does this mean that there is a potentially different way this is handled?

Sorry about my confusion, this is probably a little out of my scope but I am a quick learner!

I didn’t have my delegate signatures right! I was just looking at the problem too closely…

All sorted! Thanks!