I am working on a Blender plugin that updates light fixtures in response to network data. I have the main aspect of the program completed (parsing the network packages into instructions for how exactly a certain light should be changed), and now I am trying to address lingering issues, the most critical of which is the UI locking up while the program runs. My understanding is that a modal operator would allow my program to essentially run in the background, which would let packages be processed and lights be updated without restricting the user's ability to interact with the 3D view (for example, lights could be pulsing while the user rotates their view).

Current State: Right now, I have a version of my code that is essentially spliced into the Blender template modal operator (timer version). Here is an outline of what I have:

/* import statements and initial setup here */

class ModalTimerOperator(bpy.types.Operator):
    """Operator which runs its self from a timer"""
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"

    _timer = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            return {'CANCELLED'}

        if event.type == 'TIMER':
            /*code that process a network packet into an array called dmx here*/
            #now change the lights based on the dmx data
            objects = bpy.data.scenes
            scene = objects[0]
            #if this packet is different than the last one we applied
            if(dmxOLD != dmx):
                for light in scene.objects:
                    if "prop" in light:
                        chan = math.floor(light["prop"]+17)
                        /*code that updates the light here*/
                        #now update the display
                        bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
            dmxOLD = copy.deepcopy(dmx)             
        return {'PASS_THROUGH'}

    def execute(self, context):
        wm = context.window_manager
        self._timer = wm.event_timer_add(0.1, context.window)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        wm = context.window_manager

def register():

def unregister():

if __name__ == "__main__":

    # test call

So when I run the full version of this, it basically runs as though the code was inside of an infinite loop and not in a modal operator. In other words, the packets are processed and the display is updated but the user is locked out.

Am I using a modal operator incorrectly? Is this the wrong template to be using?

  • $\begingroup$ Suggest using scene = context.scene and Not sure of the need for bpy.ops.wm.redraw_timer The timer ticks every 0.1 seconds, How heavy is "code that updates the light". ..Whats the timing on deepcopy and array comparison, vs doing so in "code that process a network packet into an array called dmx here" $\endgroup$ – batFINGER Sep 14 '17 at 4:03
  • $\begingroup$ The redraw timer updates the 3D view after the gain values of the lights have been adjusted. If I comment it out, the data is processed and applied but the user does not see the changes in real time. The code that updates the light is a single line so isn't much. Interesting idea to move the deepcopy, but unfortunately that seems to have no effect. $\endgroup$ – KentAshfield Sep 14 '17 at 18:27

i will answer my own question:

instead of using a handler and registering it in scene update pre, turn it into a modal operator with a timer caller that checks the queue every close interval.

This way i will be able to execute any type of python script using blender api. You will bypass the handler problems!

| improve this answer | |

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.