I had problems with C++ properties set from blueprints in a project I took over from a colleague, so I created an empty project to reproduce.
I created an empty project with the Games/Blank template in Unreal 5.6.1, Blueprint type. Then I added C++ class to make it a hybrid project. I named the class MyUserWidget and had it inherit from UserWidget. The header looks like this:
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h"
#include "MyUserWidget.generated.h"
/**
*
*/
UCLASS()
class WIDGETPROPERTYTEST_API UMyUserWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
UTextBlock* Schrott;
void DoSomething();
};
Then I created a new blueprint based on my class MyUserWidget. I added a TextBlock (Common/Text, class UTextBlock) to it. I do not check the “Is Variable” in the TextBlock and I do not change any properties of the TextBlock. As expected, the blueprint has a property called Schrott that I can set to the newly added TextBlock. When I compile the blueprint, the property gets reset to empty.
Now as far as I know this is the only way to access elements created in the blueprint designer from C++ code, so how am I supposed to access those elements now?
I found these related forum entries, but they did not help me:
As suggested in one of the posts, I tried deleting the TextBlock and re-adding it. After doing so, Unreal no longer suggests the TextBlock as possible value in the dropdown of my Schrott property, but I have no idea why.
I also tried creating the project as C++ type, which did not help.
I also tried the same process with Unreal 5.7.3, which did not help.
You assign the property reference to you base class and you expect it to be referenced however designer created widgets don’t work like that.
Designer created widgets, are recreated / assigned on compile, preview so your assignment will fall.
The proper approach is slightly different.
If you want to access a TextBlock created in the designer from C++, use UPROPERTY(meta=(BindWidget)) and mark the TextBlock as “Is Variable” in the Blueprint. The names must match.
However I don’t like this approach to be honest what I do is actually even more different, I prefer manual lookups generally.
void UMyUserWidget::NativeConstruct()
{
Super::NativeConstruct();
// We simply search by string when hit do something.
if (WidgetTree)
{
UWidget* Found = WidgetTree->FindWidget(TEXT("Schrott"));
Schrott = Cast<UTextBlock>(Found);
}
}
This way I can control the lookup and assignment at runtime for various situations.
You are looking for the BindWidget meta tag, I think?
UPROPERTY(meta = (BindWidget))
class UTextBlock* Schrott;
This lets you add UMG widgets and bind them so you can use them in c++. The widget must have the EXACT same name you give it in c++. There is a Bind Widgets panel in the Widget Designer view that shows the status of your widget bindings.
Thank you both so much. I will try out the suggestions on Monday when I am back in the office.
I am coming from Unity, and this seems weird to me, since in Unity I can just assign any component to any variable with matching type (if exposed) and Unity will immediately take care to store it forever. I can’t see why Unreal allows me to assign it, then discards it.
Regarding the manual lookup, isn’t that less efficient? This also looks very much like something you can do in Unity, where looking up a component is much more expensive than assigning it beforehand. Thanks anyway for the suggestion, it’s good to learn how manual lookup works in Unreal!
Every framework and language including markups have its own architecture and behavioral patterns.
It’s possible to do slate level changes.
Unity’s Canvas or UI Toolkit (Which is a web architecture squeezed in canvas) your variables get directly assigned since there is no middle man between the canvas and C. On toolkit its give or take the same where you bind it.
Not really, since its on NativeConstruct its just once, cost is negligible. The cost is not the performance is the validation and clarity. Searching is explicit control so we gain flexibility in dyanmic widgets, optional bindings etc. BindWidget its resolved construct time and supported with UMG binding. Both is ok BindWidget is correct but searching is more defining in dynamic widgets if you have use cases.
On the other hand “Search” is a search and its operation, yes in micro level everything is a cost but do you really want to consider that is the real question.
I tested the BindWiget tag today and it worked. However, in one case, when I had “Is Variable” set, a duplicate variable showed up and caused errors. When I removed it, the error went away and my binding still worked, so I guess it’s not required. I’ll look up how that setting works exactly, but for now, my problem seems to be solved and I can continue to work. Thank you so much!
And for clarity for future readers, “same name” means my UTextBlock* variable needs to have the same name as the Text element I added in the blueprint designer. Here, this means I needed to rename my UI element in the designer to “Schrott”.