Download

Adding UWidgets to a UUserWidget in C++

I’m trying to dynamically make menus from code instead of making the base class then setting them up with blueprints.

Menu.h



UCLASS(BlueprintType)
class CUR3D_API UMenu : public UUserWidget
{
	GENERATED_BODY()
public:
	//Constructor & Destructor
	UMenu(const FObjectInitializer& objinit);
	~UMenu();
protected:
	UCanvasPanel* panel;

Menu.cpp


UMenu::UMenu(const FObjectInitializer& init) :Super(init)
{
	panel = this->WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass(), FName(TEXT("RootPanel")));

} 

Build.cs


PublicDependencyModuleNames.AddRange(new string] {
            "Core",
            "CoreUObject",
            "Engine",
            "InputCore",
            "Json",
            "HashMapPlugin",
            "HelperFunctionsPlugin",
            "HttpPlugin",
            "ThreadingPlugin",
            "UMG",
            "DataVisualizationPlugin"
            // ... add public dependency modules required here ...
        });

		PrivateDependencyModuleNames.AddRange(
			new string] {
                "Slate",
                "SlateCore"
				// ... add private dependencies that you statically link with here ...
			}
		);

Ideally what I’d like to be able to do is have a UPanelWidget or UCanvasPanel in my UUserWidget so I could do layout within my program. My code compiles, but I’m getting a runtime error


Fatal error: [File:D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.9\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 1800] 
Object is not packaged: CanvasPanel RootPanel
UE4Editor.exe has triggered a breakpoint.

I’m running this through Visual Studio if that makes a difference. I also tried using


panel = dynamic_cast<UCanvasPanel*>(this->GetRootWidget());

but it returned a null pointer. Any help would be greatly appreciated.

First set the panel Variable to be a UPROPERTY, this may help… or it may not but it needs to not be garbage collected. Second User Widgets are nested, are you SURE your RootWidget is in fact your UCanvasPanel?

Some advice on UE4. In general I would not recommend performing any layout operations via C++. I do however HIGHLY recommend creating base UUserWidget Classes with the base functionalities of your important UI Elements. For instance you can specify a HUDWidget that contains functions to get health, an InventoryWidget with functionalities to retrieve the characters inventory items and contains an array of InventoryItemWidgets that perform use actions and display the item’s information. But none of these objects specify HOW the child widgets are to be displayed. It is always better to separate Logic from Layout so you can change them without breaking something. Basically your base classes contain functions for getting and sometimes calculating data but do not do any of the actual visual manipulation, or if they do the widget being manipulated is passed in via a parameter. For manipulating layout I use BlueprintImplementableEvents or BlueprintNativeEvents to override functions in blueprint. The layout of my UUserWidgets are done in the UE4 Blueprint Editor where predefined functions and overrides drive everything.

Doing everything in C++ effectively Locks down the types you can use in your UI and makes it harder to change. What if you decide to change the CanvasPanel for something else? By spreading the logic between Blueprint and C++ you are able to change things a bit easier. In contrast I find doing everything in Blueprint to be pure chaos as I can too easily break something by changing it because some other UI Element relies on that function. Having a framework of functions and functionalities I can rely on through C++ with the ability to completely throw out the layout for something completely different if I want without breaking any other UI Elements that may rely on some given functionality of that widget is much better and easier to work with in the long run.