9
$\begingroup$

The Goal

I'm writing a Blender add-on that extracts a point cloud from multiple photos. This operation is implemented as an Operator that is invoked from a Panel button. This Operator, once started takes a lot of time to finish.

I would like to inform the user about the progress of the operation, via some kind of status text. What is the best way to script this?

What I've Tried Already

Currently, I have a status message label in the Panel which invokes the "Start SFM" Operator. This displays the text stored in a Scene Property called currentStatus.

Panel snapshot

In my Operator's Execute method, I do this:

def execute(self, context):
    thr = threading.Thread(target=self.foo, args=(context,))
    thr.start()
    return {'FINISHED'}

And in the time-consuming method foo, I update currentStatus:

def foo(self, context):
    context.scene.currentStatus = "Starting..."
    # Time consuming operation 1
    context.scene.currentStatus = "Operation 1 Completed"
    # Time consuming operation 2
    context.scene.currentStatus = "Operation 2 Completed"
    ...

The problem with this is that the label only updates when it is moused over or if the user clicks on the scene. It does not redraw automatically. I have failed at several attempts to force a redraw through python. I have tried polling, but it behaves similarly.

Am I missing something, or is this a completely wrong way to approach the problem?

$\endgroup$
  • $\begingroup$ Related: blender.stackexchange.com/q/3219/599 $\endgroup$ – gandalf3 Mar 12 '14 at 19:54
  • $\begingroup$ I tried the progress cursor method. The cursor doesn't update without moving it. So basically the user has to wave around the cursor just to get notified of progress. Not really satisfactory in my case because my operation can take a while. $\endgroup$ – ApoorvaJ Mar 14 '14 at 13:35
  • $\begingroup$ That's odd.. It was working okay for me. Anyway, I agree the cursor method is not the best. :/ $\endgroup$ – gandalf3 Mar 14 '14 at 19:26
5
+50
$\begingroup$

This is a hack, at best. So, when an image in blender is rendered, it provides a convenient status bar at the top of the window. The problem is a script has to be a renderEngine to take advantage of this. The solution? Make your script a custom renderEngine, then have your button invoke the render function.

Here's a very basic example of updating the status bar, and adding a status string to the render window. You would put the code you want run in the myCode function.

import bpy
import time

class CustomRenderEngine(bpy.types.RenderEngine):
    # These three members are used by blender to set up the
    # RenderEngine; define its internal name, visible name and capabilities.
    bl_idname = 'custom_renderer2'
    bl_label = 'Progress Bar Example2'
    bl_use_preview = True
    # This is an example function, put your code here
    def myCode(engine):
        engine.update_stats("Starting","")        #update the stats in render window
        time.sleep(1)
        engine.update_stats("Running","halfway")
        engine.update_progress(0.5)               #update the progress bar
        time.sleep(1)

    # This is the method called by blender
    def render(self, scene):
        self.myCode()

# Register the RenderEngine
bpy.utils.register_class(CustomRenderEngine)

Then select your new renderEngine. From the top of the blender window click "Blender Render" and select "Progress Bar Example." Now you can run your script by pressing F12. One other method that might be useful is test_break, which checks to see if the render(or script, in this case) has been cancelled.
One last thing to note, directly executing a script (eg. with altP) doesn't display the progress bar, however when the render function (byp.render.render) is bound to a panel it displays correctly.

See these for more information: Blender artists, setting progress bar values Blender Python Api, RenderEngine

$\endgroup$
  • $\begingroup$ Fixed the link. $\endgroup$ – user2699 Mar 14 '14 at 19:36
  • $\begingroup$ Thank you for the answer. I wanted text-based progress updates instead of a progress bar, but that seems to be surprisingly difficult, and impossible without any hacks. I'll mark this as the answer at give the bounty after six more days, if there's no text-based notification answer till then. $\endgroup$ – ApoorvaJ Mar 15 '14 at 15:46
  • $\begingroup$ @ApoorvaJ, I'm not sure how I missed that in your question. I've added a couple lines to show how a text status can be shown in the render window using update_stats. $\endgroup$ – user2699 Mar 15 '14 at 17:22
  • 1
    $\begingroup$ It's a hack, but it's the closest implementation to my requirements. Thanks! $\endgroup$ – ApoorvaJ Mar 17 '14 at 13:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.