Download

Moving UI elements from Widget Blueprint to C++ class

As part of my UI, I need to be able to fill a ScrollBox with buttons that have text on them and override a few custom methods.

I’m currently accomplishing this by having a parent class that extends UUserWidget and has the generic implementations of my custom methods. Then, I make the child classes with the overridden implementations. Finally, I make a Widget Blueprint that contains the UI that I want and has one of the child classes as its parent.

Sapling2.JPG
Sapling.JPG

This takes a long time for each case, so I’d like to get rid of the Widget Blueprint step by building the UI elements into my parent class. Can I do this by adding a button and text to my UUserWidget, and if so, how? If not, what should I extend instead?

For the sake of future people with similar issues, I’ll list things that I’ve tried.

**
Adding UUserWidget directly to a ScrollBox**
This is the similar to my flow when using Widget Blueprints. I’m trying to add a button to the UUserWidget, then add the UUserWidget to a Panel (a ScrollBox, in this case).

Following this tutorial, I added the following code to my UUserWidget’s Init function:

5a58f36abe2abb4810e22ed338bb7eb9b0df3984.jpeg

Then, in my game manager class, I try to initialize an instance of my UUserWidget (ForestObject):

4a0f7165ca309d6bf1b571d3fd016e1cd0235d8b.jpeg
Note: TextUI is just a UUserWidget that I parent to the Widget Blueprint where I do my UMG designer stuff. It’s mostly a way for my UI to interact between C++ and blueprints.

This leads to a crash with the following first few lines of log:


Access violation - code c0000005 (first/second chance not available)

UE4Editor_UMG!UUserWidget::GetSlotNames() [d:\build\++ue4+release-4.15+compile\sync\engine\source\runtime\umg\private\userwidget.cpp:533]
UE4Editor_UMG!UWidgetTree::ForWidgetAndChildren<<lambda_803f8c35be5f25e40019c9433cf4e614> >() [d:\build\++ue4+release-4.15+compile\sync\engine\source\runtime\umg\public\blueprint\widgettree.h:87]

Edit: Looking at this thread, it seems like I might not want to extend UUserWidget class at all, since I don’t want to manipulate these objects in the designer, only add them to a panel at runtime. Going to explore making a UWidget-derived class that acts as a wrapper for an SButton with text.

Success! In testing, at least.

First, I made a UWidget-derived class and overrode the RebuildWidget() method.


class FORESTOFTERROR_API UTestWidget : public UWidget
...
protected:
	virtual TSharedRef<SWidget> RebuildWidget() override

Then, I made an SBox (to control size), SButton, and STextBlock to define the button that I wanted.


TSharedRef<SWidget> UTestWidget::RebuildWidget()
{
	TSharedPtr<SBox> MyBox = SNew(SBox)
		.WidthOverride(250)
		.HeightOverride(100)
		
			SNew(SButton)
			
				SNew(STextBlock)
				.Text(FText::FromString("Hello"))
			]
		];

	return MyBox.ToSharedRef();
}

And it works! Now, I can fill my scrollbox with children of this class. Since I’ve cut Widget Blueprints out of the process and moved the UI handling to the parent, I’ll be able to save a lot of time.

If anyone is still reading, is there any way to keep this widget from appearing in the designer? Since I only want these to be populated at runtime, it just adds clutter.

IsDesignTime()

It seems like I’m not able to modify that, unless I’m just daft (it’s FORCEINLINE and non-virtual). At least, my widget still shows if I try to re-create it and return false.
I can override SetDesignerFlags and have it not call the super’s accessor, but that doesn’t work either.

You miss understand, you can use IsDesignTime() in your RebuildWidget() call to create different widgets at Design Time, one that is less clutter.

Ah, I understand what you meant now. I must have worded it poorly, I’m trying to keep the widget from appearing in the selection menu.

I couldn’t figure out how to accomplish that, but I was able to move my parent and child widgets to a different category, so that I can just keep them minimized.


#if WITH_EDITOR
	virtual const FText GetPaletteCategory() override;
#endif


#if WITH_EDITOR
const FText UForestObject::GetPaletteCategory()
{
	FText text = FText::FromString(TEXT("Forest Objects"));
	return text;
}
#endif