I believe all that already works. I use that same style of property management in many of my scripts/AddOns.
It really is such a low overhead to create an Empty and add your collection to it. The collection has to be stored somewhere when the user issues a File/Save. It might as well be stored with an object that the end user can locate and delete, if neccessary.
Here is a code section from my RE:Lay AddOn (which is available, in full, by visiting the link in my signature).
############################################################################
# Parameter Definitions
############################################################################
def updateRELayParameter(self,context):
# This def gets called when one of the tagged properties changes state.
global isBusy
if isBusy == False:
if context != None:
passedScene = context.scene
cf = passedScene.frame_current
print("")
print("updateRELayParameter on frame #" + str(cf))
reviewRELay(passedScene)
class cls_RELay(bpy.types.PropertyGroup):
# The properties for this class which is referenced as an 'entry' below.
target_name = bpy.props.StringProperty(name="Target", description="Type the name of the object that will inherit this objects motion here.")
apply_to_delta = bpy.props.BoolProperty(name="ApplyToDelta", description="When active, results are applied to the delta coordinates instead.", default=True, options={'ANIMATABLE'}, subtype='NONE', update=updateRELayParameter)
offset = bpy.props.FloatProperty(name="Offset", description="Number of frames to delay transformation.", default=0.0, min=-1800.0, max=1800, step=3, precision=2, options={'ANIMATABLE'}, subtype='TIME', unit='TIME', update=updateRELayParameter)
stretch = bpy.props.FloatProperty(name="Stretch", description="Stretch time to slow it down.", default=1.0, min=0.001, max=10.0, step=3, precision=2, options={'ANIMATABLE'}, subtype='FACTOR', unit='NONE', update=updateRELayParameter)
axis_types = [
("0","None","None"),
("1","X","X"),
("2","Y","Y"),
("3","Z","Z"),
("4","XY","XY"),
("5","YZ","YZ"),
("6","XZ","XZ"),
("7","XYZ","XYZ"),
("8","ZXY","ZXY"),
("9","XZY","XZY"),
]
axis_loc = EnumProperty(name="AxisLoc", description="The axis that will be relayed to the target.", default="7", items=axis_types, update=updateRELayParameter)
axis_rot = EnumProperty(name="AxisRot", description="The axis that will be relayed to the target.", default="7", items=axis_types, update=updateRELayParameter)
axis_scale = EnumProperty(name="AxisScale", description="The axis that will be relayed to the target.", default="7", items=axis_types, update=updateRELayParameter)
bpy.utils.register_class(cls_RELay)
# Add these properties to every object in the entire Blender system (muha-haa!!)
bpy.types.Object.Relay_List_Index = bpy.props.IntProperty(min= 0,default= 0)
bpy.types.Object.Relay_List = bpy.props.CollectionProperty(type=cls_RELay)
As far as the update getting called multiple times, I really did not notice any performance hit. But if you know one update will be CPU intensive, you can create an alternate update just for that property and route all others to a general/pass-through update.
Then all we have to do to add a new collection is…
def relay_new_source(lock, passedSourceName, passedSleepTime):
ob_source = fetchIfObject(passedSourceName)
if ob_source !=None:
ob_source.show_name = True
ob_source.hide_render = True
# Populate the new entry in the collection list.
collection = ob_source.Relay_List
collection.add()
l = len(collection)
collection[-1].name= (str(l)+ ENTRY_NAME)
And in the draw() routine you can display such properties by fetching an entry from the collection. If the user changes them, the update() will fire.
if ob.Relay_List:
# Display self created properties.
try:
entry = ob.Relay_List[ob.Relay_List_Index]
except:
entry = None
if entry != None:
box1.prop(entry, "name", text = "Name")
box = layout.box() #Separator
box1 = layout.box()
row1 = box1.row()
row1.label(" Target:", icon='CURSOR')
# Let's let the icon offer a little feedback.
if fetchIfObject(entry.target_name) == None:
box1.prop(entry, "target_name", icon='QUESTION')
else:
box1.prop(entry, "target_name", icon='OBJECT_DATAMODE')
box1.prop(entry, "offset")
box1.prop(entry, "stretch")
layout.separator()
Also, by animating the Relay_List_Index you can cause sets of properties to change over time.