Hello Everyone,
First of all, I am terribly sorry for this huge wall of a post, but i don’t know how to make it shorter without falling in the usual “how do i use 3D widgets ?” questions.
I have tried, sincerely, for a whole week, and just gathered problems and questions, while slowly becoming crazy
So let’s start.
All i want to do is define one style and use it everywhere.
I am trying to use 3D widget as (i understood) they should be when coding: define the layout in the editor, and set all the logic in c++.
So, having a lot of elements, i naturally need to centralize all the styling and would like to use some WidgetStyle for that.
I’m not going to show all my trials and errors, but i ended up with the current workflow that sort of works:
- C++: define a structure inheriting from FSlateWidgetStyle and containing all the styles i need, such as:
// button style
UPROPERTY(EditAnywhere, Category = "Yag")
FButtonStyle YagButtonStyle;
// normal text
UPROPERTY(EditAnywhere, Category = "Yag")
FTextBlockStyle YagTextStyle;
// editable test brush
UPROPERTY(EditAnywhere, Category = "Yag")
FSlateBrush YagEditableTextBrush;
- Editor: create a WidgetStyle BP inheriting from it, and set all my styles inside:
-
C++: create a c++ StyleSet using code from this wiki (adapted from menuStyle.h and menuStyle.cpp):
https://wiki.unrealengine.com/Slate_Style_Sets_Part_2 -
C++: create a “mother widget” class inheriting from UUserWidget (ALL my BP widget will inherit from this class).
-
C++: in my mother widget class, define the following SetStyle function:
void UYagMainWidget::SetStyle()
{
UE_LOG(LogTemp, Warning, TEXT("SetStyle"));
if (!WidgetTree) return;
UE_LOG(LogTemp, Warning, TEXT("SetStyle Widget OK"));
// get styles
YagGlobalStyle = FYagGlobalStyle::Get().GetWidgetStyle<FYagStyle>("YagGlobalStyle");
YagButtonStyle = YagGlobalStyle.YagButtonStyle;
YagTextStyle = YagGlobalStyle.YagTextStyle;
// set style on every child widget
WidgetTree->ForEachWidget(&](UWidget* Widget)
{
UButton* ThisButton = Cast<UButton>(Widget);
if (ThisButton)
{
ThisButton->SetStyle(YagButtonStyle);
UE_LOG(LogTemp, Warning, TEXT("UButton style OK"));
}
UTextBlock* ThisTextBlock = Cast<UTextBlock>(Widget);
if (ThisTextBlock)
{
ThisTextBlock->SetColorAndOpacity(YagTextStyle.ColorAndOpacity);
ThisTextBlock->SetFont(YagTextStyle.Font);
UE_LOG(LogTemp, Warning, TEXT("UTextBlock style OK"));
}
UEditableTextBox* ThisEditableTextBox = Cast<UEditableTextBox>(Widget);
if (ThisEditableTextBox)
{
ThisEditableTextBox->WidgetStyle.SetForegroundColor(YagTextStyle.ColorAndOpacity);
ThisEditableTextBox->WidgetStyle.SetFont(YagTextStyle.Font);
UE_LOG(LogTemp, Warning, TEXT("UEditableTextBox style OK"));
}
});
}
-
C++: create daughter class widget inheriting from the mother, that will contain specific logic for each UI
-
Editor: create BP 3D widget inheriting from the daughter classes, and make incredibly great UIs using buttons and texts
In the following capture, YagSettingsWidget is a c++ (daughter) class inheriting from my mother UUserWidget class (which is called YagMainWidget)
At this point i get a first problem that seems to hapen only with EditableTextBox: the style is correctly defined but not applied.
In the herabove capture, you can that both the UTextBlock (connect and listen) are correctly styled, but the EditableTextBox is not, despite having the correctly defined style (large red letters).
If i modify the editable text (changing any property, including the text), then the style applies correctly:
But when i compile, it comes back to its original style:
All that said, when i click play in the editor, it works:
Horray ? Not so fast.
I tried to package my game and here’s what i get in the packaged game:
As you can see, the buttons not only have no style (no transparency and incorrect font and color) but are super small.
I am absolutely sure that the BP widgetstyle is available because:
- i force its packaging in the editor settings:
- i have put logs in the setstyle function and i go through all the ifs, as showed by this extract (log from the packaged game):
So in the packaged game, the SetStyle() function is called and seems to succeed in everything it tries to do, but with no visible effect.
One important question IMO is where should i call the SetStyle function ?
I have tried to put it in Initialize()/constructor (=>editor crash), and even in various tick functions (widgets, pawn, playercontroller…) (=> no visible effect).
The only way i can have it working in PIE is to call it in the OnWidgetRebuilt() function:
UYagMainWidget::UYagMainWidget(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//SetStyle(); // editor crash
}
bool UYagMainWidget::Initialize()
{
Super::Initialize();
//SetStyle(); // editor crash
return true;
}
void UYagMainWidget::OnWidgetRebuilt()
{
Super::OnWidgetRebuilt();
SetStyle(); // works in PIE only
}
So here am i.
Am i completely out of range here ? What would be the correct/official way to achieve a style centralization/automation ?
Thanks !
Cedric