How to run a frame change observer
-
I am working on a shop drawing plugin and I need to do some of what I call clean up as the user changes from one scene to the next. The code I have come up with will run clean up on the from scene as desired. Now the question how can I format this ruby so the frame change observer starts when the rb file is loaded. (with out the user clicking on a menu or toolbar)
require 'sketchup.rb' require 'k2ws_Dovetails/k2ws_module.rb' #-NameSpace Module module K²WS #Define the Frame Change Observer which is documented in the Pages class. class FrameChangeObserver def initialize # @run_CleanUp is used to determine if cleanUP should be activated @run_CleanUp = true end # When frameChange is first triggered by User clicking on a new Scene # the selected page name points to the from Scene that may need to # be cleaned up by moving enities on Layer0 to the proper Layer. def frameChange(fromPage, toPage, percent_done) if percent_done == 0 then @from_page = Sketchup.active_model.pages.selected_page.name if @run_CleanUp == true then clean_Layer0 end #Debug UI.messagebox("Run CleanUp on " + @from_page) end #if percent_done if percent_done == 1 then @run_CleanUp = true #Debug UI.messagebox("Reset @run_CleanUp = true") end #if percent_done end def clean_Layer0 #Debug UI.messagebox("Clean_Up would run") @run_CleanUp = false end #clean_Layer0 end def self.frameChange id = Sketchup;;Pages.add_frame_change_observer(FrameChangeObserver.new) # Debug UI.messagebox("Started Frame Change Observer") end unless file_loaded?(File.basename(__FILE__)) UI.menu("Tools").add_item("FrameChange"){frameChange} end end #module K²WS
Keith
-
Make a reference to a new observer outside of the code blocks, but inside the wrapping module's open-space.
[incidentally wouldn't naming it "K2WS" be more sensible ? The ² is NOT a basic character...]
Like:
FCO = FrameChangeObserver.new()
It's an enduring Constant, defined just once.
Then remove/attach it to the current model's pages:
Sketchup.active_model.pages.remove_frame_change_observer(FCO) Sketchup.active_model.pages.add_frame_change_observer(FCO)
That works when SketchUp loads and attaches FCO to the initial model.
Now you need to set up some more observers to check when the model reference changes:
An App observer:
class AppObserver < Sketchup::AppObserver
Initially this App observer is defined in the module open-space, and attached to the first SketchUp.
AO = AppObserver.new() Sketchup.remove_observer(AO) Sketchup.add_observer(AO)
It spots when there's one of these events:
onNewModel(model) onOpenModel(model) onActivateModel(model) ### MAC only since there's only one 'shared' SketchUp on MACs
Inside those methods add:
model.pages.remove_frame_change_observer(FCO) model.pages.add_frame_change_observer(FCO)
and
Sketchup.remove_observer(AO) Sketchup.add_observer(AO
This makes sure every SketchUp and every opened Model has the FCO attached and the AO too, which will add them in future SketchUps and Models during that session
-
Thanks for the reply. I will try that and report back on how that worked for me.
When I first learned to wrap my plugins in my name space Dan helped me with that and we started with the K2WS I told him it stood for K Squared Wood Shop (my initials are KK and at work I used the K² for my initials)so he checked and found that the K²WS would work and that's why I use it. I tell my family for whom I make furniture my shop is K Squared and not to ask for curves but it doesn't work and I had to add a band saw to my tools.
Keith
-
A good rule of thumb in naming is use only A-Za-z0-9 and underscores _ for all modules, classes and 'variables'.
Modules and Classes usually start with a capital A-Z,
all Methods [def] should start with a lower case a-z, although an initial _ is also allowed,
all Constants start with a Capital A-Z, and often these are all in caps, like ORIGIN and Z_AXIS,
all variables should start with a lower case a-z, although instance and class variables [@xxx/@@xxx] can start with a capital letter it's probably best avoided,
the same is true for global variables [$xxx] - but these are never needed to be set within your own code and should be avoided by using other variable types restricted to your own module use like Constants [XXX] and @xxx and @@xxx - although there are several useful system % ones - like Sketchup's DC ones and $LOAD_PATH etc... -
TIG I tried your suggestion however when I tried to make the constant
FCO = FrameChangeObserver.new()
I always get the error
Error Loading File FrameChange.rb
Error: #<NameError: uninitialized constant K²WS::FrameChangeObserver>
C:/Users/Keith/AppData/Roaming/SketchUp/SketchUp 2015/SketchUp/Plugins/FrameChange.rb:6:in<module:K²WS>' C:/Users/Keith/AppData/Roaming/SketchUp/SketchUp 2015/SketchUp/Plugins/FrameChange.rb:5:in
<top (required)>'I am obviously using it in the wrong context.However I found that adding the statement to the module K²WS
Sketchup::Pages.add_frame_change_observer(FrameChangeObserver.new)
worked. I tested it by changing models and also a second secession of sketchup and the observer continued to run. I feel that the model observer as you suggested may not be required.Thanks
Keith -
I hadn't tested the idea.
But aren't page-change-observers added to a model.pages rather than Sketchup.pages ?
If you open a new SKP is that observer still there and working ?
If so, your version works ! -
@tig said:
But aren't page-change-observers added to a model.pages rather than Sketchup.pages ?
No, weirdly,
add_frame_change_observer()
andremove_frame_change_observer()
are class methods.@tig said:
If you open a new SKP is that observer still there and working ?
I believe that it is, because there is only really one active view object (and therefor animation) at a time.
It was a very weird way to expose it, no doubt. But it'll likely remain this way.
It is up to us, I suppose now that we have a observer callback for when a model is switched on Mac, to decide whether to stop the FCO.Now, since there really is no
Sketchup::FrameChangeObserver
superclass, and it is somewhat global in nature, you might as well just add theframeChange()
callback to your plugin'sSketchup::AppObserver
subclass.Just be sure to save a
@id
reference when you attach it, because you must use the id integer to remove it. Thereafter, re-attaching will likely use a different id integer. (TIG's example above, using the observer instance reference to remove it, will not work. The remove method wants an integer id.) -
Example: appspy_w_fco.rb
# encoding; UTF-8 module Author module PluginName class AppSpy < Sketchup;;AppObserver @@attached = false unless defined?(@@attached) def self.attached?() @@attached ? true ; false end def attach() detach() if @@attached Sketchup;;add_observer(self) end def detach() Sketchup;;remove_observer(self) @@attached = false end def initialize() @fco = nil @watched = [] @@attached = attach() return self end def expectsStartupModelNotifications return true end def frameChange(fromPage, toPage, percent_done) # Actual code here. end def ignore_frames() if @fco Sketchup;;Pages;;remove_frame_change_observer(@fco) @fco = nil end @watched.keep_if {|model| model.valid? rescue false } end def ignore_model(model) @watched.delete(model) ignore_frames() if model == Sketchup.active_model end def watch_frames(model) ignore_frames() if @fco @fco = Sketchup;;Pages;;add_frame_change_observer(self) @watched << model unless @watched.include?(model) end def watching?(model) @watched.include?(model) end # AppObserver Callbacks here can call the above methods. def onActivateModel(model) # Mac only if watching?(model) watch_frames(model) else ignore_frames() end end def onNewModel(model) watch_frames(model) end def onOpenModel(model) watch_frames(model) end def onQuit() ignore_frames() end def onUnloadExtension(extension_name) ignore_frames() end end # AppSpy PluginSpy = AppSpy;;new unless AppSpy.attached? end # extension module end # toplevel module
Advertisement