Could not call the variable in UI.start_timer

Hi all,

I have an issue with using UI.start_timer on Windows 10 OS (I tested the same function on Mac OS, it works well)

I have the code below:

$added_instance = nil
class TestDefinitionObserver < Sketchup::DefinitionObserver
       def onComponentInstanceAdded(definition, instance)
                $added_instance = instance
                UI.start_timer(0.1, false) {
                            $added_instance.explode!
                }
      end
end

$added_instance is undefined in the runtime. If anyone experienced with the issue and have any solution to fix it, please let me know. Thanks in advanced.

Not yet experienced, but with observers you should be careful. As you should never assume things just from common experience, you should never assume things in SketchUp observers.

  • Add a check that the given instance is not nil, and valid (not a deleted entity):
    if instance && instance.valid?
    This is necessary because observers can be triggered when entities are already deleted. Try copy-pasting a component instance and instead of placing it, you press Esc.
  • Also add a begin/rescue clause so that you will know about if an exception happens (exceptions in event handlers like observers or dialog callbacks do not print to the console).

Also you should not use the global variable and there is never a need for passing data with global variables (I think you added it for debugging). If you need it, you could give the observer a reference to the class that needs the collected instances, and notify it:

class TestDefinitionObserver < Sketchup::DefinitionObserver
  def initialize(my_extension)
    # Initialize with a reference to a class to notify
    @my_extension = my_extension
  end
  def onComponentInstanceAdded(definition, instance)
    begin
      if instance && instance.valid?
        # Notify the related class and pass the instance over to it.
        @my_extension.instance_added(instance)
      end
    rescue Exception => e
      puts(e.message)
      puts(e.backtrace.join($/))
    end
  end
end

# Example code using messaging between observer and extension classes.
class MyExtension
  def initialize
    @instances = []
  end
  def run
    model = Sketchup.active_model
    definition = model.definitions.add("My Definition")
    definition.entities.add_edges(ORIGIN, ORIGIN+X_AXIS)
    # Pass a reference to the class that should be notified (this class, self)
    instance_added_observer = TestDefinitionObserver.new(self)
    definition.add_observer(instance_added_observer)
    # Simulate the user doing this:
    instance = model.entities.add_instance(definition, IDENTITY)
  end
  def instance_added(instance)
    @instances << instance
    puts(@instances)
  end
end

MyExtension.new.run
2 Likes

I second what Aerulius said. And in addition I see this exercise as problematic.
The OP is interrupting the instance creation process with an observer that destroys that very instance.

  1. There may be other observers in the queue that have not yet been called and expect a valid instance.
  2. The exploding can cause new component instances (that were previously nested) to trigger another observer calling loop before the current one is done.

Hence the OP’s attempt at using a timer to delay the explode.
This does not seem to me to be a very good coding pattern.