SelectionObserver - multiple instances

Hi all,

I started learning programming Sketchup API. I implemented SelectionObserver

class MySelectionObserver < Sketchup::SelectionObserver
  def onSelectionBulkChange(selection)
    puts "onSelectionBulkChange: #{selection.at(0).definition.name}"
  end
end

# Attach the observer.
Sketchup.active_model.selection.add_observer(MyEntityObserver.new)

The problem is that with each execution of the code another instance of the observer is created which result in the following behavior:

onSelectionChange: test_component
onSelectionChange: test_component
onSelectionChange: test_component
onSelectionChange: test_component
onSelectionChange: test_component

What is the problem here? Is it necessary to remove the observer from the selection?

Thanks.

(1) ALL of your code needs to be within a top level namespace module that is unique. (Your company name, an online nickname, etc.) Then, each of your extensions should be separated into a submodule of your namespace module.

(2) SketchUp extension programming is event driven. This means that you do not execute the code on demand. Instead an event causes the code to run under certain conditions.
Normally observers are defined once and attached once. (Most need not be detached as the API will do it automatically if the “watched” object is destroyed, such as the model being closed.)

In your example case (above) the attachment of the Selection observer object should happen once upon the situation when a model is opened or newly created. This is done using a Sketchup::AppObserver object which can be your extension submodule itself. (Ie, observers do not need to be class instances even though all the examples show there implementation this way. An observer need only be an object that has publicly accessible observer callback methods.)

# encoding: UTF-8
#
# File: Miskohut_TestExtension_main.rb
#
# <<Extension file description.>>

# TOPLEVEL NAMESPACE MODULE
module Miskohut

  # EXTENSION SUBMODULE
  # <<Extension description.>>
  # This extension submodule will also be an application observer.
  module TestExtension

    # Extend this submodule with itself so all the methods
    # are publicly accessible (and internally without qualification):
    extend self

    ### EXTENSION SPECIFIC CLASSSES
    #

    class SelectionSpy < Sketchup::SelectionObserver
      def onSelectionBulkChange(selection)
        obj = selection.at(0)
        if obj.respond_to?(:definition)
          puts "onSelectionBulkChange: #{obj.definition.name}"
        elsif obj.respond_to?(:name)
          puts "onSelectionBulkChange: #{obj.name}"
        elsif obj.respond_to?(:typename)
          puts "onSelectionBulkChange: #{obj.typename}"
        else
          puts "onSelectionBulkChange: #{obj.class.name}"
        end
      end
    end

    ### EXTENSION LEVEL METHODS
    #

    # This method is where all observers would be attached to
    # a model object or model level collection objects.
    def attach_model_spies(model)
      # Attach the selection observer:
      model.selection.add_observer(SelectionSpy.new)
      #
      # Here is where one might attach other observers at the model level.
      #
    end


    ### AppObserver callback methods:
    #
      def expectsStartupModelNotifications
        return true
      end

      def onNewModel(model)
        attach_model_spies(model)
      end

      def onOpenModel(model)
        attach_model_spies(model)
      end
    #
    ###

    # RUN THIS BLOCK ONCE UPON FIRST LOAD:
    unless defined?(@loaded)

      # Attach this submodule as the AppObserver object:
      Sketchup.add_observer(self)

      @loaded = true
    end

  end # extension submodule
end # toplevel namespace module

Scroll to view entire file.


Also read about the SketchupExtension class and how an extension’s files are organized inside the “Plugins” folder …