Ruby 搭配 Sketchup 學習筆記(六)
前情提要
Sketchup 是一款在建築、都市計畫和遊戲開發都頗有名氣的 3D 建模軟體,而 Ruby 則是一個程式語言,它可以搭配 Sketchup 達成程式化 建模的任務,近期經由系主任引薦,要開發 Sketchup 的 Extension,雖然我寫過 Ruby,但 Sketchup 則是完全沒碰過,於是利用文章來記錄所學的一點一滴。
本篇內容
- 對話方塊
- 功能表
- 命令
- 工具列
- WebDialogs
對話方塊
對話方塊在之前的範例中用作於呈現資訊,但其實它還可以與使用者進行互動。以下是基本的用法:
UI.messagebox "測試訊息"
輸出結果:
UI.messagebox
的參數除了接受一個 String 之外,還可以傳入第二個參數決定按鈕形式,以下介紹幾種參數:
- MB_OK:有一個「確定」按鈕
- MB_OKCANCEL:有「確定」和「取消」按鈕
- MB_RETRYCANCEL:有「重試」和「取消」按鈕
- MB_ABORTRETRYCANCEL:有「放棄」、「重試」和「取消」按鈕
- MB_YESNO:有「是」和「否」按鈕
- MB_YESNOCANCEL:有「是」、「否」和「取消」按鈕
- MB_MULTILINE:顯示多列文字的訊息方塊,有第三個參數,代表訊息方塊的標題
各事件回傳的值皆不同:
- 「確定」:1
- 「取消」:2
- 「重試」:4
- 「放棄」:3
- 「是」:6
- 「否」:7
使用範例:
case UI.messagebox "測試訊息",MB_OKCANCEL when 1 puts "你按下確定" when 2 puts "你按下取消" end
還有一種對話方塊可以讓使用者輸入資訊,以下示範 BMI 計算:
label = ["身高", "體重"] defaults = [173, 68] result = inputbox label, defaults, "輸入你的身高與體重" bmi = result[1]/((result[0]/100.0)**2) UI.messagebox "你的BMI是#{bmi}"
輸出結果:
以下示範如何使用下拉式選單:
label = ["餐點種類"] default = ["炒飯"] options = ["炒飯", "炒麵"] enums = [options.join("|")] result = inputbox label, default, enums, "今天晚上吃什麼?" UI.messagebox "今天吃#{result[0]}" if result
輸出結果:
比較麻煩的就是所有的參數都要塞 Array
功能表
功能表可以新增的位置有兩種:
- 上方工具列
- 右鍵點擊物件(快顯)
上方工具列
要新增在上方工具列,請先選擇一列,例如: File, Plugins等等,以下示範如何使用:
menu = UI.menu "Plugins" menu.add_item "按按看" do UI.messagebox "這是功能表" end submenu = menu.add_submenu "工具列" submenu.add_item "板手" do UI.messagebox "板手" end submenu.add_item "螺絲起子" do UI.messagebox "螺絲起子" end submenu.add_separator item = submenu.add_item "電動起子" do UI.messagebox "電動起子" end submenu.set_validation_proc(item){MF_DISABLED}
輸出結果:
set_validation_proc
的區塊中共有五種常數可以填入:
- MF_ENABLED
- MF_DISABLED
- MF_CHECKED
- MF_UNCHECKED
- MF_GRAYED
右鍵點擊物件(快顯)
以下示範如何使用快顯功能表:
UI.add_context_menu_handler do |menu| menu.add_item("這是快顯按鈕") do UI.messagebox("你點到啦!") end end
輸出結果:
命令
當有需要製作大量相同功能的按鈕時,可以考慮使用命令:
UI.menu("Draw").add_item("觸發命令") do UI.messagebox("從這裡開始執行我定義的程序") end cmd = UI::Command.new("測試新的命令") do UI.messagebox("開始執行") end UI.menu("Draw").add_item cmd
工具列
還記得裝完 Ruby Code Editor 後會有一個小對話框浮現嗎?那其實就是工具列。以下示範如何製作:
tool_cmd = UI::Command.new("測試工具"){UI.messagebox "這是我第一個工具"} tool_cmd.large_icon = "carton.jpeg" tool_cmd.tooltip = "這是提示" tool_toolbar = UI::Toolbar.new "我的工具列" tool_toolbar.add_item tool_cmd tool_toolbar.show
輸出結果:
WebDialogs
Sketchup Ruby Api 官方文件建議改為 HTMLDialogs。
以下示範如何建立一個 WebDialogs
wd = UI::WebDialog.new "一個 WebDialog" wd.show
在新增 WebDialog 時也可以給予其參數:
- dialog_title
- scrollable
- preferences_key:記住 WebDialog 的位置尺寸
- width
- height
- left
- top
- resizable
而產生出來的物件有以下的方法可使用:
- set_url
- set_potition
- set_size
- set_file
- max_height
- max_width
- min_height
- min_width
搭配 HTML
在 WebDialogs 之中可以放入 HTML 和 Javascript,例如以下範例先建立一個 .html 檔,之後進行引入:
新增一個 index.html
在 Sketchup 的 Plugins/mytest
資料夾之下
wd = UI::WebDialog.new "一個 WebDialog" path = Sketchup.find_support_file "index.html", "Plugins/mytest" wd.set_file path wd.show
輸出結果:
搭配 Javescript
當 Ruby 想要傳送訊息到 Javascript 時可以使用 wd.execute_script funcName(arg1,arg2)
,當 Javascript 想要傳送資料到 Ruby 時,可以在 Javascript 使用 window.loaction = "skp:callback_name@callback_data"
Ruby 傳資料給 Javascript
先建立 ex_909.rb
,程式碼如以下:
class EntObserver < Sketchup::EntityObserver def onChangeEntity(entity) f_count = 1 for v in entity.vertices args = "'#{v.position.x.to_s}','#{v.position.y.to_s}','#{v.position.z.to_s}'" $wd.execute_script "setPoint#{f_count.to_s}(#{args})" f_count += 1 end end def onEraseEntity(entity) $wd.execute_script "faceDeleted()" end end ents = Sketchup.active_model.entities face = ents.add_face [0, 0, 0], [10, 0, 0], [10, 10, 0], [0, 10, 0] cbs = EntObserver.new face.add_observer cbs $wd = UI::WebDialog.new "檢查並顯示端點位置" path = Sketchup.find_support_file "ex_910.html", "Plugins/mytest" $wd.set_file path $wd.show
再建立 ex_910.html
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> function setPoint1(c1, c2, c3) { document.getElementById("pt1").innerHTML = `` } function setPoint2(c1, c2, c3) { document.getElementById("pt2").innerHTML = `` } function setPoint3(c1, c2, c3) { document.getElementById("pt3").innerHTML = `` } function setPoint4(c1, c2, c3) { document.getElementById("pt4").innerHTML = `` } function faceDeleted() { document.getElementById("pt1").innerHTML = "圖形已被刪除" document.getElementById("pt2").innerHTML = "圖形已被刪除" document.getElementById("pt3").innerHTML = "圖形已被刪除" document.getElementById("pt4").innerHTML = "圖形已被刪除" } </script> </head> <body> <h1>第一個點:</h1> <p id="pt1">在預設位置</p> <h1>第二個點:</h1> <p id="pt2">在預設位置</p> <h1>第三個點:</h1> <p id="pt3">在預設位置</p> <h1>第四個點:</h1> <p id="pt4">在預設位置</p> </body> </html>
輸出結果:
Javascript 傳資料給 Ruby
請建立 ex_911.rb
,並複製以下內容:
wd = UI::WebDialog.new "Face 製造機" wd.set_size 600, 350 path = Sketchup.find_support_file "ex_912.html", "Plugins/mytest" wd.set_file path wd.add_action_callback("create_face") do |dialog, arg| if arg.to_s.length == 0 puts "無效的輸入" else v = arg.to_s.split(",") pt1 = [v[0].strip.to_f, v[1].strip.to_f, v[2].strip.to_f] pt2 = [v[3].strip.to_f, v[4].strip.to_f, v[5].strip.to_f] pt3 = [v[6].strip.to_f, v[7].strip.to_f, v[8].strip.to_f] pt4 = [v[9].strip.to_f, v[10].strip.to_f, v[11].strip.to_f] Sketchup.active_model.entities.add_face pt1, pt2, pt3, pt4 end end if RUBY_PLATFORM.index "darwin" wd.show_modal else wd.show end
再建立 ex_912.html
,複製以下內容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> function sendPoints() { var ids = new Array("x1", "y1", "z1", "x2", "y2", "z2", "x3", "y3", "z3", "x4", "y4", "z4"); var arg = ""; var entry = ""; var valid = true; for (i in ids) { entry = document.getElementById(ids[i]).value if (entry.length == 0 || isNaN(entry)) { valid = false; } else { arg += `${entry},` } } if (!valid) { arg = ""; } window.location = `skp:create_face@${arg}`; } </script> </head> <body> <input type="text" id="x1" value="0.0" size="10" maxlength="6"> <input type="text" id="y1" value="0.0" size="10" maxlength="6"> <input type="text" id="z1" value="0.0" size="10" maxlength="6"> <hr> <input type="text" id="x2" value="0.0" size="10" maxlength="6"> <input type="text" id="y2" value="0.0" size="10" maxlength="6"> <input type="text" id="z2" value="0.0" size="10" maxlength="6"> <hr> <input type="text" id="x3" value="0.0" size="10" maxlength="6"> <input type="text" id="y3" value="0.0" size="10" maxlength="6"> <input type="text" id="z3" value="0.0" size="10" maxlength="6"> <hr> <input type="text" id="x4" value="0.0" size="10" maxlength="6"> <input type="text" id="y4" value="0.0" size="10" maxlength="6"> <input type="text" id="z4" value="0.0" size="10" maxlength="6"> <hr> <input type="submit" onclick="sendPoints();" value="產生"> </body> </html>
輸出結果: