[UserWidget] Setting an Image on PostEditChangeProperty

Hello there!

I have a problem with a UUserWidget blueprint overridden from a C++ Class, I try to set a Uimage’s Brush with a new Texture2D* in C++ at editor time, but the changes are reverted when I compile the child blueprint inheriting from my UuserWidget.


I have made a UWHButton c++ class with inherit UuserWidget.
This UWHButton is then used as a base class for Blueprint Widget classes.
And those Blueprint Widget Classes can then be used in other Blueprint Widgets, as custom buttons with my C++ logic packaged in them.

What failed is when I tried to provide a simple Texture2D* field (Inner Icon Texture) in the Details panel to permit designers to customize my button’s appearance from the root object in the blueprint and from any other widget blueprint using the button as well.

image


When the user change the Texture2D* field _innerIconTexture of my custom class in the details panel, I change the Uimage _innerIconImage’s FSlateBrush with the new Texture2D* in a PostEditChangeProperty.

#if WITH_EDITOR
void UWHButton::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
FProperty* innerIconProperty = FindFProperty(this->GetClass(), “_innerIconTexture”);
if (innerIconProperty && (PropertyChangedEvent.Property == innerIconProperty))
{
FStructProperty* uIBrushPropStruct = FindFProperty(_innerIconImage->GetClass(), “Brush”);
if (uIBrushPropStruct)
{
_innerIconImage->PreEditChange(uIBrushPropStruct);
FPropertyChangedEvent changedEvent = FPropertyChangedEvent(uIBrushPropStruct, EPropertyChangeType::ValueSet);

  	_innerIconImage->SetBrushFromTexture(_innerIconTexture);

  	_innerIconImage->MarkPackageDirty();
  	_innerIconImage->PostEditChangeProperty(changedEvent);
  }

}
Super::PostEditChangeProperty(PropertyChangedEvent);
}
#endif
(Image version of code as indentation is broken)


However, as soon as I try to compile the changes to the blueprint, the changes on the UImage _innerIconImage have reverted to their previous state :



This is quite a problem as I wanted my UWHButton to be usable in other UserWidget blueprints, and so only the root parameters are accessible there, not the child components. So I cannot modify the child component UImage in editor directly, only the custom field.

I search the internet but found little than would help me understand the issue.

I came across this thread : C++ property modifications (PostEditChange) are not saved

And so tried to set the value in a PreSave function but the UImage pointer is null at PreSave time, so I can’t set it there.

I also tried multiple things with NativeConstruct but with little success there as well.

If anyone has either a solution, an explanation or a workaround I would be grateful, because making a custom button doesn’t seem at all a complicated endeavor, I don’t get what is it I do so terribly wrong.

Thanks for reading me !

RedYggdrasil,
Wannabe developer.

The common way to set up widgets is through the OnInitialized / PreConstruct / Construct methods. OnInitialized conditionally only runs once when the game starts. Preconstruct runs at least once in both the editor and in-game. Construct runs at least once in-game. You should read the Texture2D property during PreConstruct in c++ and set the appearance from there.

2 Likes

Yep !
Was using NativeConstruct, changing it to NativePreConstruct did the trick.
Thanks a lot ! I spent so much time on so stupid a mistake, I’ll definitively remember this one :sweat_smile:

image

image