UWidgetComponent Has No Interface To Set Class

I am trying to create a UWidgetComponent by C++ and I have encountered a problem. I create a UUserWidget along with a UWidgetComponent, and I use UWidgetComponent::SetWidget(UUserWidget* InWidget) function.

The problem is, UWidgetComponent::Widget is reverted back to null inside UWidgetComponent::InitWidget() function since the WidgetClass variable is not set yet:

void UWidgetComponent::InitWidget()
{
	// Don't do any work if Slate is not initialized
	if ( FSlateApplication::IsInitialized() )
	{
     // Some other if checks

		else if ( !WidgetClass && Widget )
		{
			Widget = nullptr;
		}

    // Some other if checks
	}
}

I can’t seem to find an interface to set WidgetClass and since WidgetClass is private, I can’t also use an extended UWidgetComponent class. I also don’t want to modify engine code due to obvious reasons.

How should I proceed?

Definitely looks like an oversight, UWidgetComponent is still marked as experimental I believe. Hopefully someone from Epic will catch this and file a bug report.

Two possible workarounds without editing engine code:

  1. Delay your call to SetWidget. InitWidget is called at one point only, inside OnRegister. So if you set the widget after that, it shouldn’t be reset to null.
  2. Sneakily circumvent the private access modifier issue via the property system. Depending on at what point you do this, you may need to manually call InitWidget afterwards for it to take effect.
UWidgetComponent* MyWidgetComponent = ...;
UClass* MyUserWidgetClass = ...; // The class of widget you want to use
auto ClassType = UWidgetComponent::StaticClass();
auto ObjProp = Cast< UObjectProperty >(ClassType->FindPropertyByName(FName(TEXT("WidgetClass"))));
auto PropAddress = ObjProp->ContainerPtrToValuePtr< void >(MyWidgetComponent);
ObjProp->SetObjectPropertyValue(PropAddress, MyUserWidgetClass);

First of all, thanks for your help, I really appreciate it.

Tried the first approach, I call SetWidget after InitWidget is called but the WidgetClass is still empty. Moreover, SetWidget function does not set WidgetClass variable to anything, it just sets Widget and that’s it, WidgetClass is still empty. I don’t know where WidgetClass is initialized but it is definitely not inside WidgetComponent. I think Epic guys handle it somewhere upper in the hierarchy, possibly inside UI classes when you set the class through user interface while adding a component to an actor.

I did not try the second approach yet, I will report back when I did. My concern with this approach is that Epic guys do some other magic stuff when they set WidgetClass through user interface but we will see.

Yeah basically the WidgetClass property is meant to be set manually, usually in the editor. The component then uses it to determine what kind of widget to create during initialization.

If you call SetWidget, you’re basically overriding this and saying ‘I don’t care what WIdgetClass is, just use this already created widget’. So WidgetClass won’t be adjusted, but assuming you do it after InitWidget, that shouldn’t matter. If it doesn’t work, I’m not sure why.

My bad, you are absolutely right. I was trying to get the render target from WidgetComponent and seeing that it was the default checkered one, I assumed WidgetComponent was not initialized correctly but I attached it to my skeletal mesh and it displays fine. There are some texture size issues but the first approach definitely works. Thank you.