I have a few custom properties in my add-on to store state data of my job which is executed in the cloud.
class Properties(bpy.types.PropertyGroup):
"""Add-on properties."""
# Job
job_id: bpy.props.StringProperty(name="Id", default="", description="Id of the job",)
job_title: bpy.props.StringProperty(name="Title", default="", description="Title of the job",)
job_status: bpy.props.StringProperty(name="Status", default="", description="Status of the job",)
job_progress: bpy.props.FloatProperty(name="Progress", default=0.0, max=100.0, subtype="PERCENTAGE", description="Progress percentage of the job",)
When I execute a job from the add-on, I also run a separate thread that listen to my API using a websocket connection / GraphQL subscription. When the subscription receives a message, it calls a callback method (running in the separate thread) to updates the job progress and job status properties. Here are the methods.
class CRAFT_OT_subscribe_job(bpy.types.Operator):
"""Subscribe to a job"""
bl_idname = "craft.subscribe_job"
bl_label = "Subscribe Job"
bl_options = {"REGISTER"}
@staticmethod
def update_job_progress(job):
# Update the status and progress percentage of the job
bpy.context.scene.craft_addon.job_status = job["status"]
bpy.context.scene.craft_addon.job_progress = float(job["progress"])*100
# Redraw panel
for region in bpy.context.area.regions:
if region.type == "UI":
region.tag_redraw()
def execute(self, context):
# Subscribe job and output
job_id = int(context.scene.craft_addon.job_id)
client = bpy.app.driver_namespace.get("craftclient")
client.subscribe_job(job_id=job_id, callback=self.update_job_progress) # This starts a new thread
return {"FINISHED"}
The job progress and job status properties are updated properly but they are not refreshed in the N panel UI until user moves the mouse over it. I have tried to call tag_redraw()
as mentioned in this answer but since my static method update_job_progress()
runs in a separate thread, it triggers the error.
AttributeError: 'NoneType' object has no attribute 'regions'
Any suggestion how I could force redraw the N panel or just the corresponding custom property from a separate thread?
context.area.tag_redraw()
on your panel. $\endgroup$bpy.context.area.tag_redraw()
ratther thancontext.area.tag_redraw()
because I don't have the context in my callback methodupdate_job_progress
. I get the same error:AttributeError: 'NoneType' object has no attribute 'tag_redraw'
$\endgroup$for region in context.area.regions: AttributeError: 'NoneType' object has no attribute 'regions'
with your method, most likely because contrariwise to your script, mine is multi-threaded. That said, it seems using theupdate
method of theFloatProperty
is enough to force the refresh of the UI, even if the method does nothing :) Don't you want to write an answer so that I vote it up? $\endgroup$