Tracking changes of component definitions with observers
-
Hey,
I'm trying to track changes of the model with observers. An EntitiesObserver added to active_model lets me see when faces are created outside any component. What do I have to do to see changes inside components? What I tried to do is add an EntitiesObserver to the entities object of each newly created ComponentDefinition but it doesn't seem to work.
Thanks,
Ralf -
Attach an EntitiesObserver subclass to the Definition's entities object (just as you did the model's entities object.)
some_defn.entities.add_observer( defn_watcher_by_oric )You can also attach a custom subclass of EntityObserver to the ComponentDefinition objects themselves ??
-
@oricatmos said:
What I tried to do is add an EntitiesObserver to the entities object of each newly created ComponentDefinition but it doesn't seem to work.
OK.. I see you tried that (my previous post was the first of the morning. "yawn")
IF you are doing this inside a method, it's possible the references are being Garbage Collected.
You can try (and I am assuming you wrap your code inside a module,) to use module var references for both the definition entities collection objects and the custom observer instance.
module Oric @@my_ents_spy = MyDefnEntitiesObserver.new() @@watched_comp_ents = [] # a blank array def self.attach_spies() Sketchup.active_model.defintions.each {|defn| ents = defn.entities unless @@watched_comp_ents.include?( ents ) success = ents.add_observer( @@my_ents_spy ) if success @@watched_comp_ents << ents else puts("Error attaching observer to #{defn.inspect} entities collection; #{ents.inspect}") end end } end # module init unless file_loaded?(__FILE__) self.attach_spies() file_loaded(__FILE__) end end
-
@dan rathbun said:
IF you are doing this inside a method, it's possible the references are being Garbage Collected.
I think it's got something to do with the references. Inside my DefinitionsObserver class I was using an instance variable to hold a reference to my EntitiesObserver like this:
# class definition inside module AC3D_Raven_Exporter class DefinitionsObserver < Sketchup;;DefinitionsObserver @entities_observer = AC3D_Raven_Exporter;;EntitiesObserver.new def onComponentAdded(definitions, definition) definition.entities.add_observer(@entities_observer) end end
This didn't work (I think I should have used the method initialize). It works if I change it to a class variable. It also works if I just create a new EntitiesObserver every time I need to add one. But that's a waste of resources.
Thanks for the help!
-
@oricatmos said:
This didn't work (I think I should have used the method initialize).
Yes you do. Your variable was defined in the wrong scope.
-
@thomthom said:
@oricatmos said:
This didn't work (I think I should have used the method initialize).
Yes you do. Your variable was defined in the wrong scope.
Where exactly did the variable end up anyway? did it exist only while the class definition was read from the file and executed?
-
I got defined as a class level instance variable.
Here's a breakdown if the scopes: http://railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/ -
FWIW,
you may want this as a singleton that is shared amongst all instances (as you've almost written by mistake).
"class instance variables" is definitely a double-take.
Adam
-
@adamb said:
you may want this as a singleton that is shared amongst all instances (as you've almost written by mistake).
Like so:
# class definition inside module AC3D_Raven_Exporter class DefinitionsObserver < Sketchup;;DefinitionsObserver @@entities_observer = nil # ref to the singleton instance attr_reader( ;entities_observer ) def initialize() if @@entities_observer.nil? # ref'ing the class ref @@entities_observer = AC3D_Raven_Exporter;;EntitiesObserver.new() # otherwise the instance to the observer is valid and just reuse it. end @entities_observer = @@entities_observer end def onComponentAdded(definitions, definition) definition.entities.add_observer(@entities_observer) end end
ADD: and you can do the same thing 1 level up (in your custom AppOserver,) by creating a singleton instance of the DefinitionsObserver, and attaching it to all the component definitions that you wish to "watch".
I usually also write a detach_from() method, that uses an array or hash of "watched" items, in order to detach observers when I no longer need to watch them.
Advertisement