Long running operator - modal? how about the properties dialog?

I am working on an operator which will do some heavy calculations for animation. I want it the user to be able to interrupt it by pressing escape or the x button, just like when rendering. I thought that I should use a modal operator for this, as normal operators freeze blender.

  1. how do I add the X (cancel) button?
  2. I have some properties that need to be set before it starts calculating, but the call to wm.invoke_props_dialog(self) does not go well together with the modal operator. How do I make my modal operator work together with the properties dialog?

The modal operator would also freeze the GUI until the calculations are complete and it returns {‘MODAL’} to wait for new events.

You can send an Interrupt Signal by pressing CTRL + C in the console.

You’re right, the modal operator will wait till next user input. (except if I use the timer, like in one of the examples, but I actually want it to go as fast as possible).
To explain my Idea about the modal operator: the operator loops through all the frames of the scene to animate objects. I want the UI to remain responsive (and show the progress), while the operator is doing that.

This is the approach I am trying now (with invoke, execute and modal):


    def finish(self, context):
        context.window_manager.event_timer_remove(self.timer)
        self.timer=None
        
    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.finish(context)
            return {'CANCELLED'}
        elif event.type == 'TIMER' and not self.updating:
            try:
                self.updating = True
                if self.next_frame <= self.frames_to_bake[-1]:
                    self.bake_frame(context, self.next_frame)
                    self.next_frame += self.keyframe_interval
                    return {'PASS_THROUGH'}
                else:
                    self.finish(context)
                    return {'FINISHED'}
            finally: 
                self.updating = False
        else:
            return {'PASS_THROUGH'}

    def execute(self, context):
        self.frames_to_bake = list(range(scn.frame_start, scn.frame_end+self.keyframe_interval, self.keyframe_interval))
        self.next_frame = 0
        self.timer = context.window_manager.event_timer_add(0.01, context.window)
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}
        
    def invoke(self, context, event):
        wm = context.window_manager
        return wm.invoke_props_dialog(self)

However, the problem is that the combination of invoke_props_dialog and modal_handler_add crashes blender. The crashlog says:


bpy.data.window_managers["WinMan"].(null) = False  # Property

Show progress yes, responsive not really.

Ah, at least that kind of showing progress is something.

Any ideas about combining the dialog and the modal operator?

disregard this

I finally ended up having two operators: a GUI operator, which calls the modal operator. Seems to work OK, except that it is a bit hacky. (From the spacebar search you can find both operators)

Add this to your operator class:

bl_options = {‘INTERNAL’}

It will hide the operator in the spacebar menu.