Skip to content

[solved] Why is my Blender addon panel property read only?

Read only, immutable, frozen, unchanging, static… just not working!


tl;dr: Both the panel and the operator need access to any properties- using a PointerProperty to a PropertyGroup which holds the operator options / properties and is stored somewhere accessible (like bpy.types.WindowManager) is a decent way of doing this (ref).


When I went to implement the panel to provide the options for the ‘split into words’ operator, I found that I could display the one option I had written for the operator, but it wouldn’t change:

As part of QTE, I am implementing a new feature: splitting a text strip with a sentence into individual words which appear over time.

It took me a while to figure out panels for setting custom keymap items, but it turns out those are handled just very slightly differently anyway. Everywhere I looked talked about setting properties when calling an operator, but not why I could show an option on a panel but not set it.

You know how when you find a bunch of results that are talking about something very close to what you want to do but not quite, and a bunch of the results are from 10 years ago and out of date, and you begin to doubt your sanity and lose your hair? Me too.

Finally, as I was in the process of writing a question on BlenderArtists, I stumbled upon a thread that asked pretty much exactly what I was about to:

These operator properties can be made visible to the user in the UI panel: [snip] However, they’re not editable here – they’re locked.

There’s some info about panels and instancing of operators and their properties that follows, which is worth a read.

Elsewhere in the thread, there’s a suggestion about how to define and share operator properties between the operator and the panel, using a PropertyGroup and a PointerProperty. The idea is: create a PropertyGroup class to store settings; then store a reference to that as a PointerProperty either within the WindowManager or the Scene.

That approach works:

Code might speak louder than explanations, so here’s a simplified example from the feature I am working on:

# For reading this, you may want to jump to register() first where the reference to the PropertyGroup is stored, then back to the operator and panel classes

# Options / properties of the operator & panel - the PropertyGroup
class AppearingWordsOptions(bpy.types.PropertyGroup):
    time_offset: bpy.props.FloatProperty(
        name="Time offset",
        default=1,
        min=0.0,
        soft_max=5,
        step=5,
        description="Time between words appearing",
        update=update_frames_from_time,
    )

    frame_offset: bpy.props.IntProperty(
        name="Frame offset",
        default=0,
        min=0,
        soft_max=300,
        step=5,
        description="Frames between words appearing",
        update=update_time_from_frames,
    )

# The operator itself
class SEQUENCER_OT_split_to_appearing_words(TextSequenceAction):
    # (parts snipped)
    def execute(self, context):
        prop_group = context.window_manager.appearing_text_options
        frame_offset = prop_group.frame_offset
    # (rest of operator)

# The panel
class SEQUENCER_PT_appearing_text(bpy.types.Panel):
    """Panel for appearing text"""
    bl_label = "Appearing Words"
    bl_space_type = "SEQUENCE_EDITOR"
    bl_region_type = "UI"

    def draw(self, context):
        """Draw the appearing text panel"""
        prop_group = context.window_manager.appearing_text_options
        layout = self.layout

        layout.operator("sequencer.split_to_appearing_words")
        layout.prop(prop_group, "time_offset", slider=True)
        layout.prop(prop_group, "frame_offset", slider=True)

# register the classes AND set up a PointerProperty to the operator/panel options in WindowManager

def register():
    for classname in REGISTER_CLASSES:
        bpy.utils.register_class(classname)
    for classname in PREFERENCES_CLASSES:
        bpy.utils.register_class(classname)
    bpy.types.SEQUENCER_PT_effect.append(appearing_text_panel_layout)

    bpy.types.WindowManager.appearing_text_options = \
        bpy.props.PointerProperty(type=AppearingWordsOptions)


def unregister():
    for classname in REGISTER_CLASSES:
        bpy.utils.unregister_class(classname)
    for classname in PREFERENCES_CLASSES:
        bpy.utils.unregister_class(classname)
    bpy.types.SEQUENCER_PT_effect.remove(appearing_text_panel_layout)

    del bpy.types.WindowManager.appearing_text_options

Since some of the references to this dated back ~10 years, I asked a follow-up question about whether this was still the right approach on BlenderArtists. Hopefully this and the follow up Q will spare someone else’s hair!

1 thought on “[solved] Why is my Blender addon panel property read only?”

  1. Pingback: Quicker Text Editing in Blender (Part 10): Beta 2 Release – Rob's Blog

Tell us what's on your mind

Discover more from Rob's Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading