Tk 簡介
為什麼學 Tk?
Tk 是一個 GUI 函式庫, 你可以用它來為你的程式加上 圖形使用者介面 (Graphical User Interface), 讓你的程式提供選單, 按鈕, 拉棒, ... 等等方便使用者以滑鼠操作的功能。
學 GUI 函式庫並不是件最熱門最酷的事情; 而且就算已經決定要學 GUI 函式庫, 也還有很多其他更流行的函式庫, 例如 VB 或 VC++ 的 Microsoft Foundation Class, Java 的 AWT 或 Swing, ... 等等。 Tk 比起上述各種函式庫, 要稍微不方便些: 你寫的 Tk 程式, 可以讓使用者以滑鼠操作; 但是你 -- 程式設計師 -- 自己寫程式的過程, 卻必須老老實實地開一個文字檔案編輯器 (例如 nano 或 vim) 一列一列敲進去。 市面上流行的其他函式庫, 則多數都有更簡單的介面, 方便程式設計師用拉選單的方式畫出圖形介面。
那麼為什麼要學 Tk 呢? 如果你在乎的是短暫的方便, 是眼前的流行, 或許並不適合學 Tk; 但如果你在乎的是長遠的學習投資, Tk 就非常值得考慮。
- 它可以與眾多語言配合使用, 例如 tcl, perl, ruby, python, guile, java, c, c++, ...
- 上述語言, 都有跨作業平臺的版本, 只要選對編譯器, 你寫的程式不論在 MS Windows, Mac, Linux, *BSD, ... 任何作業平臺下, 都可以執行。
- 自己用手寫的程式, 比較容易理解/維護/撿片斷作他用。
- 就像製作 html 一樣, 學語法比背選單麻煩, 但也更能夠長久保值, 不因為軟體退流行而失去價值。
- Tk 是 自由軟體, 不會因為廠商停止支援而失去活力。
程式語言與作業系統的市場是多變的, 今天最流行的語言或 OS, 十年後可能已成為歷史。 如果你希望未來二者不論如何更迭興衰, 現在所學的東在西廿年之後仍舊還能有一些用處; 如果你希望花很多時間所學的東西, 可以和最多不同的軟體元件溝通, 發揮相乘的效果, 那麼 Tk 就非常值得考慮。
與 Tk 一樣具有活用組合特性的類似 GUI 函式庫其實還有很多, 例如 wxWidgets, gtk+, qt, ... 等等, 都是自由軟體, 也因此理論上都可以跨作業平臺並與多種語言搭配。 可是網路上似乎找不到較完整客觀的比較文章。 筆者選擇 Tk, 主要原因還是個人經驗與偏好, 同時也因為個人最拿手的是 perl, 而目前與 perl 搭配較好的 GUI 函式庫似乎是 Tk。
本講義的編排
這份講義假設你略熟 tcl 或 perl 兩種 Scripting Languages 其中一種。
筆者堅守程式設計師懶惰的美德, 希望只寫一份講義, 就可以適用於不同語言版本的 Tk; 希望這份講義對於來自 tcl 的讀者與來自 perl 的讀者一樣有參考價值。 甚至希望將來有朋友可以共同參與修改這份講義, 只需要為它增加 python 版 / ruby 版 / java 版 / ... 的程式範例, 及少數幾個章節, 馬上就變成其他語言的 Tk 學習手冊, 這樣不是很帥嗎?
為此, 講義主體以觀念為主, 盡量適用於任何版本; 不同語言的 Tk 範例程式則放在不同的目錄下。 講義當中遇有必須針對不同版本解釋之處, 就以顏色區分。 目前有以下三個版本, 範例程式分置於不同的子目錄底下:
- 最原始的 tcl 版
- 目前較成熟, 由 Nick Ing-Simmons 所移植的 perl-Tk; 此處稱之為 nis 版
- 非常有潛力的 Tcl::Tk 模組, 原始作者是 Malcolm Beattie; 這兩年則由 Vadim Konovalov 積極更新; 此處稱之為 mbvk 版
在 pl/ 目錄底下的程式, 則是更有趣 (也更複雜) 的 "nis/mbvk 混合版"。 目前函式庫本身, 及筆者所寫的範例程式都不成熟, 暫時不推薦 學習這種混合風格。 (花格子背景的段落)
所以總結地說, 遇到有顏色的部分, 請只挑你有興趣的版本來看; 但有時候即便是沒有顏色的部分, 也可能因為講義太舊還沒有更新, 內容其實與你無關。 此外, 如果範例程式的連結失效, 或許把路徑當中的 "pl/" 改成 "nis/" 就可以找到舊版; 當然, 這就只適用於 nis 版。 造成困擾, 抱歉啦 ^_^|||。
取得 Tk
您想學的是...?
牛刀小試
我們先看三個簡單的範例程式:
cfglisting | |||
tcl 版 | v | v | v |
nis 版 | v | v | v |
nis/mbvk 混合版 | v | v | v |
mbvk 版 | v | v | v |
執行方式:
- tcl 版:
wish hello
- nis 版:
perl hello.pl
(這裡的 hello.pl 是 以指令 處理 hello 所產生出來的檔案。) - mbvk 版:
perl hello.pl
(這裡的 hello.pl 是 以指令 處理 hello 所產生出來的檔案。)
Tk 程式所產生的畫面, 由許多 widgets (姑且譯為 視窗元件) 所構成。 例如 hello 的畫面, 只有 1 個明顯的 widget; 而 add 的畫面, 則明顯地可看到 5 個 widgets。
每個 widget, 分屬於不同的 widget class (姑且譯為
元件類別)。 例如 label
就是一個純為顯示資訊用, 不直接接受使用者輸入的類別。 在 hello
的畫面上, 有 1 個 label 元件; 在 add 的畫面上, 則有 2 個 label 元件
-- 固定不變的 "+" 號, 與最右邊的加法答案。 在 hello 的畫面上, 還有 2
個 entry
元件, 與一個 button
元件 (那個
"=") 。 前者用來輸入字串; 後者用來觸發命令。 如何查
label
這個 widget class 的手冊呢?
- tcl 版:
man n label
- nis 版:
perldoc Tk::Label
或man 3pm Tk::Label
注意類別名稱的第一個字母大寫 - mbvk 版: 查 tcl 版 Tk 的手冊
man n label
但要自行翻譯成 perl 的語法寫程式。 (不同擔心, 請抄我的範例程式來改)
沒關係, 不需要從頭細讀到尾, 現在只是先熟悉一下如何查手冊。
事實上每個 tk 程式的畫面, 還有一個最基本的 widget -- 最外圍,
包含其他一切 widgets 的東東。 也就是說 hello 其實有兩個 widgets; 而
add 則有六個。 最外面這個 widget 屬於 toplevel
類別。
複雜的程式, 可以有好幾個 toplevel 的 widgets;
不過我們的範例都只會用到一個 toplevel widget。 這個內建的 toplevel
widget 有個名字, 叫做 .
。 在 nis 版中,
程式開始要呼叫 MainWindow->new()
產生一個 toplevel
widget; 在其他版本中, .
本來就存在,
不必手動產生。 Q: 請查一下這個 widget class 的手冊。
注意: 在 nis 版中, 應查 MainWindow 的手冊。
裝扮你的 widgets
Tk 的視窗元件, 內定都採用醜醜的灰色, 土土的 helvetica 字形。 如
hello 程式所見, 我們可以用 -fg
設定前景顏色, 用
-bg
設定背景顏色, 用 -bd
改變框框的寬度,
... 等等。 這些描述 widgets 的屬性, 稱為 configuration
options。
想改變 widget 的外觀, 並不限於只在它誕生時設定。 程式當中任何時候,
都可以呼叫 configure
函數來修改 widget 的 configuration
option。 例如 add 程式中, 使用者每次按下按鈕要計算加法,
就必須改變最右邊的 label 的顯示字串:
- tcl 版:
.result configure -text $sum
- nis 版:
$result->configure(-text=>$sum);
- mbvk 版:
widget(".result")->configure(-text=>$sum);
反過來說, 想查詢視窗元件某項屬性設定, 可以呼叫 cget
函數。 例如想查詢 .greetings
的背景顏色, 可以這樣寫:
- tcl 版:
set color [.greetings cget -bg]
- nis 版:
$color = $greetings->cget(-bg);
- mbvk 版:
$color = widget(".greetings")->cget(-bg);
如何稱呼一個 widget? 在 mvbk 版裡面稱呼方式和
tcl 版一樣 -- 用一個 "句點開頭的字串"。 但是要將一個 widget
(例如 ".greetings
拿來當做物件使用
(例如對它呼叫 configure 或 cget), 不能只寫名字
(畢竟 ".greetings"
只是一個字串,
總不能在後面放箭頭吧), 而要用
widget
函數將名字轉成物件, 例如寫成:
widget(".greetings")
。
還有那些 c.o. 可以修改, 讓 Tk 程式變得更美觀呢? 不同類別的 widget classes, 有著不同的 c.o., 所以理論上應針對你想修改的 widget class 去查手冊。 但其實也有不少 c.o. 對不同的 widget classes 一樣都有效。 例如上述的字形/前景顏色/背景顏色等等, 可以適用於 label, entry, button 等等 widget classes。 這些 「所有 widget classes 共同的 c.o.」 如果重複分散寫在各個 widget class 自己的手冊, 非常浪費, 所以 Tk 將它們合併寫在同一篇手冊 options(n) 當中。 馬上查查看有那些屬性可以更改吧: (注意 option 後面要加 s, 不然會查到另外一篇手冊!)
- tcl 版:
man n options
- nis 版:
perldoc Tk::options
或man 3pm Tk::options
- mbvk 版:
man n options
請特別看看 -relief 這個常用 c.o. 是做什麼用的? 還有其他那些值可以變化? 提示: 把框框的寬度 (-bd) 調得很大 (例如 50) 然後照著手冊把 -relief 設定成不同的值, 觀察 tk 如何利用明暗製造眼睛的錯覺, 達到立體的效果。
請注意: label 上面的字串, 是由程式產生的, 所以算是 c.o., 可以用 configure/cget 兩函數改/查; 但是 entry 上面的字串, 是使用者直接輸入的, 不算是 c.o., 不能用 configure/cget 改/查。 這裡要用 entry 類別的 get 函數來查。 這函數是 entry 特有的, 並不適用於 label 或 button, 所以稱為 entry 類別的 widget command。 在 entry 類別的手冊 "WIDGET COMMAND" 一節中可以查到 get 的用法。
產生 + 打包 = 顯示
一個 widget 產生出來之後, 並不直接顯示, 還要用 pack
將它打包顯示在螢幕上:
- tcl 版:
pack .n1 -side left -fill both
- nis 版:
$n1->pack(-side=>"left", -fill=>"both")
- mbvk 版:
tkpack($n1, -side=>"left", -fill=>"both")
例如 cfglisting 程式當中, 產生的 label 並未用 pack 打包,
所以沒有顯示。 打包的方向 (-side
) 可以有
"top"
"bottom"
"left"
"right"
四個方向。 至於 -fill
,
建議永遠填 "both"
。
初始化 + 事件處理 = 互動介面
Tk 程式包含兩部分: 建立視窗元件與打包顯示的
initialization script, 及後續處理與使用者互動的 event
handlers (處理事件的副程式) 。 例如 add 範例的
do_it
副程式, 就是一個 event handler。 在建立 "等號"
按鈕時, 我們就指定: 以後凡是使用者按下 "等號" 按鈕 (產生一個事件),
do_it
就要跳出來處理。 注意此時傳給
-command
的參數, 是
副程式的入口, 是一個 位址;
這時候 並沒有 呼叫 do_it
副程式。
這裡只是要告訴 "等號" 按鈕, 以後有需要的時候, 要到那裡去找
do_it
的執行碼; 但現在根本還不到真正呼叫的時候。
現在連兩個數字都還沒有出現哩, 怎麼相加呢?
至於無法與使用者互動的 hello, 則只有 initialization script 而沒有 event handler, 所以這個程式要用 ^c 或 kill 手動終止, 或從選單把它 close 掉。
那麼沒有 event 發生的時候, 你的 Tk 程式在做什麼呢? 就在 event
loop 裡面睡覺, 等待 event 發生嘍。 一旦發生 event,
就醒過來執行某個 event handler; 處理完了, 又回去睡覺。
tcl 版的 Tk 自動會進入 event loop,
不必特別呼叫; nis 版 與
mbvk 版則需要在 initialization script
最後面加上一句 MainLoop()
, 進入 event loop。
像 cfglisting 就是因為最後面少了這句, 所以印完資料程式就結束。
心得
為了寫一個小視窗就要打那麼多鍵, 真麻煩! 寫 tk 程式確實比目前常見的 visual programming 類工具囉嗦; 但正因為所有的程式碼都攤在陽光下, 所以維護比較容易。 (可用 grep, sed 等工具協助搜尋, 修改程式片斷.) 此外, 它提供了較多的彈性, 可以做一些 visual programming 不容易做的事情。
建議不要花力氣記函數的名稱及參數的用法。 常用的自然會記起來; 記不起來的, 表示不常用, 所以不重要, 需要用到時再查手冊就好了。 倒是專有名詞非常值得記, 因為查手冊時到處都會看到。 是否熟悉這些專有名詞, 將大大影你的響學習效率。
作業
- 顯示一個 label, 它的外觀由兩個 entries 與一個 button 來控制。 從這兩個 entries 可以輸入不同的外框, 及外框的寬度; 按下 button 時即生效。 提示: 拿 add 來改。 又, 畫面上這個不藍不綠的顏色叫做 "cyan"。
- 本頁最新版網址: https://frdm.cyut.edu.tw/~ckhung/b/tk/intro.php; 您所看到的版本: June 29 2016 10:26:12.
- 作者: 朝陽科技大學 資訊管理系 洪朝貴
- 寶貝你我的地球, 請 減少列印, 多用背面, 丟棄時做垃圾分類。
- 本文件以 Creative Commons Attribution-ShareAlike License 或以 Free Document License 方式公開授權大眾自由複製/修改/散佈。