2
$\begingroup$

I want to create locator and move it with my mouse, and eventually correct its position with floatProperty. But I get error in execute : ReferenceError: StructRNA of type Object has been removed What did I miss ? (Blender 2.8)

import bpy
from bpy.props import IntProperty, FloatProperty

class ModalOperator(bpy.types.Operator):
    """Move an object with the mouse, example"""
    bl_idname = "object.modal_operator"
    bl_label = "Simple Modal Operator"
    bl_options = {"REGISTER","UNDO"}

    x_translation = FloatProperty()

    def execute(self, context):
        print (self.locator.name)
        self.locator.location.x += self.x_translation
        return {'FINISHED'}

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

        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):
        bpy.ops.object.empty_add(type='ARROWS')
        context.active_object.name = "locator_start"
        self.locator = context.active_object
        print (self.locator.name)
        if context.object:
            self.first_mouse_x = event.mouse_x
            self.first_value = context.object.location.x

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "No active object, could not finish")
            return {'CANCELLED'}


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


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


if __name__ == "__main__":
    register()
$\endgroup$
0
$\begingroup$

Solution was provided on blenderartist by tricotou: https://blenderartists.org/t/referenceerror-structrna-of-type-object-has-been-removed-between-modal-and-execute/1186026

import bpy
from bpy.props import IntProperty, FloatProperty

def get_locator():
    bpy.ops.object.empty_add(type='ARROWS')
    bpy.context.active_object.name = "locator_start"
    locator = bpy.context.active_object
    return locator

class ModalOperator(bpy.types.Operator):
    """Move an object with the mouse, example"""
    bl_idname = "object.modal_operator"
    bl_label = "Simple Modal Operator"
    bl_options = {"REGISTER","UNDO"}

    x_translation = FloatProperty()
    loc = {}
    def execute(self, context):
        locator = get_locator()
        locator.location.x += self.first_value + self.x_translation
        return {'FINISHED'}

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

        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):
        self.locator = get_locator()
        self.first_mouse_x = event.mouse_x
        self.first_value = context.object.location.x
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}

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


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


if __name__ == "__main__":
    register()

The class ModalOperator runs a 1st time with invoke and modal, creates the locator, then finished. When we modify properties in panel, an undo is performed on what modal did (no more locator here), then execute is launched. So we have to recreate it in execute. (thanks to rjg for the precision)

| improve this answer | |
$\endgroup$
  • 1
    $\begingroup$ The explanation isn't 100% correct. When the modal operator finishes execution, either by returning FINISHED or CANCELED the Empty object still exists. What causes the object to be deleted is the adjusting of the FloatProperty which is treated as an undo of the operations performed by the invoke and modal functions, followed by the call to execute. Hence the objects created before will be removed before execute is run. That is also why bl_options = {"REGISTER", "UNDO"} is used, otherwise the Adjust Last Operation panel wouldn't be displayed. $\endgroup$ – Robert Gützkow Oct 16 '19 at 12:27

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.