4
$\begingroup$

I have created a basic addon that loads text files and applies some game logic. In its script form it works fine, no problems, however when I try install it as an addon I get the pyrna_struct_meta_idprop_setattro() readonly error when trying to assign my scene variables.

I did some research and found a method that uses an initialize button which seems to work.

import bpy


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"


def draw(self, context):
    layout = self.layout

    # If Scene.my_prop wasn't created in register() or removed, draw a note
    if not hasattr(context.scene, "my_prop"):
        layout.label("Scene does not have a property 'my_prop'")

    # If it has no longer the default property value, draw a label with icon
    elif context.scene.my_prop != 'default value':
        layout.label("my_prop = " + context.scene.my_prop, icon="FILE_TICK")

    # It has the default property value, draw a label with no icon
    else:
        layout.label("my_prop = " + context.scene.my_prop)

    layout.operator(InitMyPropOperator.bl_idname, text=InitMyPropOperator.bl_label)


class InitMyPropOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "scene.init_my_prop"
    bl_label = "Init my_prop"


@classmethod
def poll(cls, context):
    return context.active_object is not None

def execute(self, context):
    if context.scene.my_prop != "initialized":
        context.scene.my_prop = "initialized"
        self.__class__.bl_label = "Change my_prop"
    else:
        context.scene.my_prop = "foobar"
        self.__class__.bl_label = self.bl_label
    return {'FINISHED'}



def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.my_prop = bpy.props.StringProperty(default="default value")

def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.my_prop

if __name__ == "__main__":
    register()

Worst-case scenario I will probably end up using this, however if possible I would like to avoid it.

Are there other ways of storing variables like this which can be referenced across multiple modules? (I have 1 Enum property for a drop down list, and 1 Integer property which is updated and changed).

The script only runs on Camera objects.

Thanks!

$\endgroup$

1 Answer 1

4
$\begingroup$

Finally managed to solve this!

One problem with the method mentioned above is if the user changes scene with the addon enabled the UI breaks because the scene properties are no longer available.

Solution:

initialize your variables under the register function and register the classes within your script.

def register():
bpy.types.Scene.myprop1 = IntProperty(default = 0)
bpy.types.Scene.myprop2 = EnumProperty(items = [('ONE', 'ONE', 'NUMBER ONE'),('TWO', 'TWO', 'NUMBER TWO'),('THREE','THREE', 'NUMBER THREE')],name = "Choose Number", default='ONE')
bpy.utils.register_class(MyPanel)
bpy.utils.register_class(MyOperator)

Then whenever you want to reference or change the item in the script use:

bpy.context.scene.myprop1

Obviously replacing myprop1 with the name of the property. For example:

print(bpy.context.scene.myprop1, bpy.context.scene.myprop2)
>>>0 ONE
bpy.context.scene.myprop1 += 1
print(bpy.context.scene.myprop1, bpy.context.scene.myprop2)
>>>1 ONE

Last but not least to unregister the script:

bpy.utils.unregister_class(MyPanel)
bpy.utils.unregister_class(MyOperator)
del bpy.types.Scene.myprop1
del bpy.types.Scene.myprop2

Initially I was using:

bpy.context.scene['prop1']

from the code snippets but this doesn't work well so I recommend using scene.prop1 instead of scene['prop1']

Hope this helps!

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .