Hi,
I have attached a AppObserver to my model.
When I export the model to obj sometimes. PreSave in the app observer is called twice.
Console Logs
Exporting C:\Users\Ajay\Documents\Hexagon.skp to obj
Export path: C:/Users/Ajay/AppData/Local/Temp/sentio/Hexagon/Hexagon/Hexagon.obj
Pre save callback
Pre save callback
Error: #<TypeError: reference to deleted DrawingElement>
Even if i press Ctrl+S presave is called twice. Followed by two postsave
class ModelSpy < Sketchup::ModelObserver
def self.attach
Sketchup.active_model.add_observer(self::new)
end
def respond_to?(meth)
puts "SketchUp polled #{self.class} for a #{meth.to_s} callback."
super(meth)
end
end
… then execute this …
ModelSpy.attach
Upon saving the model, I see the following in SU2016 … v 16.1.1449
SketchUp polled ModelSpy for a onPreSaveModel callback.
SketchUp polled ModelSpy for a onSaveModel callback.
SketchUp polled ModelSpy for a onPostSaveModel callback.
… so all looks good and normal.
@rajawatWhat SketchUp version are you seeing this on?
(Your forum profile needs to be updated to show your SketchUp version.)
This might happen if your code has attached an observer twice. (Although in most cases, SketchUp will check to see if the object is already attached, and move it to the end of the callback queue, or ignore the attachment call.)
There have been double callback call bugs in the past.
But I ran the test again with an OBJ file export and got the same normal expected output.
No double calls.
However, the onSaveModel callback was the old name (version 6) that is still there for backward compatibility.
Going forward you should use onlyonPostSaveModel callback (version 8+).
If you define both, SketchUp polls your observer object and will call both if they are both defined
Observer objects do not need to be instantiated classes. They can be a module. Try this …
module Solutionario
module Sentio
extend self
REG_KEY = 'Sentio'.freeze
IS_WIN =( Sketchup.platform == :platform_win rescue RUBY_PLATFORM !~ /darwin/i )
IS_OSX = !IS_WIN
attr_accessor :login_dialog
attr_accessor :upload_dialog
def init
Sketchup.add_observer(self)
end
def expectsStartupModelNotifications
return true
end
def onNewModel(model)
puts "New model"
if @state.eql? "upload"
if @upload_dialog != nil
@upload_dialog.activate
end
end
model.add_observer(self)
end
def onOpenModel(model)
puts "Open model"
if @state.eql? "upload"
if @upload_dialog != nil
@upload_dialog.activate
end
end
model.add_observer(self)
end
def onQuit
puts "Quitting sketchup"
if @upload_dialog != nil
@upload_dialog.onQuit
end
# You do not really need to do this as SketchUp
# will detach all observers during shutdown.
Sketchup.active_model.remove_observer(self)
Sketchup.remove_observer(self)
end
def onPreSaveModel(model)
puts "Pre save callback"
if @upload_dialog != nil
@upload_dialog.onPreSave
end
end
def onPostSaveModel(model)
puts "Post save callback"
if @upload_dialog != nil
@upload_dialog.onPostSave
end
end
unless file_loaded?(__FILE__)
menu = UI.menu('Plugins')
#TODO Group the multiple menu items.
menu.add_item('Sentio') {
self.display
}
init() # attach the Sentio module as an AppObserver
file_loaded(__FILE__)
end
end
end
No problem. If you think about it, a module is an instance of class Module, so it also is actually an instance object.
However, the key here with regard to SketchUp API observers is that they are now all semi-abstract, in that the classes have been made devoid of the actual prototype callbacks, which never did anything anyway. So the core developers decided that it was faster to “duck-type” observer objects by asking them if they respond to a callback before calling that callback.
In addition, the API has never hard typed any observer object by testing if it is descended from any particular observer superclass. This means that you can write more robust hybrid observer classes that have a mixture of callbacks from multiple observers. You don’t even need to declare any superclass for an observer. These hybrid observers often make it easier as the single module or class can share object references that otherwise would need to be passed around as method parameters in a clunky way.
The API observer classes only exist now as a means of documenting the optional callbacks (via YARD.)