[UMG] How to get canvas variable references into C++

The Problem

So I’ve been doing a lot of work with widgets and UMG but I prefer to keep as much logic inside C++ as possible where I can. So the problem comes when I want to get say a “TextBlock” element from the Canvas but into code as a variable such as UTextBlock* MyTextBlock.

I’ve been doing it in a specific way but it’s not full proof, it often produces “data races” more like misaligned c++ vs BP timings I think.

My Current Solution - Half Broken

229843-capture.png

Capture - Shows some variables from my canvas object, you can see their variables and public.

Capture 1 - Shows a method (Set All Text and Image Elements" which is a custom C++ function called in BP via the construct where I’m assigning all of the canvas variables to C++.

Capture 2 - The actual C++ method you saw being called in BP in Capture 1, I’ve scratched out a few extra elements as they’re not essential for this question. I’m associating my class member variables “AttackTextBlock”, “DefenceTextBlock” etc with the canvas variables I’m passing via blueprint.

229846-capture3.png

Capture 3 - Another method that is called via other objects that will actually update the text on the TextBlocks. When I get to this point it tends to say that there is a nullptr here on the text block and it breaks.

My question

Sorry if this has been answered before but I did look for quite a while and I prefer not to type long questions and I usually try out my own solutions regardless.

Question - Is there a much better way to get access to your canvas variables via C++ code on a custom classed UMG widget? Thanks for your help! If you need any further information please let me know.

UPDATE

So I’ve tried the advice of a comment by using BlueprintImplementable events but that problem is still there. Here is a snippet or what is happening.

From my Player Controller I am calling a “DisplayStats” method and am sending AUnitBase which is the unit that contains my data (this is fine and populated)

WidgetParentClass->DisplayStats(UnitDataToPull);

Display Stats is actually an event in Blueprints for a different Class (UUserWidget) and this event calls this function The cast in this function is not needed but I was trying to see if accepting a generic widget and casting would help and it didn’t:

void UStatBattleWidget::ShowAllStats(AUnitBase* UnitToObserve, UUserWidget* StatPanel) 
{

	USeperateStatPanel* TempPanel = Cast<USeperateStatPanel>(StatPanel);
	UE_LOG(LogTemp, Warning, TEXT("WAiting"));

	if (UnitToObserve != nullptr) 
	{
		TempPanel->DisplayDataEvent(UnitToObserve);
	}
}

229946-capture.png

This is the blueprint showing the event calling this function and you can see I’m passing a UUserWidget Object (It’s my W_Stat_VB_Panel which is a custom widget that I added to this one. Now this is where the problem happens. It’s this specific line:

TempPanel->DisplayDataEvent(UnitToObserve);

It throws an error saying that Access Violation but essential the error comes from the StatPanel or TempPanel because they are null. Yet I just passed a reference via the method call. So the method has been called 100% but the variable is null.

Does anyone have any idea why this would be null?

Is the code that invokes capture 3 also being called from another constructor script? Looks like a null pointer issue because it is being called before the Capture2 code is called.

If that is the case, try invoking the listing 3 code from the PostLoad

Well I was presuming that might be happening. However I’m mostly doing things in C++ and no constructor is asking for the information, it’s methods further down the line. As you can see in Capture2 that’s done in the Event Construct of the Widget. I presumed that if I was accessing a widget it would be created, thus the Construct method should be called and all references should be set.

What you mean mean by invoke listing 3 code from the postload? Could you please elaborate on that?

Thanks for your time.

I believe Ali is suggesting that the code in Capture 3 is begin called at some point before Capture 2 has set the pointer. You could check the pointer (AttachTextBlock->IsValidLowLevelFast()) before performing any actions on it, and see whether it still crashes.
Why don’t you just create BlueprintImplementableEvents that can access the variables inside your widgets instead however, rather than trying to store them in C++ as well?

Hi thanks for your response. I’ve decided to go for the BlueprintImplementableEvents but because this event gets called from different locations I’ve had to use it in conjunction with a BlueprintCallable function which then takes the variables and does the work. This however produces an error. I’ll add the update to my question, hopefully someone can make sense of it.