[UMG][C++] Load Image Async

hi, I’d like to load images/textures async, everything is being loaded correctly, I just don’t know how to cast the loaded UObject to UTexture2D so I can assign it to a FSlateBrush and then the slate brush to a UBorder

if check(AssetToLoad.ResolveObject() != nullptr)
{
	UObject* NewTexture = AssetToLoad.ResolveObject();
	
	FSlateBrush brushEffect = UWidgetBlueprintLibrary::MakeBrushFromTexture(Cast<UTexture2D>(NewTexture));
	BorderPicture->SetBrush(brushEffect);
}

I tried the above, the object is being loaded correctly but the texture is being displayed all white.

please let me know. Thanks!

bump

@DryreL a little bit of thread necromancy there.

Here is the solution.

header

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "MyUserWidget.generated.h"

/**
 * 
 */
UCLASS(Blueprintable)
class YOURGAME_API UMyUserWidget : public UUserWidget
{
	GENERATED_BODY()
	
public:
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
	TSoftObjectPtr<UTexture2D> TextureToLoad;


	UFUNCTION(BlueprintCallable)
	UTexture2D* LoadImage(bool& Loaded);

	UPROPERTY(BlueprintReadWrite,editAnywhere, meta = (BindWidget))
	class UImage* BorderPicture;

};

Don’t forget to create an image inside of the widget and call it BorderPicture

cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyUserWidget.h"
#include "Components/Image.h"
#include "Blueprint/WidgetBlueprintLibrary.h" 

UTexture2D* UMyUserWidget::LoadImage(bool& Loaded)
{	
	Loaded = false;
	UTexture2D* Texture = nullptr;
	
	FSoftObjectPath AssetData = TextureToLoad.ToSoftObjectPath();
	if (AssetData.IsValid()) {

		Texture = Cast<UTexture2D>(AssetData.TryLoad());
		Loaded = Texture != nullptr;

		FSlateBrush brushEffect = UWidgetBlueprintLibrary::MakeBrushFromTexture(Cast<UTexture2D>(Texture));
		if (BorderPicture != nullptr) {
			BorderPicture->SetBrush(brushEffect);
		}
	}	
	return Texture;
}

Set TextureToLoad to the needed image & after construct call LoadImage to see the results.



1 Like

Thanks for your help!!

I have a question for you.

Is this method better or using “Lazy Image” from the Common UI?

Seems pretty similar looking at the engine code of CommonLazyImage.cpp. They seem to use weak pointers for the UCommonLazyImage just in case it gets garbage collected.

It might have some overhead when compared to the simpler code.

void UCommonLazyImage::SetBrushFromLazyDisplayAsset(const TSoftObjectPtr<UObject>& LazyObject, bool bMatchTextureSize)
{
	if (!LazyObject.IsNull())
	{
		TWeakObjectPtr<UCommonLazyImage> WeakThis(this); // using weak ptr in case 'this' has gone out of scope by the time this lambda is called

		RequestAsyncLoad(LazyObject,
			[WeakThis, LazyObject, bMatchTextureSize]() {
				if (UImage* StrongThis = WeakThis.Get())
				{
					ensureMsgf(LazyObject.Get(), TEXT("Failed to load %s"), *LazyObject.ToSoftObjectPath().ToString());
					if (UTexture2D* AsTexture = Cast<UTexture2D>(LazyObject.Get()))
					{
						StrongThis->SetBrushFromTexture(AsTexture, bMatchTextureSize);
					}
					else if (UMaterialInterface* AsMaterial = Cast<UMaterialInterface>(LazyObject.Get()))
					{
						StrongThis->SetBrushFromMaterial(AsMaterial);
					}
				}
			}
		);
	}
	else
	{
		ShowDefaultImage();
	}
}
1 Like