Creating GUI in Sketchup, could I gtk file or is there another option in sketchup built in?

Is there a good choice to make tables in sketchup GUI?

I searched online and they are saying that TreeView would be a good choice. but how to import them in sketchup? I always have trouble trying to import file in sketchup plugin RubyCodeEditor. I’m not sure which directory should I use to save my imported file.

I installed gtk using gem install gtk3 and it is stored in a gem package. However, I installed CSV using gem install csv, it could be imported and works well in sketchup rubyCodeEditor. Quite confused now.

I tested a example GUI code in RubyMine Intellij, and it doesn’t work in rubycodeEditor.


require 'gtk3'

class RubyApp < Gtk::Window

  def initialize
    super

    set_title "Center"
    signal_connect "destroy" do
      Gtk.main_quit
    end

    set_default_size 300, 200

    set_window_position Gtk::WindowPosition

    show
  end
end

window = RubyApp.new
Gtk.main


This is what ruby console returns:

"Nil result (no result returned or run failed)"
Error: #<LoadError: cannot load such file -- gtk3>
C:/Program Files/SketchUp/SketchUp 2019/Tools/RubyStdLib/rubygems/core_ext/kernel_require.rb:59:in `require'
C:/Program Files/SketchUp/SketchUp 2019/Tools/RubyStdLib/rubygems/core_ext/kernel_require.rb:59:in `require'
<main>:in `<main>'
C:/Users/cyg/AppData/Roaming/SketchUp/SketchUp 2019/SketchUp/Plugins/as_rubyeditor/as_rubyeditor.rb:324:in `eval'
C:/Users/cyg/AppData/Roaming/SketchUp/SketchUp 2019/SketchUp/Plugins/as_rubyeditor/as_rubyeditor.rb:324:in `block in initialize'
~

I also tried the following path, but it doesn’t work, not sure what is wrong.

C:/Users/cyg/.gem/specs/api.rubygems.org%443/quick/Marshal.4.8

try this and then adapt to your needs…

# the top bit is just for example content, I think it was posted by @Aerilius 
exceptions = []
tree = {}
ObjectSpace.each_object(Class) do |cls|
  next unless cls.ancestors.include? Exception
  next if exceptions.include? cls
  next if cls.superclass == SystemCallError # avoid dumping Errno's
  exceptions << cls
  cls.ancestors.delete_if {|e| [Object, Kernel].include? e }.reverse.inject(tree) {|memo,cls| memo[cls] ||= {}}
end
# I added the formatting
formated = ''
indent = 0
tree_printer = Proc.new do |t|
  t.keys.sort { |c1,c2| c1.name <=> c2.name }.each do |k|
   # and some html formatting
    space = ('&nbsp;' * indent); space ||= ''
    formated << "<ul>#{space}#{k.to_s}</ul>"
    indent += 2; tree_printer.call t[k]; indent -= 2
  end
end
tree_printer.call tree
# use a standard dialog
dialog = UI::HtmlDialog.new(
{
  :dialog_title => "Tree in Dialog",
  :preferences_key => "tree.sample.ruby",
  :scrollable => true,
  :resizable => true,
  :width => 600,
  :height => 1000,
  :left => 100,
  :top => 100,
  :min_width => 50,
  :min_height => 50,
  :max_width =>1000,
  :max_height => 1000,
  :style => UI::HtmlDialog::STYLE_DIALOG
})
# inject some styling
script = '<script>document.body.style="font:80% sans-serif; line-height:.4em;"</script>'
dialog.set_html(formated << script)
dialog.show

john

Did you try just importing the gems (require without a complete program code)? If csv can be imported and gtk3 not, check whether they are installed in the same Ruby installation (SketchUp’s Ruby, not system-wide Ruby installation).

This starts the “main loop” of an interactive program (graphical user interface). A normal function would do its processing and return (exit if it is a standalone program, or return control to the caller, here that is SketchUp). A main loop is an infinitely running function so that the user interface stays open.

It is blocking, so it does not return control to SketchUp. It will basically freeze SketchUp’s own main loop. The way to avoid that is either

  • to use separate threads (which don’t work in SketchUp)
  • or a separate process (write your GUI as a separate program and start it in a separate process)
  • or to use those GUI functionalities which are provided and supported by the SketchUp API

I don’t understand how sketchup ruby do when using require.
As When I use require_relative ‘file’ in RubyMine Intellij, the file under the same environment could be found, however, it could not be found in sketchup rubyEditor plugin.

puts "test_library included"
class TestClass
  def initialize
    puts "TestClass object created"
  end
end

I created this two simple rb file to test it.

#!/usr/bin/env ruby
require_relative 'test_library.rb'
t = TestClass.new

it could be executed in RubyMine and could not be executed in sketchup rubyEditor:

"Nil result (no result returned or run failed)"
Error: #<LoadError: cannot infer basepath>
<main>:1:in `require_relative'
<main>:1:in `<main>'
C:/Users/cyg/AppData/Roaming/SketchUp/SketchUp 2019/SketchUp/Plugins/as_rubyeditor/as_rubyeditor.rb:324:in `eval'
C:/Users/cyg/AppData/Roaming/SketchUp/SketchUp 2019/SketchUp/Plugins/as_rubyeditor/as_rubyeditor.rb:324:in `block in initialize'

your shebang

is not relative to SU ruby used by as_rubyeditor nor to as_rubyeditor.rb itself…

to require_relative it would need to be in the same folder as the __callee__ file…
to require it would need to be in the same folder as the SU ruby or __callee__ file…

BTW: @Aerilius has his own ‘RubyConsole+’ extension with more functionality then ae’s one…

john

Thank you john, I am trying to understand how to custumize it, but is it possible to change value on the interface? I mean it could definitely display values, but is it possible to insert a inputbox?

you keep throwing up ‘red herrings’ …

UI.messagebox can do a lot…

UI::HtmlDialog can be used to create anything gtk3 can create…

you can even use vanilla js or js libraries for widgets…

it would be a lot easier if you clarified your objectives in simple terms and ask how to achieve each step using the API if you can’t figure it out…

e.g.

  1. create an input dialog with prompts from a default list

  2. create a group based on users reply

  3. store the replies as user ‘defaults’

rarely, there may be a need for adding gems and they will only work if compiling is not needed…

john

Which you can find and try here: https://extensions.sketchup.com/en/content/ruby-console

1 Like

May I ask in the code you shared.

tree_printer = Proc.new do |t|
  t.keys.sort { |c1,c2| c1.name <=> c2.name }.each do |k|
   # and some html formatting
    space = ('&nbsp;' * indent); space ||= ''
    formated << "<ul>#{space}#{k.to_s}</ul>"
    indent += 2; tree_printer.call t[k]; indent -= 2
  end
end

is this the part to insert entities I might need? But how to draw a table using the HTMLDialog?

I don’t know what entities you need, but that code will create a ‘tree’ view not a table…

if you want a ‘table’ view you need a html table, which you can create in ruby using model derive data…

heres a simple table that has model material information displayed…

run it on a model with material to see results…

model = Sketchup.active_model
mats  = model.materials
html  = %Q[
<!DOCTYPE html>
<html>
<head>
<style>
body { font: 100% sans-serif; }
table, th, td { border: 1px solid black; }
</style>
</head>
<body>

<h3><span style="color:red;">S</span>ketch<span style="color:red;">U</span>p Colors in Model:</h2>

<table>
  <tr>
    <th>File Name</th>
    <th>Display Name</th>
  </tr>
 ]

mats.each do |mat| 
  next if mat.name.length < 2
  html << %Q[
     <tr>
      <td>#{mat.name.gsub(/[<>]/, '')}</td>
      <td>#{mat.display_name.gsub(/[<>]/, '')}</td>
    </tr>
   ]
end

html << %Q[
</table>
</body>
</html>
]
# use a standard dialog
dialog = UI::HtmlDialog.new(
{
  :dialog_title => "Table in Dialog",
  :preferences_key => "table.sample.ruby",
  :scrollable => true,
  :resizable => true,
  :width => 600,
  :height => 500,
  :left => 100,
  :top => 100,
  :min_width => 50,
  :min_height => 50,
  :max_width =>1000,
  :max_height => 1000,
  :style => UI::HtmlDialog::STYLE_DIALOG
})
# inject some styling
dialog.set_html(html)
dialog.show

I hate tables so I use css3 grid layout instead, but you can do almost anything…

the gif shows me copy pasting the gsub onto the display name ruby…

john

1 Like

thank you john. it seems it just need to tell sketchup to make a html and it will be fine.

I copied a code on the website to learn how they create a editable table. Going to sleep now… carry on the work tomorrow…

model = Sketchup.active_model
mats  = model.materials

html1 =%Q[
<!-- Editable table -->
<div class="card">
  <h3 class="card-header text-center font-weight-bold text-uppercase py-4">Editable table</h3>
  <div class="card-body">
    <div id="table" class="table-editable">
      <span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success"><i
            class="fas fa-plus fa-2x" aria-hidden="true"></i></a></span>
      <table class="table table-bordered table-responsive-md table-striped text-center">
        <thead>
          <tr>
            <th class="text-center">Person Name</th>
            <th class="text-center">Age</th>
            <th class="text-center">Company Name</th>
            <th class="text-center">Country</th>
            <th class="text-center">City</th>
            <th class="text-center">Sort</th>
            <th class="text-center">Remove</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td class="pt-3-half" contenteditable="true">Aurelia Vega</td>
            <td class="pt-3-half" contenteditable="true">30</td>
            <td class="pt-3-half" contenteditable="true">Deepends</td>
            <td class="pt-3-half" contenteditable="true">Spain</td>
            <td class="pt-3-half" contenteditable="true">Madrid</td>
            <td class="pt-3-half">
              <span class="table-up"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-up"
                    aria-hidden="true"></i></a></span>
              <span class="table-down"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-down"
                    aria-hidden="true"></i></a></span>
            </td>
            <td>
              <span class="table-remove"><button type="button"
                  class="btn btn-danger btn-rounded btn-sm my-0">Remove</button></span>
            </td>
          </tr>
          <!-- This is our clonable table line -->
          <tr>
            <td class="pt-3-half" contenteditable="true">Guerra Cortez</td>
            <td class="pt-3-half" contenteditable="true">45</td>
            <td class="pt-3-half" contenteditable="true">Insectus</td>
            <td class="pt-3-half" contenteditable="true">USA</td>
            <td class="pt-3-half" contenteditable="true">San Francisco</td>
            <td class="pt-3-half">
              <span class="table-up"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-up"
                    aria-hidden="true"></i></a></span>
              <span class="table-down"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-down"
                    aria-hidden="true"></i></a></span>
            </td>
            <td>
              <span class="table-remove"><button type="button"
                  class="btn btn-danger btn-rounded btn-sm my-0">Remove</button></span>
            </td>
          </tr>
          <!-- This is our clonable table line -->
          <tr>
            <td class="pt-3-half" contenteditable="true">Guadalupe House</td>
            <td class="pt-3-half" contenteditable="true">26</td>
            <td class="pt-3-half" contenteditable="true">Isotronic</td>
            <td class="pt-3-half" contenteditable="true">Germany</td>
            <td class="pt-3-half" contenteditable="true">Frankfurt am Main</td>
            <td class="pt-3-half">
              <span class="table-up"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-up"
                    aria-hidden="true"></i></a></span>
              <span class="table-down"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-down"
                    aria-hidden="true"></i></a></span>
            </td>
            <td>
              <span class="table-remove"><button type="button"
                  class="btn btn-danger btn-rounded btn-sm my-0">Remove</button></span>
            </td>
          </tr>
          <!-- This is our clonable table line -->
          <tr class="hide">
            <td class="pt-3-half" contenteditable="true">Elisa Gallagher</td>
            <td class="pt-3-half" contenteditable="true">31</td>
            <td class="pt-3-half" contenteditable="true">Portica</td>
            <td class="pt-3-half" contenteditable="true">United Kingdom</td>
            <td class="pt-3-half" contenteditable="true">London</td>
            <td class="pt-3-half">
              <span class="table-up"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-up"
                    aria-hidden="true"></i></a></span>
              <span class="table-down"><a href="#!" class="indigo-text"><i class="fas fa-long-arrow-alt-down"
                    aria-hidden="true"></i></a></span>
            </td>
            <td>
              <span class="table-remove"><button type="button"
                  class="btn btn-danger btn-rounded btn-sm my-0">Remove</button></span>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</div>
<!-- Editable table -->
 ]
html  = %Q[
<!DOCTYPE html>
<html>
<head>
<style>
body { font: 100% sans-serif; }
table, th, td { border: 1px solid black; }
</style>
</head>
<body>

<h3><span style="color:red;">S</span>ketch<span style="color:red;">U</span>p Colors in Model:</h2>

<table>
  <tr>
    <th>File Name</th>
    <th>Display Name</th>
  </tr>
 ]

mats.each do |mat| 
  next if mat.name.length < 2
  html << %Q[
     <tr>
      <td>#{mat.name.gsub(/[<>]/, '')}</td>
      <td>#{mat.display_name.gsub(/[<>]/, '')}</td>
    </tr>
   ]
end

html << %Q[
</table>
</body>
</html>
]
# use a standard dialog
dialog = UI::HtmlDialog.new(
{
  :dialog_title => "Table in Dialog",
  :preferences_key => "table.sample.ruby",
  :scrollable => true,
  :resizable => true,
  :width => 600,
  :height => 500,
  :left => 100,
  :top => 100,
  :min_width => 50,
  :min_height => 50,
  :max_width =>1000,
  :max_height => 1000,
  :style => UI::HtmlDialog::STYLE_DIALOG
})
# inject some styling
dialog.set_html(html1)
dialog.show

The CSV class is included in the Ruby Standard library that comes with SketchUp since v2014.
You do not need to install it from a gem.

require "csv"

CSV.foreach("path/to/file.csv") do |row|
  # use row here...
end

For this reason, GTK is not compatible for use (as is) in an embedded Ruby process.

Also, last I looked, GTK3 was not yet “ready for primetime” on MS Windows. (There was still work that needed to be done. I played with it after dealing with numerous issues getting the correct version of dependency libraries, and still had lock up and crash issues even within a system Ruby process.)

So John’s advice …

… is the best for the OP’s needs.

1 Like

Thanks for the tip Dan.

I tried the whole day yesterday and could not set it up to work onSketchup…
I’m now trying to set up my Html file.

Hi, John. in the html you provided below. I believe this code is to replace each object by an mat object using <<, is there some function to save file from the html table? I searched for editable tables online and got a code like the second code attached below. there are also a button as well.

mat.each do |arrays|
  html << %Q[
     <tr>
      <td>#{mat.name.gsub(/[<>]/, '')}</td>
      <td>#{mat.display_name.gsub(/[<>]/, '')}</td>
    </tr>
   ]
  puts "#{arrays}"
end

Code 2:

model = Sketchup.active_model
mat  = model.materials
a = [
["London Eye", "1952", "3000"],
["Paris", "1952", "3000"],
["California", "1952", "3000"]
]
html1 =%Q[
<!-- Editable table -->
<div class="card">
  <h3 class="card-header text-center font-weight-bold text-uppercase py-4">Editable table</h3>
  <div class="card-body">
    <div id="table" class="table-editable">
      <span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success"><i
            class="fas fa-plus fa-2x" aria-hidden="true"></i></a></span>
      <table class="table table-bordered table-responsive-md table-striped text-center">
        <thead>
          <tr><!-- "first table"-->
            <th class="text-center">Building Name</th>
            <th class="text-center">Built Year</th>
            <th class="text-center">Torned Down Year</th>
          </tr><!-- "first table"-->
        </thead>
        <tbody>
          <tr>
            <td class="pt-3-half" contenteditable="true">Aurelia Vega</td>
            <td class="pt-3-half" contenteditable="true">1951</td>
            <td class="pt-3-half" contenteditable="true">1999</td>
          </tr>
          <!-- This is our clonable table line -->
          <tr>
            <td class="pt-3-half" contenteditable="true">Guerra Cortez</td>
            <td class="pt-3-half" contenteditable="true">45</td>
            <td class="pt-3-half" contenteditable="true">Insectus</td>
            </td>
          </tr>
          <!-- This is our clonable table line -->
          <tr>
            <td class="pt-3-half" contenteditable="true">Guadalupe House</td>
            <td class="pt-3-half" contenteditable="true">26</td>
            <td class="pt-3-half" contenteditable="true">Isotronic</td>
            </td>
          </tr>
          <!-- This is our clonable table line -->
          <tr class="hide">
            <td class="pt-3-half" contenteditable="true">Elisa Gallagher</td>
            <td class="pt-3-half" contenteditable="true">31</td>
            <td class="pt-3-half" contenteditable="true">Portica</td>
            </td>
          </tr>
          </form>
        </tbody>
      </table>
    </div>
      <button id="export-btn" class="btn btn-primary">Export Data</button>
      <p id="export"></p>
  </div>
</div>
<!-- Editable table -->
 ]
html  = %Q[
<!DOCTYPE html>
<html>
<head>
<style>
body { font: 100% sans-serif; }
table, th, td { border: 1px solid black; }
</style>
</head>
<body>

<h3><span style="color:red;">S</span>ketch<span style="color:red;">U</span>p Colors in Model:</h2>

<table>
  <tr>
    <th>File Name</th>
    <th>Display Name</th>
  </tr>
 ]
 


a.each do |arrays|
  html << %Q[
     <tr>
      <td>#{mat.name.gsub(/[<>]/, '')}</td>
      <td>#{mat.display_name.gsub(/[<>]/, '')}</td>
    </tr>
   ]
  puts "#{arrays}"
end

html << %Q[
</table>
</body>
</html>
]
# use a standard dialog
dialog = UI::HtmlDialog.new(
{
  :dialog_title => "Table in Dialog",
  :preferences_key => "table.sample.ruby",
  :scrollable => true,
  :resizable => true,
  :width => 600,
  :height => 500,
  :left => 100,
  :top => 100,
  :min_width => 50,
  :min_height => 50,
  :max_width =>1000,
  :max_height => 1000,
  :style => UI::HtmlDialog::STYLE_DIALOG
})
# inject some styling
dialog.set_html(html1)
dialog.show

look up javascript onClick="" event…

also SU add_action_callback

combining the two allows you to receive data from the web dialog…

you need to step back and try to learn the basics…

html = %Q[
<!DOCTYPE html>
<html>
<body>

<h1>The onclick Event</h1>

<p>The onclick event is used to trigger a function when an element is clicked on.</p>

<p>Click the button to trigger a function that will output "Hello World" in a p element with id="demo".</p>

<button onclick="myFunction()">Click me</button>

<p id="demo"></p>

<script>
function myFunction() {
  sketchup.js2ruby('hi from javascript');
}
</script>

</body>
</html>
]

# use a standard dialog
dialog = UI::HtmlDialog.new(
{
  :dialog_title => "Table in Dialog",
  :preferences_key => "table.sample.ruby",
  :scrollable => true,
  :resizable => true,
  :width => 600,
  :height => 500,
  :left => 100,
  :top => 100,
  :min_width => 50,
  :min_height => 50,
  :max_width =>1000,
  :max_height => 1000,
  :style => UI::HtmlDialog::STYLE_DIALOG
})
dialog.set_html(html)
dialog.add_action_callback("js2ruby") {|_, value|
	UI.messagebox(value)
}
dialog.show
1 Like