Modal operator and menu

Some one know why I can’t use a Menu for run a Modal operator?
ex. this script


import bpy
class ModalOperator(bpy.types.Operator):
    bl_idname = "test.modal"
    bl_label = "test modal"
 
    def modal(self, context, event):
        print(event.type)
 
    def invoke(self, context, event):
        print("Invoke")
 
def menu_func(self, context):
    self.layout.operator(ModalOperator.bl_idname, text="Description")
 
def register():
    bpy.utils.register_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.append(menu_func)
 
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(menu_func)
 
if __name__ == "__main__":
    register()

return

invalid operator call TEST_OT_modal

Thanks

does this work?


import bpy
class ModalOperator(bpy.types.Operator):
    bl_idname = "test.modal"
    bl_label = "test modal"
 
    def modal(self, context, event):
        print(event.type, "ARGH")
        return {'RUNNING_MODAL'}
 
    def invoke(self, context, event):
        print("Invoke2")
        return {'PASS_THROUGH'}
 
def menu_func(self, context):
    self.layout.operator(ModalOperator.bl_idname, text="Description")
 
def register():
    bpy.utils.register_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.append(menu_func)
 
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(menu_func)
 
if __name__ == "__main__":
    register()

it seems to avoid that error

I add some return statement, but always don’t work:


import bpy
class ModalOperator(bpy.types.Operator):
    bl_idname = "test.modal"
    bl_label = "test modal"
 
    def modal(self, context, event):
        if event.type == 'LEFTMOUSE':
            return {'FINISHED'}
        elif event.type in ('RIGHTMOUSE', 'ESC'):
            return {'CANCELLED'}
        print(event)
        return {'RUNNING_MODAL'}
 
    def invoke(self, context, event):
        print("Invoke")
        return {'RUNNING_MODAL'}
 
def menu_func(self, context):
    self.layout.operator(ModalOperator.bl_idname, text="Description")
 
def register():
    bpy.utils.register_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.append(menu_func)
 
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(menu_func)
 
if __name__ == "__main__":
    register()
 
#Return: invalid operator call TEST_OT_modal

Any idea?

You forgot to add a modal handler to the window manager. Include the following in your invoke function:

context.window_manager.modal_handler_add(self)

You can also have a look at the Operator Modal script template.

you are right , thanks :slight_smile:

Hi.

Does this still works on 2.58? Im having the same problem.
I tried to add the simple operator modal template to bpy.types.VIEW3D_MT_object_specials and still getting the invalid operator call error.


import bpy
from bpy.props import IntProperty, FloatProperty


class OBJECT_OT_modal_operator(bpy.types.Operator):
    '''Move an object with the mouse, example.'''
    bl_idname = "object.modal_operator"
    bl_label = "Simple Modal Operator"

    first_mouse_x = IntProperty()
    first_value = FloatProperty()

    def modal(self, context, event):
        if event.type == 'MOUSEMOVE':
            delta = self.first_mouse_x - event.mouse_x
            context.object.location.x = self.first_value + delta * 0.01

        elif event.type == 'LEFTMOUSE':
            return {'FINISHED'}

        elif event.type in ('RIGHTMOUSE', 'ESC'):
            context.object.location.x = self.first_value
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.object:
            context.window_manager.modal_handler_add(self)
            self.first_mouse_x = event.mouse_x
            self.first_value = context.object.location.x
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "No active object, could not finish")
            return {'CANCELLED'}

    

def menu_draw(self, context):
    self.layout.operator("object.modal_operator")
    
bpy.types.VIEW3D_MT_object_specials.append(menu_draw)

def register():
    bpy.utils.register_class(OBJECT_OT_modal_operator)



def unregister():
    bpy.utils.unregister_class(OBJECT_OT_modal_operator)


if __name__ == "__main__":
    register()