1
$\begingroup$

I'm using Blender 3.4 and I want to display an image in the UI and be able to change it by pressing a button.

The button using ImportHelper executes this code:

image = bpy.data.images.load(self.filepath, check_existing=True)
texture = bpy.data.textures.get("Test_Texture")
if not texture:
    texture = bpy.data.textures.new("Test_Texture", type="IMAGE")
texture.image = image

In the UI the image gets displayed like this:

texture = bpy.data.textures.get("Test_Texture")
if texture:
    row = layout.row(align=True)
    row.template_preview(texture)

Simple, right? After the first button press the first image shows up fine, but the second time the UI refuses to update the image. I have tried bpy.ops.wm.redraw_timer and tag_redraw() on all regions and areas, but it won't update. Only when the user manually resizes the image it gets updated to the new one.

How can I tell the UI to update the image?

$\endgroup$
2
  • $\begingroup$ The image type has an update function itself (docs), perhaps it helps you out? So something like texture.image.update(). $\endgroup$ Commented Feb 28, 2023 at 19:21
  • $\begingroup$ I have tried this, and it too didn't work. $\endgroup$ Commented Mar 1, 2023 at 16:00

1 Answer 1

2
$\begingroup$

I had this problem too, if you have found a proper way to update template_preview please share, meanwhile I have found a workaround that works for me. As you noticed when you manually resize the image it gets updated. you can do that also programmatically inside the draw function for example: col.scale_y = 1.01 and also I had to add reload() and update() functions so I created a switch inside my draw function:

updater = True
def draw(self, context):
    layout = self.layout
    prop_group = context.scene.my_prop_group
    split = layout.split(factor=0.5)
    # First column for the image
    col = split.column()
    col.label(text="Image Preview:")
   
    tex = bpy.data.textures.get("TempScreenImg")
    try:
        tex.image.reload()
        tex.image.update()
    except:
        print("no data")
    slot = getattr(context, "texture_slot", None) #tried this because that's how blender does template_preview but as far as I understand this is optional for what we try to do.

    # Use the texture for preview
    if tex:
        col.template_preview(tex, slot=slot)
        if self.updater:
            col.scale_y = 1.0
            self.updater = not self.updater
        else:
            col.scale_y = 1.01
            self.updater = not self.updater

Now the template_preview will update whenever the panel is redrawn but this still is not good enough that is why if you need to trigger the update whenever you change some properties you can add update function to the property like this:

def update_func(self, context):
    context.area.tag_redraw()

def register():
    #or inside propertygroup
    ....
    bpy.types.Scene.my_prop = bpy.props.IntProperty(update=update_func)
    ....

This approach will automatically resize your template_preview whenever you modify properties that should trigger an update. While this will introduce some extra refresh cycles, making it more noticeable in the template_preview, it's a functional workaround. I haven't found a better solution yet, other than potentially creating custom panels that bypass Blender's native UI.

Additionally, I'm encountering update-related issues with other template_ui elements as well. If anyone has insights into how to properly handle these templates, I'd be interested in hearing your suggestions.

$\endgroup$
1
  • $\begingroup$ This is actually a really good idea! As a temporary fix I was using some other UI type to show the image, but I prefer this $\endgroup$ Commented Sep 16, 2023 at 15:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .