7
$\begingroup$

This time I have a question about Properties in Blender. I want the operator window of my add-on to have one BoolProperty per action defined in bpy.data.actions and I want them to have the names from bpy.data.actions.keys(). I googled a bit and tried some stuff, but it wont work, theres allways something wrong, so is this even possible and can someone give me some hints on how to do it?

class ExportTSA(bpy.types.Operator, ExportHelper):

    actionprop0 = BoolProperty(name=bpy.data.actions.keys()[0],description="Exporet this action",default=True)
    actionprop1 = BoolProperty(name=bpy.data.actions.keys()[1],description="Exporet this action",default=True)
    actionprop2 = BoolProperty(name=bpy.data.actions.keys()[2],description="Exporet this action",default=True)
    actionprop3 = BoolProperty(name=bpy.data.actions.keys()[3],description="Exporet this action",default=True)

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

        row = layout.row()
        row.prop(self,"actionprop0")
        row = layout.row()
        row.prop(self,"actionprop1")
        row = layout.row()
        row.prop(self,"actionprop2")
        row = layout.row()
        row.prop(self,"actionprop3")

Heres a simplified version of my class, to demonstrate the idea. Instead of making hardcoded props like actionprop0, actionprop1... I want it to be dynamic in a way that it creates an automatic list, assigns the correct names, registers each one and draws them. I also found that you get into trouble when using bpy.data.actions where I used it, after I googled it it turns out that blender seems to be not fully initialized at that point so that causes errors, which might lead to additional problems.

$\endgroup$
2
$\begingroup$

I don't think dynamic property creation is possible. I've tried it before, and Blender always complains:

rna_uiItemR: property not found: [property_name]

An alternative way would be to put the property in bpy.types.Action instead, so every actions already have the property. Then it's only a matter of displaying it.

import bpy

class EX_dynamic_property(bpy.types.Panel):
    bl_idname = 'EX_dynamic_property'
    bl_label = 'Dynamic Property'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'

    def draw(self, context):
        layout = self.layout
        for action in bpy.data.actions:
            layout.prop(action, 'EX_export_this', text=action.name)
        layout.operator('view3d.print_action_export_status')

class OT_dynamic_property(bpy.types.Operator):
    bl_idname = 'view3d.print_action_export_status'
    bl_label = 'Print'
    bl_options = {'REGISTER'}

    def execute(self, context):
        print('*' * 5)
        for action in bpy.data.actions:
            print("%s:\t%s" % (action.name, action.EX_export_this))
        return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Action.EX_export_this = bpy.props.BoolProperty(default=False)

if __name__ == "__main__":
    register()

It's easy, and there's not a lot we need to do. Upon execution, the code above will list the property:

Screenshot

$\endgroup$
  • $\begingroup$ Thanks alot, it´s not perfect but it works fine so i´ll just go with it $\endgroup$ – Luis W Jul 12 '13 at 11:00
  • $\begingroup$ I've try to change the 'dynamic property' : for action in bpy.data.actions: With : for action in bpy.data.scenes: But it doesn't work. Does your solution only work with action or it also work with other bpy.data? (I want to create a dynamic check box panel with the Scene.) $\endgroup$ – lucblender Nov 18 '13 at 9:33
  • $\begingroup$ @lucblender: Scene is a subclass of ID, so it should work. That iteration accesses Action class' boolean EX_export_this property, which is added on script registration. Within register() function, you need to substitute bpy.types.Action with bpy.types.Scene. $\endgroup$ – Adhi Nov 18 '13 at 11:20
  • $\begingroup$ Sorry for asking question again but is it possible to create a dynamic property panel with string, int, etc... property and not boolean? Edit: I've found it's in registration bpy.types.Scene.RenderTrue = bpy.props.StringProperty(default='Text') $\endgroup$ – lucblender Dec 16 '13 at 15:18
  • $\begingroup$ @lucblender Yes, as long as the data type is supported by bpy.props. $\endgroup$ – Adhi Dec 16 '13 at 20:36
8
$\begingroup$

In addition to what Adhi suggested, you can use CollectionProperty in your operator to store key value pairs (where keys are name of the action and values are boolean values). For this to work you must...

  • create a subclass of PropertyGroup that will hold single key-value pair.
  • populate this collection from Operator.invoke method (you might already have it)

So the code goes like this:

import bpy
from bpy_extras.io_utils import ExportHelper
from bpy.props import *

class ActionSelProperty(bpy.types.PropertyGroup):
    name = StringProperty(name="Action Name")
    export = BoolProperty(name="Export", description="Exporet this action", default=True)

class ExportTSA(bpy.types.Operator, ExportHelper):
    bl_idname = "test.export_tsa_op"
    bl_label = "Export TSA"

    actionprop = CollectionProperty(name="Actions", type=ActionSelProperty, description="Select actions to exporet")
    filename_ext = "*.*" # Only needed if subclassing `ExportHelper`

    def invoke(self, context, event):
        for aname in bpy.data.actions.keys():
            self.actionprop.add().name = aname
        wm = context.window_manager
        wm.fileselect_add(self)
        return {'RUNNING_MODAL'}

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

        for aindx in range(len(self.actionprop)):
            row = layout.row()
            row.prop(self.actionprop[aindx], "export", text=self.actionprop[aindx].name)

    def execute(self, context):
        for aprop in self.actionprop:
            print("%s:\t%s" % (aprop.name, aprop.export))
        return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)

if __name__ == "__main__":
    register()

In this case, name is a key and export is a boolean value.

PS: Invoke by searching Export TSA. Screenshots:

enter image description here enter image description here

This may not be perfect, but you can investigate more! :)

HTH

$\endgroup$
  • $\begingroup$ I tried your implementation and it works, but adhi´s seemed a little bit simpler but thanks anyways, i appreciate the help $\endgroup$ – Luis W Jul 12 '13 at 11:01
  • $\begingroup$ Love your answer, this is definitely the right way to do it, though I must admit, adhi's answer is very interesting. $\endgroup$ – Tcll Sep 23 '16 at 20:11

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.