EntitiesObserver and Attributes - work around
-
There is still the problem that you modify the model on observer events. When you do that you interfer with any operation that is going on - which might be in the middle of a start/commit operation of another plugin or native tool. You'll be adding to the Undo stack - causing unexpected behaviour when the user expects to undo their last operation but instead the undo is your injected attribute change.
Model change at observer events may cause bug splats. -
@thomthom said:
There is still the problem that you modify the model on observer events. When you do that you interfer with any operation that is going on - which might be in the middle of a start/commit operation of another plugin or native tool. You'll be adding to the Undo stack - causing unexpected behaviour when the user expects to undo their last operation but instead the undo is your injected attribute change.
Model change at observer events may cause bug splats.Im not sure how to do it yet, but I think a solution could be to remove the observers, when editing the group, and adding the observer again when finished.
It seems to be very quick to add observers to ALL the entities in the model, and its not possible to add more than one observer to each entity, so you dont have to take care if the entity allready has got one.
-
@rvs1977 said:
It seems to be very quick to add observers to ALL the entities in the model
Strongly recommend you use observers sparsely. Also what you do within the events. Some events trigger many times a second - and that mean you can easily bog down SketchUp.
@rvs1977 said:
and its not possible to add more than one observer to each entity, so you dont have to take care if the entity allready has got one.
Yes you can add more than one observer.
-
@rvs1977 said:
and its not possible to add more than one observer to each entity, so you dont have to take care if the entity allready has got one.
@thomthom said:
Yes you can add more than one observer.
What I meant was, if you do like this:
(adding 3 identical observers to one entity)
Code:
[....]
mygroup.entities.add_observer(myEntitiesObserver.new)
mygroup.entities.add_observer(myEntitiesObserver.new)
mygroup.entities.add_observer(myEntitiesObserver.new)
[....]it will only have one myEntitesObserver attached to mygroup. - not three. That means its easier to handle... You dont need to check if its allready added, its faster just to add new one to every entities.
Yes you can add more observers to one entity eg. MyEntitiesObserverWatchFaces and MyEntitiesObserverWatchEdges
-
Not correct. For each new instance of your observer class you attach you add an observer:
Here I first drew one line. Then added another observer. When I draw a second line I get two observer triggering - and they are both of the same class.However, if you attach the same instance of your observer to the same element, then it's no extra observers added:
Here I only ever get one observer triggering - because I'd only ever attached a single instance.I store the reference to the observers I use. Then I remove it - just to be sure.
` @entities_observer = myEntitiesObserver.new
def self.observers
mygroup.entities.remove_observer( @entities_observer )
mygroup.entities.add_observer( @entities_observer )
end`Just to be sure
-
@thomthom said:
Not correct. For each new instance of your observer class you attach you add an observer
Ok, maybe you are right, but to me it seems like it only triggers once, even though I have attached it many times in a row.
Could it be that it is overwritten each time its attached?! As far as I can see its not possible to see which observers is added in the model.
If you try the code I have attached above you can what I mean...
(Run the first code a couple of times to get some boxes without observers, then run the second code as many times you want, and the observers only triggers once) -
@rvs1977 said:
Could it be that it is overwritten each time its attached?!
If you attach the same instance. But if you do like in my second example, you keep a reference to an instance and use that reference when you attach observers it won't create duplicates.
@rvs1977 said:
As far as I can see its not possible to see which observers is added in the model.
Correct, there isn't.
-
@rvs1977 said:
If you try the code I have attached above you can what I mean...
(Run the first code a couple of times to get some boxes without observers, then run the second code as many times you want, and the observers only triggers once)Got a sample model with "Boxes"?
What do you do to trigger the events?Btw - you know that
model.entities
isn't all the entities in the model? It's just the root context. The rest of the entities is inside Groups, Components and Image entities.
http://www.thomthom.net/thoughts/2012/02/definitions-and-instances-in-sketchup/ -
@thomthom said:
Got a sample model with "Boxes"?
What do you do to trigger the events?In post number 7 in this thread there are two pieces of codes attached...
The 1. piece of code draw boxes without observers, the 2. piece of code add observers to the boxes.
When you have deleted a box, try to undo, and it attaches new observers in a way that it solves the problem with lost observers.It triggers when the red face is modified (push/pulled) using the def onElementModified(entities, entity) in the "MyEntitesObserver", and it messure the area of the green face.
-
Ok - seeing it now. Still trying to work out the code flow.
But you still have the issue with setting observers adds to the Undo stack.
So when you push pull - the observer triggers and add an event to the Undo stack. So when the user press undo after push/pull he first undo the attribute change - then he has to undo again to undo the push pull.
If the user undo just one - he will have undone the attribute change, but not the push-pull - making your data invalid. Also, the user is likely to become frustrated that Undo is working unpredictably. -
Worked out why your observer triggered only once:
The set_attribute call short-circuited the other events. When I commented outset_attribute
and also changed theUI::Messagebox
to this:
puts "#{self} - Height changed - green face - area before: " + attr_area.to_s + " m² - area after: " + yv_area_new.to_s + " m²"
You will then see that all theMyEntitiesObserver.new
adds new observers - and doesn't remove the old ones. You'll see it output events for each instance you created. It was just your model change that prevented the events to propagate.<span class="syntaxdefault"><br /> mod </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model </span><span class="syntaxcomment"># Open model<br /> </span><span class="syntaxdefault">ent </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">mod</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities </span><span class="syntaxcomment"># All entities in model<br /> </span><span class="syntaxdefault">sel </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">mod</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">selection </span><span class="syntaxcomment"># Current selection<br /><br /> </span><span class="syntaxkeyword">class </span><span class="syntaxdefault">MyModelObserver </span><span class="syntaxkeyword">< </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">ModelObserver<br /> def onTransactionUndo</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">model</span><span class="syntaxkeyword">) <br /> </span><span class="syntaxcomment">#UI.messagebox("onTransactionUndo; " + model.to_s)<br /> </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each </span><span class="syntaxkeyword">do |</span><span class="syntaxdefault">o</span><span class="syntaxkeyword">|<br /> </span><span class="syntaxdefault">attr </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">o</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">get_attribute </span><span class="syntaxstring">"rsdict"</span><span class="syntaxkeyword">,</span><span class="syntaxstring">"area"<br /> <br /> </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">attr <br /> o</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_observer</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">MyEntityObserver</span><span class="syntaxkeyword">.new) <br /> </span><span class="syntaxdefault">o</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_observer</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">MyEntitiesObserver</span><span class="syntaxkeyword">.new) <br /> </span><span class="syntaxdefault">end<br /> end <br /> end <br /> end </span><span class="syntaxcomment">#MyModelObserver<br /> #Adding ModelObserver - Undo<br /> </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_observer</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">MyModelObserver</span><span class="syntaxkeyword">.new)<br /><br /> class </span><span class="syntaxdefault">MyEntityObserver </span><span class="syntaxkeyword">< </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">EntityObserver <br /> </span><span class="syntaxcomment">#def onEraseEntity(entity) #this work <br /> #UI.messagebox("onEraseEntity; " + entity.to_s) <br /> #end<br /> <br /> #def onChangeEntity(entity) <br /> #UI.messagebox("onChangeEntity; " + entity.to_s)<br /> #end<br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#class<br /><br /> </span><span class="syntaxkeyword">class </span><span class="syntaxdefault">MyEntitiesObserver </span><span class="syntaxkeyword">< </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">EntitiesObserver <br /> def onElementModified</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">entity</span><span class="syntaxkeyword">) <br /> </span><span class="syntaxdefault">attr_length </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">entity</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">get_attribute </span><span class="syntaxstring">"rsdict"</span><span class="syntaxkeyword">, </span><span class="syntaxstring">"yv_face_length"<br /> </span><span class="syntaxdefault">attr_height </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">entity</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">get_attribute </span><span class="syntaxstring">"rsdict"</span><span class="syntaxkeyword">, </span><span class="syntaxstring">"yv_face_height" <br /> <br /> </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">attr_length <br /> entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each </span><span class="syntaxkeyword">do |</span><span class="syntaxdefault">i</span><span class="syntaxkeyword">|<br /> </span><span class="syntaxdefault">attr_area </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">i</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">get_attribute </span><span class="syntaxstring">"rsdict"</span><span class="syntaxkeyword">, </span><span class="syntaxstring">"yv_face_area"<br /> <br /> </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">attr_area<br /> yv_area_new </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">i</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">area</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_m</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_m<br /> </span><span class="syntaxcomment">#UI.messagebox "Length changed - area before; " + attr_area.to_s + " m² - area after; " + yv_area_new.to_s + " m²" <br /> #i.set_attribute "rsdict", "yv_face_area", yv_area_new<br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#attr_area<br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#each do<br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#if attr_length<br /> <br /> <br /> </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">attr_height <br /> entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each </span><span class="syntaxkeyword">do |</span><span class="syntaxdefault">i</span><span class="syntaxkeyword">|<br /> </span><span class="syntaxdefault">attr_area </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">i</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">get_attribute </span><span class="syntaxstring">"rsdict"</span><span class="syntaxkeyword">, </span><span class="syntaxstring">"yv_face_area"<br /> <br /> </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">attr_area<br /> yv_area_new </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">i</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">area</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_m</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_m<br /> puts </span><span class="syntaxstring">"#{self} - Height changed - green face - area before; " </span><span class="syntaxkeyword">+ </span><span class="syntaxdefault">attr_area</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_s </span><span class="syntaxkeyword">+ </span><span class="syntaxstring">" m² - area after; " </span><span class="syntaxkeyword">+ </span><span class="syntaxdefault">yv_area_new</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_s </span><span class="syntaxkeyword">+ </span><span class="syntaxstring">" m²" <br /> </span><span class="syntaxcomment">#i.set_attribute "rsdict", "yv_face_area", yv_area_new<br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#attr_area<br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#each do<br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#if attr_height<br /> <br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#onElementModified_end <br /> </span><span class="syntaxdefault">end </span><span class="syntaxcomment">#class<br /><br /> </span><span class="syntaxdefault">i </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">0<br /> ent</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each </span><span class="syntaxkeyword">do |</span><span class="syntaxdefault">o</span><span class="syntaxkeyword">|<br /> </span><span class="syntaxdefault">attr </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">o</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">get_attribute </span><span class="syntaxstring">"rsdict"</span><span class="syntaxkeyword">,</span><span class="syntaxstring">"area"<br /> <br /> </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">attr <br /> o</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_observer</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">MyEntityObserver</span><span class="syntaxkeyword">.new) <br /> </span><span class="syntaxdefault">o</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_observer</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">MyEntitiesObserver</span><span class="syntaxkeyword">.new)<br /> </span><span class="syntaxdefault">i </span><span class="syntaxkeyword">+= </span><span class="syntaxdefault">1<br /> end<br /> end<br /><br /> UI</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">messagebox </span><span class="syntaxstring">"number of boxes; " </span><span class="syntaxkeyword">+ </span><span class="syntaxdefault">i</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">to_s<br /></span>
-
I'm not sure how to do these tests.
Are you saying if I pushpull one red face, it triggers events for every instance?? (If there is 200 boxes it triggers 200 times?) (box=instance)
Or will it trigger the number of times, you have runned the script which adds observers? (instance = observer added)
(Because in my case it only shows the UI.messagebox once) -
@rvs1977 said:
Or will it trigger the number of times, you have runned the script which adds observers? (instance = observer added)
(Because in my case it only shows the UI.messagebox once)As describe above - in your case it triggers only once because when you modify the model with
set_attribute
it blocks all the other observers attached. Comment out theset_attribute
code and you'll see all the observers you added will trigger.
And then it's the issue with the Undo stack which I also mentioned. -
Ok. hopefully there is a solution. If I find one I will return...
Advertisement