Hello, I’m wondering how I can change the underlying SObjectWidget of the UUserWidget class.
By going through some source code I found out that the SObjectWidget is constructed in UUserWidget::TakeWidget()
. The the function documentation says the following: If you're looking to replace what slate widget gets constructed look for RebuildWidget.
.
I have overrode the function along making my own SCustomObjectWidget like this:
SCustomObjectWidget.h
class SCustomObjectWidget
: public SObjectWidget
{
public:
SLATE_BEGIN_ARGS(SCustomObjectWidget)
: _Content()
{
}
/** Widget contents. */
SLATE_DEFAULT_SLOT(FArguments, Content)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
{
ChildSlot
[
InArgs._Content.Widget
];
}
};
CustomUserWidget.cpp
TSharedRef<SWidget> UCustomUserWidget::RebuildWidget()
{
TSharedRef<SWidget> Inner = Super::RebuildWidget();
TSharedRef<SWidget> UserRootWidget = SNew(SCustomObjectWidget)
[
Inner
];
return UserRootWidget;
}
My custom RebuildWidget is called, however the result is never actually used. It’s called from UWidget::TakeWidget_Private()
, however this if block always enters in its inner else branch, using the ConstructionMethod
passed from outside, which always constructs the SObjectWidget
.
The if block:
// If it is a user widget wrap it in a SObjectWidget to keep the instance from being GCed
if (IsA(UUserWidget::StaticClass()))
{
TSharedPtr<SObjectWidget> SafeGCWidget = MyGCWidget.Pin();
// If the GC Widget is still valid we still exist in the slate hierarchy, so just return the GC Widget.
if (SafeGCWidget.IsValid())
{
ensure(bNewlyCreated == false);
PublicWidget = SafeGCWidget;
}
else // Otherwise we need to recreate the wrapper widget
{
SafeGCWidget = ConstructMethod(Cast<UUserWidget>(this), PublicWidget.ToSharedRef());
MyGCWidget = SafeGCWidget;
PublicWidget = SafeGCWidget;
}
}
What passed the ConstructionMethod
:
TSharedRef<SWidget> UWidget::TakeWidget()
{
return TakeWidget_Private(
[](UUserWidget* Widget, TSharedRef<SWidget> Content)
-> TSharedPtr<SObjectWidget>
{
return SNew(SObjectWidget, Widget)[Content];
}
);
There is no way to change the UWidget::TakeWidget()
since it’s not virtual, and the UWidget::TakeWidget_Private()
is private, as the name implies, hence the ConstructionMethod
is always the same. There is no other place the SafeGCWidget
is initialized either.
This makes me understand that the passed any UUserWidget
will always have SObjectWidget
as the underlying UMG-Slate widget.
Can anyone point at what I’m doing wrong or what I’m missing? Thanks.