3
$\begingroup$

I have a simple panel that I've made. I have a bunch of checkboxes and I want to use them to change the value of a few custom properties e.g. when the checkbox is unchecked, the value should be 0, and when it is checked, the value is 1. I have done the logical thing:

being called from inside my Panel's draw function:

if "iSight_Camera_Indicator" == True:
    bpy.data.objects["Macbook_Gold"]["00_iSight Camera Indicator"] = 1
else:
    bpy.data.objects["Macbook_Gold"]["00_iSight Camera Indicator"] = 0

But it gives me this error:

Traceback (most recent call last):
  File "/Users/MacBook/Documents/Blender/Blends/MacBook/MacBook.blend/macbook_controller.py", line 86, in draw
AttributeError: Writing to ID classes in this context is not allowed: Macbook_Gold, Object datablock, error setting Object.00_iSight Camera Indicator

location: <unknown location>:-1
$\endgroup$
0
7
$\begingroup$

The draw function of a panel is intended only for adjusting UI, it is essentially blocked from doing anything else by design. At first this limitation can be perceived as restrictive, but it's really there to prevent bad practice and unnecessary updates. When you interact with a Panel (or any element of UI) its draw function is called many times per second when your mouse moves.

As soon as you need to update objects or scene data via UI you should attach an update function to your properties or make dedicated operators (triggered by buttons).

Update Function

enter image description here

Please see this answer for why a ProperyGroup is a good idea to keep your properties organized. In the code below I've commented out where you would have an opportunity to react to the tickbox state. The update-response is part of the property not part of the draw function of a Panel.

import bpy

def common_update(self, context, origin):
    if origin == 'my_bool_one':
        print('button_one', getattr(self, origin))
        # bpy.data.objects["Macbook_Gold"]["00_iSight Camera Indicator"] = getattr(self, origin)
    if origin == 'my_bool_two':
        print('button_two', getattr(self, origin))


class IgnitProperties(bpy.types.PropertyGroup):
    my_bool_one = bpy.props.BoolProperty(
        update=lambda self, context: common_update(self, context, 'my_bool_one')
    )
    my_bool_two = bpy.props.BoolProperty(
        update=lambda self, context: common_update(self, context, 'my_bool_two')
    )

class IGLayoutDemoPanel(bpy.types.Panel):
    """Creates a Panel in the scene context of the properties editor"""
    bl_label = "IG Layout Demo"
    bl_idname = "SCENE_PT_layout"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        col = layout.column()
        col.prop(scene.ignit_panel, "my_bool_one", text='option 1')
        col.prop(scene.ignit_panel, "my_bool_two", text='option 2')


def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.ignit_panel = bpy.props.PointerProperty(type=IgnitProperties)


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


if __name__ == "__main__":
    register()

Operators

See the TextEditor > Templates -> Python -> Operator Simple

$\endgroup$
1
  • $\begingroup$ as for the operators.. that's really a separate question, but enum should be fine to get a working protoype $\endgroup$ – zeffii Dec 27 '15 at 21:32

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.