How to properly assign a property during construction?

I’m trying to create an object for using it in Blueprint widget graph, I have assigned a default value in the widget constructor. However every time I’m trying to use it as function target I’m getting a “Error Accessed None” in the Editor.

As a workaround I found I can change the name of the property and it will work (ie. won’t trigger above Error), but when I try to make some changes the Error comes back.

This is my class:

UCLASS()
class TESTGAME_API UMyWidget : public UUserWidget
{
	GENERATED_BODY()
public:
    UMyWidget(const FObjectInitializer& ObjectInitializer);
private:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, NoClear, Category = Test, meta = (AllowPrivateAccess = "true"))
    class UMyObject* MyObject;
}

And this is a constructor:

UMyWidget::UMyWidget(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
    , MyObject(CreateDefaultSubobject<UMyObject>(TEXT("MySubObject")))
{
}

As far as I understand, simply adding UPROPERTY() to a pointer member is enough for it to be smart pointer so there should be no garbage collection until the destructor. I have also added a NoClear specifier just to be sure. But still it is being cleared all the time.

Also as a bonus: How to make this property visible as a variable in the “My Blueprint” tab in “Graph Editing Mode”?

Thank you for your help.

EDIT:

Looking at some more wiki pages, code and questions here, I’ve changed the constructor to below code, but it did not help:

UMyWidget:: UMyWidget(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    MyObject = ObjectInitializer.CreateDefaultSubobject<UMyObject>(this, "MySubObject");
}

Hi,

It’s inheriting directly from UObject. I’m trying to expose additional functionality to Widget’s Blueprint not related to UI.

Thanks,

Michal Debski

Hey Neos3452-

What class does MyObject inherit from? Are you trying to have your widget create another widget or are you trying to add a widget element (such as a button) at runtime?

Cheers

Hey Neos3452-

Depending on the functionality you’re trying to add it would be a better workflow to have the UI make a call to the object and have the object preform the action rather than adding the action to your UI. One method I was able to test to do this was to create an UObject class to define a function’s behavior as well as a dummy actor with a reference to my UObject and a “redirect” function that called the UObject’s function. This was done so I could add an instance of the actor to the level since UObjects cannot be directly added to a level. Inside the UI I created a button that, when clicked, used “Get All Actors of Class” to find my dummy actor and call the Redirect function which preformed the UObject’s function.

UObject.h

UCLASS(Blueprintable)
class MYPROJECT16_API UMyObject : public UObject
{
	GENERATED_BODY()
public:

	UFUNCTION(BlueprintCallable, Category = Test)
	void TestFunction();
	
};

UObject.cpp

void UMyObject::TestFunction()
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 4.f, FColor::Magenta, TEXT("Redirect Call Successful"));
	}
}

DummyActor.h

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = test)
	UMyObject* ObjRef;
UFUNCTION(BlueprintCallable, Category = Test)
	void Redirect();

DummyActor.cpp

void AMyActor::Redirect()
{
	ObjRef->TestFunction();
}

UIButton

Hey, thanks for your answer.

This is exactly what I’m trying to achive, however instead of creating proxy Actor I would like to expose UObject directly (I would have to proxy all delagates, functions and properties through dummy).

But you did not answer my question, how did you assign default value of UMyObject to AMyActor::ObjRef? I don’t see a constructor defined, is it created using default object constructor if the parent’s object constructor isn’t declared? How to initalize the object using this way? I’m asking, because even though I have created UMyObject in the constructor and assigned it to the property I’m getting a “null pointer exception”.

In this setup I did not have to assign a default value to ObjRef. The pointer knows what class it points to and can see any of its public variables/functions. And the DummyActor can be omitted if you add the pointer to your UObject inside the widget class. I did a similar setup with a pointer to my UObject inside the widget and a function that used this pointer to call another function of the UObject. Inside the widget blueprint I simply called the widget function on a button click which redirects to the UObject function.

I think the problem I have is a bug in the editor, either linked to hot reload or blueprint compilation. My inheritance looks as follows:

UUserWidget->UMyUserWidget(C++)->BPMyUserWidget(Blueprint)

The things I need to do are done in C++ part, however I would like to leave UI entirely to blueprint class. So I’m creating an object (UMyObject) for UPROPERTY in C++ constructor which could be further utilized in Blueprint. Problem is it sometimes works and sometimes it is None (ie. nullptr).

I have reproduced it on a new project as follows:

  1. Create new empty c++ project
  2. Create new c++ class deriving from UObject (UMyObject) and add some UFUNCTION(BlueprintCallable)
  3. Create custom constructor for UMyObject
  4. Create new c++ class deriving from UUserWidget (UMyUserWidget)
  5. Add UPROPERTY() of type UMyObject* which is visible to blueprint
  6. Create custom constructor for UMyUserWidget, within it CreateDefaultSubobject() and assign it to the above property
  7. Inside the editor create “User Interface”->“Widget Blueprint” asset (BPMyUserWidget).
  8. Set BPMyUserWidget parent to UMyUserWidget
  9. Add button to BPMyUserWidget and in graph editor link onclick event to UFUNCTION from UMyObject UPROPERTY inherited from UMyUserWidget
  10. Add creation of BPMyUserWidget on your level beginplay event and add it to view port
  11. Play → everything works, on button click function of UMyWidget is called
  12. Change BPMyUserWidget blueprint, ex. add print node between onclick and UMyObject function call
  13. Play → “LogScript:Warning: Accessed None ‘MyObject’” is logged and UMyObject function is not called