Joseph Chen
在 SCT 做測試工程師時,第一個任務是把原本靠人工操作的測試流程包成一個 GUI。用 Tkinter 做出第一個視窗,讓測試員點一個按鈕就能跑完整個流程——那種成就感到現在都記得。
Tkinter 是什麼
Tkinter 是 Python 內建的 GUI 函式庫,安裝 Python 就有,不需要額外 pip install。它基於 Tk GUI toolkit,跨平台支援 Windows / macOS / Linux。
適合場景
快速開發內部工具、測試介面、自動化控制台、小型桌面應用
最大優勢
零額外依賴,Python 安裝就能跑。嵌入式環境(Raspberry Pi)的首選
限制
外觀較老舊,複雜 UI 建議用 PyQt6 或 customtkinter,商業 App 不適合
基本視窗架構
所有 Tkinter 程式的骨架都一樣:建立 root window → 加入 Widget → 呼叫 mainloop() 進入事件迴圈。
四大佈局管理器
Tkinter 有三種佈局方式(加上 Frame 容器概念共四種)。實際開發幾乎只用 grid,它最靈活且可預測。
| 佈局 | 原理 | 適合場景 | 推薦度 |
|---|---|---|---|
| pack() | 由上到下或左到右依序堆疊 | 簡單的垂直/水平排列 | ★★☆☆☆ |
| grid() | 表格定位,指定 row 和 column | 複雜表單、控制面板 | ★★★★★ |
| place() | 絕對像素座標定位 | 需要精確位置的特殊需求 | ★★☆☆☆ |
常用 Widget 速查
| Widget | 用途 | 關鍵用法 |
|---|---|---|
| ttk.Label | 顯示文字或圖片 | text="..." / textvariable=var |
| ttk.Button | 按鈕(觸發函數) | command=my_func |
| ttk.Entry | 單行文字輸入框 | .get() 取值 / .delete(0, END) |
| tk.Text | 多行文字輸入/輸出 | .insert(END, text) / .get(1.0, END) |
| ttk.Combobox | 下拉選單 | values=[...] / .get() 取目前選項 |
| ttk.Checkbutton | 勾選框 | variable=IntVar() |
| ttk.Radiobutton | 單選按鈕 | variable=var, value="A" |
| ttk.Frame | 容器(分區使用) | 可在裡面繼續用 grid/pack |
| tk.Scrollbar | 捲軸 | 需與 Text/Listbox 連接 |
| tk.Canvas | 繪圖畫布 | .create_line / create_rectangle |
事件驅動設計
Tkinter 是事件驅動模型:程式在 mainloop() 裡等待使用者操作,有事件發生就呼叫對應的 callback 函數。理解這個模型是 GUI 開發的核心。
mainloop() 是什麼
mainloop() 是一個無限迴圈,持續監聽作業系統的事件佇列(滑鼠點擊、鍵盤輸入、視窗關閉等),有事件就分派給對應的 Widget 或 callback 處理。
command= vs bind()
command= 只用於 Button,綁定點擊事件。bind() 更通用,可以綁定任何事件(鍵盤、滑鼠移動、視窗大小改變)到任意 Widget,例如 widget.bind("<Return>", handler)。
多執行緒:最重要的陷阱
GUI 的 mainloop() 跑在主執行緒。若在主執行緒執行長時間任務(串口通訊、等待 I/O),mainloop() 無法處理事件,視窗會「凍結」。解法:把長任務放到 threading.Thread 裡,用 root.after() 或 Queue 回傳結果給主執行緒更新 UI。
實際範例:自動化測試 GUI
以下是在 SCT 類似場景的簡化版本:選擇測試項目 → 點開始 → 背景執行測試(不凍結 UI)→ 結果顯示在 Text widget。
面試常考題
Q1. Tkinter 的 mainloop() 做什麼?
mainloop() 是一個持續運行的事件迴圈,不斷監聽作業系統送來的事件(點擊、鍵盤、計時器等),並分派給對應的 callback 函數處理。呼叫 mainloop() 後程式才「活起來」,關閉視窗後 mainloop() 才返回。
Q2. 如何避免 GUI 在執行長任務時凍結?
使用 threading.Thread 把長任務(I/O、計算、串口通訊)移到背景執行緒,主執行緒繼續跑 mainloop()。背景執行緒完成後透過 Queue + root.after() 回傳結果到主執行緒更新 UI。注意:絕對不能在背景執行緒直接操作 Tkinter Widget(非執行緒安全)。
Q3. StringVar 和普通變數有什麼差?
StringVar 是 Tkinter 的「可觀察變數」,與 Widget 雙向綁定。改變 StringVar 的值(.set()),綁定的 Label/Entry 會自動更新顯示;使用者在 Entry 輸入,StringVar 也會自動同步。普通 Python 變數改變後 Widget 不會自動更新,需要手動 .config(text=...)。
Q4. grid() 的 sticky 參數是什麼?
sticky 決定 Widget 在格子內如何對齊或延伸,使用 "n"(上)/"s"(下)/"e"(右)/"w"(左)或組合。sticky="ew" 讓 Widget 水平填滿格子;sticky="nsew" 讓 Widget 四個方向都填滿,通常配合 columnconfigure(weight=1) 使用。
上一篇
EP.02 — PyTorch
AI 工程師必備基礎
下一篇
EP.04
即將推出