OnElementAdded inside Group or Component
-
Hi,
I've defined EntitiesObserver class to observe when new Face object is added to entities collection.
class DLEntitiesObserver < Sketchup;;EntitiesObserver def onElementAdded( ents, new_ent ) if new_ent.class == Sketchup;;Face puts "Face added #{new_ent}" end end end Sketchup.active_model.entities.add_observer(DLEntitiesObserver.new() )
This code catches when Face is added directly in model, but doesn't catch when face is added inside some Group or Component instance.
I tried to add another observer to catch when active path is changed and to attach observer to active_entities.class DLModelObserver < Sketchup;;ModelObserver def onActivePathChanged(model) Sketchup.active_model.active_entities.add_observer(DLEntitiesObserver.new()) end end
This catches faces added inside group, but when I open and close group multiple times it adds each time new observer -> so each new face is detected multiple times.
I've tried to find solution on forum, but didn't have success (or used wrong keywords .
So my question is how to detect when new face is added in model, or inside any group, component instance, and how to detect that exactly once?
Thanks in advance,
Marija -
In the observer class code [outside of the 'def' methods], initially set up a hash as an enduring class variable...
@@obs = {}
Then in the method itself, remove any existing observer, so we never get more that one in each entities context...
Sketchup.active_model.active_entities.remove_observer(@@obs[Sketchup.active_model.active_entities])
It fails silently if there is not an observer to remove !
Then add a new observer...
@@obs[Sketchup.active_model.active_entities] = Sketchup.active_model.active_entities.add_observer(DLEntitiesObserver.new()
This is untested, but it should give you the idea...
-
Thanks TIG,
Your post give me the idea and after few modifications and tests code looks like this:
class DLModelObserver < Sketchup;;ModelObserver @@observers = {} def onActivePathChanged(model) #if active_path is nill (no group or component is opened) #skip adding new observer to model entities - since it is added on startup if !Sketchup.active_model.active_path return end Sketchup.active_model.active_entities.remove_observer(@@observers[Sketchup.active_model.active_entities]) #define observer object and try to add it to active_entities #if it is successfully added, update class variable @@observers observer = DLEntitiesObserver.new() if Sketchup.active_model.active_entities.add_observer(observer) @@observers[Sketchup.active_model.active_entities] = observer end end end
It works correctly and each time only single observer is defined for active_entities.
Thanks again,
Marija -
Hi,
I've been experimenting on adding/removing EntitiesObservers when groups/components are opened/closed, and I've found difference in behavior in old and new Sketchup versions.
When I have few nested groups and I open/close them multiple times (without leaving top parent group):
- Sketchup 8 and Sketchup 2013 - observers are added/removed as expected and each new entity is detected only once
- Sketchup 2014 and Sketchup 2015 - it seems like observers aren't removed each time 'onActivePathChanged' is called (although in console is printed that they are removed). When I add new face inside some nested group it is detected multiple times. Number of times EntitiesObserver is called is increased each time I open/close some subgroup.
Below it the code which is independent from my plugin and can be simply loaded in Sketchup for testing purposes:
module DL;;Daylighting #Attach observers to model, entities and materials class DLAppObserver < Sketchup;;AppObserver def initializeObservers(model) model_observer = DL;;Daylighting;;DLModelObserver.new() model_observer.initializeObservers(model) model.add_observer(model_observer) end def onNewModel(model) initializeObservers(model) end def onOpenModel(model) initializeObservers(model) end end class DLModelObserver < Sketchup;;ModelObserver @@observers = {} @@entitiesObserver = nil def initializeObservers(model) @@entitiesObserver = DL;;Daylighting;;DLEntitiesObserver.new() model.entities.add_observer(@@entitiesObserver) end #When new group is opened remove old observers and add new observer for active_entities def onActivePathChanged(model) puts "active path changed" #remove all previous observers @@observers.each_pair{|entities,observer| begin puts "***entities #{entities} remove observer #{observer}; #{entities.remove_observer(observer)}" rescue Exception => e puts "Can't remove observer",e.message end } @@observers={} #if all groups are closed -> don't add observers if !Sketchup.active_model.active_path return end entitiesObserver = DL;;Daylighting;;DLEntitiesObserver.new() entities = Sketchup.active_model.active_entities puts "***entities #{entities} add observer #{entitiesObserver}" if entities.add_observer(entitiesObserver) @@observers[entities] = entitiesObserver end end end class DLEntitiesObserver < Sketchup;;EntitiesObserver def onElementAdded( ents, new_ent ) #detect only Sketchup;;Face entities if new_ent.class == Sketchup;;Face puts "onElementAdded #{ents}; #{new_ent}" end end end end #DL;;Daylighting
To attach these observers to the application just in call in Ruby console
app_observer = DL;;Daylighting;;DLAppObserver.new() app_observer.initializeObservers(Sketchup.active_model) Sketchup.add_observer(app_observer)
I don't understand what I'm doing wrong, because printed messages in ruby console show that old observer is always removed from entities when Active path is changed, but still new faces are detected multiple times.
Once I leave all groups and go back to model (active_path=nil), all observers are like reset and I have only one EntitiesObserver.
When I go inside groups and subgroups again, the number of observers increases again.And to repeat, in Sketchup 8 and Sketchup 2013 - this problem doesn't exist.
Any suggestion is welcome, because I'm moving in circles with this observers.
Thanks in advance,
Marija
Advertisement