How do I replace the texture on a button at runtime?

(this is my first post to the forum, please let me know if I put this in the wrong area, and I’ll move it)

I have a small project. The project has tiles, which are widget blueprint objects. The tile has an image I put a default texture on the image at startup time. I’m trying to replace the texture at runtime.

Here is the heirarchy from the designer. Both TileButton and tile_image are variables and visible.

In my tile blueprint there is an event which will get called by other classes to replace the picture shown on the tile.

What is the proper way to use this brush (texture) to update the image on the button?

I’ve tried a bunch of things so far by watching videos, but I haven’t been able to make any
of them work, and I think I have a fundamental misconception about what I should be doing.

Things I’ve tried:
Getting the image object setting the brush on it (nothing changes visually, though)
Getting the image object, setting the brush, and trying to save the tile_image (can’t, it is read only)
Using make slate brush from the 2d texture
SetTileBrush calls SetBrushFromTexture passing in the “brush” as a texture
Getting the button, setting the style, setting normal style to a call from set brush resource to texture with the passed in texture
Making a slate brush from the passed in texture, calling make button style, and setting the style

Videos I’ve tried using for reference:

Search terms I’ve tried:
“unreal engine how do i change a button’s image at runtime?”
“unreal engine set texture 2d on button”
“unreal engine cant draw texture2d onto widget”

Any help would be welcome!

1 Like

SetTileBrush calls SetBrushFromTexture passing in the “brush” as a texture

That’s a good way to do it. The tile_image widget in your case.

Where are you calling the Set Tile Brush event? Are the tiles within a parent container?

1 Like

Thanks for the reply!

The tiles live in a Tile Grid, which is basically a 2d array of tiles.

the Set Tile Brush event is called by the TileGrid, passing in the brush with the texture 2d that I want to appear on the button.

1 Like

So I tried this, but the texture on the button is not getting set to the new texture passed into the SetTileBrush event:

Any ideas what I might be missing?

1 Like

Some things to try and confirm.

Does the passed variable Brush have type Texture2D?

Try setting without Match Size checked, maybe something weird is happening there.

It’s possible you have set the texture correctly but there is a size/scaling issue. If match size is true and the texture size is very small, it may be hard to see a change.

I recommend checking Tile_Image properties to see if there is something gone awry there, maybe image alpha is set to zero, texture size is zero, Draw As is set to None etc.

Worth double checking those kinds of values.

Another thing to try is to set up a test with the tile widget in isolation. If you can update a single tile widget’s image texture correctly, then there may be an issue with the container or how you are calling SetTileBrush.

1 Like

Thanks, HotInnards!

  1. I did confirm that I am sending a Texture 2D to the brush argument.

  2. When I try without MatchSize checked, the result is the same.
    The tile already has an image on it which was set at tile creation time, I am trying to replace the image. When SetTile runs, the old image remains, and no sign of the new image.

  3. Tile image properties look sane to me:


    However, these properties don’t mention alpha or size, so it could be that I’m looking in the wrong place for tile properties. (By the way, I renamed “Set Tile Brush” to “Set Tile Brush1” in these examples)

  4. I tried calling the test widget in isolation - There is a layout class which is the parent of the tile grid (which is the parent of the array of tiles). I added a W_Tile instance to the layout class, and called the Set Tile Brush method there. It has the same problem.

Thanks for all the ideas so far, anything else you can think of that I should try?

Other things I’ve tried:
A. A different way to implement Set Tile Brush:

B. Checking the order of events - maybe the function call to “Set Tile Brush” was happening after the create event. Turns out that the tiles are being created before the tile grid which calls “Set Tile Brush”. Since the tiles set the default image when they are created, if they were called too late, the default image would overwrite the one that “Set Tile Brush” is trying to set. I called “Set Tile Brush” on a mouse click event, but still the image is not getting updated.

One idea - one of the videos that I watched called a “set” method after calling Set Brush From Texture. Is there something I need to do after the call to “Set Brush From Texture” to make sure that the change sticks? I haven’t been able to call a set method on the image since tile_image is marked as read-only in the designer. I have made it a variable, but I still don’t seem to be able to set it.

1 Like

Function we use to change a button image at run time. C++ but should (?) be straightforward to convert to BP. This function is in a base class that’s parent of all our HUD blueprints.

Struggled with this for a bit as well, but long story short: you have to set the image for each button style: Normal, Hovered, Disabled, and Pressed.

If there’s any other way I wouldn’t mind hearing about it. :+1:

// in .h file
void SetButtonImage(UButton* button, UTexture2D* image);

// in .cpp file
void UBaseHUDWidget::SetButtonImage(UButton* button, UTexture2D* image)
{
	// validate button and default icon
	if (button != nullptr && _defaultIcon != nullptr)
	{
		// if image is null use the default icon
		if (image == nullptr)
		{
			image = _defaultIcon;
		}

		// if the images match then do not set the images again
		// must set the image for each button style
		FButtonStyle buttonStyle = button->GetStyle();
		if (buttonStyle.Normal.GetResourceObject() != image)
		{
			buttonStyle.Normal.SetResourceObject(image);
			buttonStyle.Hovered.SetResourceObject(image);
			buttonStyle.Disabled.SetResourceObject(image);
			buttonStyle.Pressed.SetResourceObject(image);
			button->SetStyle(buttonStyle);
		}
	}
}

Using it would simply be like this, assuming you have a pointer to an image and button.

SetButtonImage(buttonPtr, imagePtr);
2 Likes

Thanks, Shmoopy1701!
I tried this below (which I think is a blueprint version of your C++ code), but it also doesn’t seem to do anything.

I tried using just an image instead of a button.

That does work with this function:

Any idea why this works with just an image, and not an image on a button?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.