How to show dialog at the beginning of the process and handle errors inside UI.start_timer?

I want a simple window to pop up at the beginning of a heavy process. However, the window is not loading properly because the HTML part is delayed by the Ruby script and is only rendered after the job is done. To work around this, I placed the heavy process inside UI.start_timer(0.3, false) {heavy_process} to give the HTML some time to load. It works but, the heavy process contains some raise and rescue bits that when triggered conflict with UI.start_timer. Once an error is raised and rescued, the script doesn’t stop but is instead raised and rescued repeatedly. In this case, a UI.messagebox from the rescue block pops up over and over again.

Do you have any ideas how to make the process wait for the dialog to load, or how to make raise and rescue work with UI.start_timer?

    def self.run_constructor

      UI.start_timer(0.3, false) {

        some process....

      rescue ComponentOutOfBoundsError
        UI.messagebox("no luck")

This is a known problem, See the following code and the explanation in the link below.

def self.run_constructor
  # This must be outside of the timer Proc
  first_invocation = true
  UI.start_timer(0.3, false) {
      x = 1/0 # raise an error

      if first_invocation 
        first_invocation = false      
        UI.messagebox("no luck")

      p "Close"  


We do this all the time without using timer blocks.

At the bottom of the dialog’s Javascript …

// Tasks to be performed after the document has loaded:
function tasksPostLoad(event) {

    // No longer need this event listener:

    // Tell the SketchUp Ruby-side the document has loaded:

    // other post load task ...


// Attach master document DOMContentLoaded event listener:

The Ruby-side dialog code needs to attach an action callback that reponds to the call from the JS DOMContentLoaded event handler function.

In the following snippet, (taken from an example I am writing to show font size control like in normal browsers,) … I have named it "dialog_ready", but it can be whatever name you desire, as long as the name used in the call upon the sketchup JS object and the name assigned in the Ruby #add_action_callback method call match.

So, this snippet defines three action callbacks:

    def add_callbacks
      unless @dialog
        puts 'Dialog object not instantiated.'
      # Do initial tasks after dialog has loaded, like setting font size.
      # Also, tells the dialog what platform SketchUp is running upon.
      @dialog.add_action_callback('dialog_ready') {
        puts 'In callback: "dialog_ready"' if @debug
        # Restore the font size from the previous use as set by user:
        font_size = format('%.3f',@font_size)
        # Set the dialog's JS var `WINDOWS` as appropriate for platform:
        val = (Sketchup.platform == :platform_win rescue RUBY_PLATFORM !~ /darwin/)
        puts "  Platform WINDOWS is: #{val}" if @debug
        @dialog.execute_script(%[WINDOWS = #{val};])
        # Let the dialog know the current sort_by key:
        @dialog.execute_script(%[sort_by = "#{@sort_by.to_s}";])
      # Callback to save the font size as it is changed by the user:
      @dialog.add_action_callback('save_font_size') { |_action_context, fontsize|
      # Callback to resort the shortcuts table data when the user clicks
      # upon one of the column headings in the dialog document:
      @dialog.add_action_callback('resort_shortcuts') { |_action_context, sort_by|
        puts 'In callback: "resort_shortcuts"' if @debug
        # Resort the shortcuts listing and send back to the dialog:
        resort_shortcuts(sort_by) if sort_by

The Ruby-side UI::HtmlDialog callbacks should usually be wrapped up in a method so they can be reattached in case the user has closed the window. When the window is closed the callbacks are detached but the Ruby dialog object is still valid.
If your code is going to reshow the dialog window (say if a toolbar button is clicked,) then the callbacks need to be reattached. This is most easily done by calling the method that wraps up the callback definitions.


Thank you very much for the answer. I have made a changes based on your suggestion but the problem persists. That is, the dialog appears but the text inside the <p> tag is not rendered until the run_constructor function is finished. Do you have any idea why that might be?

    def self.show_progress_dialog
      dialog_width = 200
      dialog_height = 150

      viewport = Sketchup.active_model.active_view.vpwidth, Sketchup.active_model.active_view.vpheight
      left = (viewport[0] - dialog_width) / 2
      top = (viewport[1] - dialog_height) / 2

      @progress_dialog =
          :dialog_title => "ElipseGrade",
          :preferences_key => "com.sample.plusdsadagin",
          :scrollable => false,
          :resizable => false,
          :width => dialog_width,
          :height => dialog_height,
          :left => left,
          :top => top,
          :style => UI::HtmlDialog::STYLE_DIALOG

        <!DOCTYPE html>
            body {
              background-color: #F3F3F3;
              font-family: Arial, sans-serif;
            p {
              text-align: center;
              padding-top: 10px;
              font-size: 0.9em;
          <p>Processing...<br><br>Please wait</p>
        function dialog_ready() {
          document.removeEventListener("DOMContentLoaded", dialog_ready);
        document.addEventListener("DOMContentLoaded", dialog_ready);

      @progress_dialog.add_action_callback("progress_dialog_ready") do |action_context|
        puts "Dialog ready"


The callback code needs a timer for your task.

See attached, if you uncomment line 38 and comment out line 39, it repros your issue.

Wrote the code for Ruby 2.2 (and later) compatibility.


00-dialog.rb (2.0 KB)

Hi Greg, Tank you very much for the answer. This is the solution I have tried initially but the problem is that the error handling inside the UI.start_timer is not working (description in the initial post) and this is the functionality that I need.

Nevermind this reply ... I solved it. ... See next post.

I have no idea what is in the run_constructor method.

Are you saying that the text: "Processing... Please wait" … is not rendering until after Constructor.run_constructor method returns ?

If so, then you might change from listening for DOMContentLoaded to the load event on the window object. This event is supposed to not fire until the page is totally loaded.

UPDATE: No change using window onload event

REF: Window: load event - Web APIs | MDN (


        function dialog_ready() {
          window.removeEventListener("load", dialog_ready);
        window.addEventListener("load", dialog_ready);

SOLVED it without a timer !

The key / trick is to use a dummy JS callback object and then
the sketchup.progress_dialog_ready callback does not block.

ie … I just used a statement writing a console message:

Notice also that I sent an unused empty string parameter to the Ruby callback. In some older versions the callbacks would not fire unless at least one parameter was sent to Ruby.

  const dialog_ready = () => sketchup.progress_dialog_ready("",
      onCompleted: function() {
        console.log('Ruby callback "progress_dialog_ready" has returned.');
  window.addEventListener("load", dialog_ready);

I used Greg’s example to test, and added in a percent_done() method to draw a graphic progress indicator.


ProgressBar_dialog_fixed.rb (3.7 KB)