sketchucation logo sketchucation
    • Login
    🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    How to run a frame change observer

    Scheduled Pinned Locked Moved Developers' Forum
    8 Posts 3 Posters 938 Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • K Offline
      ktkoh
      last edited by

      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

      1 Reply Last reply Reply Quote 0
      • TIGT Offline
        TIG Moderator
        last edited by

        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

        TIG

        1 Reply Last reply Reply Quote 0
        • K Offline
          ktkoh
          last edited by

          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

          1 Reply Last reply Reply Quote 0
          • TIGT Offline
            TIG Moderator
            last edited by

            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

            1 Reply Last reply Reply Quote 0
            • K Offline
              ktkoh
              last edited by

              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

              1 Reply Last reply Reply Quote 0
              • TIGT Offline
                TIG Moderator
                last edited by

                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

                1 Reply Last reply Reply Quote 0
                • Dan RathbunD Offline
                  Dan Rathbun
                  last edited by

                  @tig said:

                  But aren't page-change-observers added to a model.pages rather than Sketchup.pages ?

                  No, weirdly, add_frame_change_observer() and remove_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 the frameChange() callback to your plugin's Sketchup::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.)

                  I'm not here much anymore.

                  1 Reply Last reply Reply Quote 0
                  • Dan RathbunD Offline
                    Dan Rathbun
                    last edited by

                    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
                     
                    

                    I'm not here much anymore.

                    1 Reply Last reply Reply Quote 0
                    • 1 / 1
                    • First post
                      Last post
                    Buy SketchPlus
                    Buy SUbD
                    Buy WrapR
                    Buy eBook
                    Buy Modelur
                    Buy Vertex Tools
                    Buy SketchCuisine
                    Buy FormFonts

                    Advertisement