My add-on acts upon a hierarchy of data (a tree). I am not sure how best to represent this hierarchy as properties to expose the data to the user.
For simplicity, let us define an example: say that each node of the tree has a "value" which for example purposes is a float. Each node also has zero, one, or many child nodes. As I understand it, properties must all be registered up front in register(), which is the problem -- I guess I need to register all the properties for all the children that could ever exist?
I have had good results with conditionally presenting UI elements in draw(), and so I thought that one approach could be to add an "isEnabled" flag to the node class and define the tree as having a certain maximum depth with each node having a maximum number of children. If in our example the maximum tree that we require has a max depth of 2 and max children of 5, we end up with 31 nodes: the root, the root's 5 children, and then each child has 5 children.
Then, for every node in the tree, for node.value and node.isEnabled register a property in register(). In draw, we can use the isEnabled flag to show or hide the children of a node, which kind of expands or collapses the tree.
Is there a cleaner way to map this kind of data to Blender properties?
Edit: I learned about PropertyGroup, but as I expected it doesn't like circular references.
class MyNode(bpy.types.PropertyGroup):
value = bpy.props.IntProperty(name="value", default=1, min=1, max=1000, description="")
child1 = bpy.props.PointerProperty(type=MyNode)
results in:
NameError: name 'MyNode' is not defined
But I think you could define classes for each level:
A MyRoot
___|___
/ \
B C MyTrunk
| |
/ \ / \
D E F G MyLeaf
I think that MyRoot can have a bpy.props.CollectionProperty(type=MyTrunk) and MyTrunk each have a collection of MyLeaf and then in register(), on single PointerProperty could be registered of type MyRoot.
This is pretty clean, except that you need to define a class for each level of the hierarchy. Therefore the hierarchy must necessarily be short and the maximum depth limited in advance (by the number of classes you're willing to define).


NodePropertyof, say,PointerProperty? Or doesn't the API let you in that far? – Robin Betts Jun 04 '19 at 10:33bpy.propsproperties set up properties on the classes just how blender likes them to display in UI etc. And in particular store data in blend file. Added example to answer above wherecontext.scene.mytree.nodesis a dictionary mapping to make it function similarlyish to saynode_tree.nodes. – batFINGER Jun 04 '19 at 11:03