忙完樹莓派架設 WordPress 網站的任務後, 終於可以回到 Tkinter 的學習了. 本篇記錄 Button 元件之測試, 本系列之前的文章參考 :
按鈕元件是 GUI 程式中最常用到的元件, 主要用來觸發一個事件以執行, 中斷, 或終止一個程序. 建立按鈕元件之語法如下 :
參考 :
按鈕元件常用參數如下表 (部分參數 ttk 不支援) :
Button 元件常用屬性 | 說明 |
command | 按下按鈕時要執行的函式名稱 (不可加括號) |
text | 按鈕上的文字, 多行文字可用 "\n" 跳行 |
width | 寬度 (單位=字元數) |
height | 高度 (單位=字元數) |
bg/background | 背景色, 可用標準顏色名稱字串例如 'blue' 或 "#0000ff" |
fg/foreground | 前景色 (文字顏色), 可用標準顏色名稱字串例如 'blue' 或 "#0000ff" |
activebackground | 按下按鈕時的背景色, 例如 'blue' 或 "#0000ff" |
activeforeground | 按下按鈕時的前景色, 例如 'blue' 或 "#0000ff" |
highlightbackground | 按鈕取得焦點時的背景色 |
highlightcolor | 按鈕取得焦點時的前景色 |
font | 設定字型與尺寸 (px), 粗體 (bold) 或斜體 (italic), 底線或刪除線等 |
padx | 元件與容器的水平間距 (px) |
pady | 元件與容器的垂直間距 (px) |
textvariable | 綁定按鈕文字內容的類別變數物件之名稱 |
bitmap | 設定預設之 Bitmap 圖示作為標籤內容 |
relief | 外框型式, sunken flat (預設), groove, raised, ridge, solid |
bd/borderwith | 邊框寬度 (預設 1px) |
underline | 設定第幾個字元加上底線 (0 起始, 預設 -1 都不加底線) |
justify | 設定按鈕文字的對齊方式, LEFT/CENTER (預設)/RIGHT |
anchor | 設定錨定位置="e", "w", "s", "n", "es","en", "ws", "wn","center" (預設) |
compound | 設定疊圖方式, TEXT/IMAGE/CENTER/TOP/BOTTOM/LEFT/RIGHT |
image | 設定按鈕上的圖片 (PhotoImage 圖片物件名稱) |
wraplength | 設定字串超過多少寬度 (單位 px) 換行 |
state | 設定按鈕狀態=tk.NORMAL (預設可用)/tk.DISABLED (不可用) |
綁定按鈕操作函式的方式有兩種, 其一是使用 def 定義函式一個函式, 並將其名稱賦值給 command 參數 (只要名稱即可, 不可加括弧, 雖然不會出現錯誤訊息, 但不會動作). 其次是使用 lambda 匿名函式, 這只適用於操作敘述只有一列的情況, 例如 :
測試 1 : 綁定操作函式的兩種做法 [看原始碼]
import tkinter as tk
def click_count():
var.set(var.get() + 1) # 取得 var 變數現值增量 1 後回存
win=tk.Tk()
win.geometry("200x150")
var=tk.IntVar() # 定義整數類別變數
var.set(0) # 設定初始值
label=tk.Label(win, textvariable=var) # 將整數類別變數綁定到標籤內容
label.pack()
button_1=tk.Button(text="增量", command=click_count) # 綁定指名函式
button_1.pack()
button_2=tk.Button(text="歸零", command=lambda: var.set(0)) # 綁定匿名函式
button_2.pack()
win.mainloop()
此例在視窗中放置了一個標籤元件以及兩個按鈕, 標籤用來顯示按鈕次數, 增量按鈕用來使整數類別變數 var 由 0 開始增量, 用 command 參數綁定指名函式 click_count(); 而歸零按鈕則用來將此變數值歸零, 綁定 lambda 匿名操作函式.
類別變數可用 set() 與 get() 方法存取其值, 在 click_count() 函式中先呼叫 var.get() 取得目前之計數值, 增量後傳給 var.set() 存回去, 標籤元件由於是透過 textvariable 參數與 var 類別變數綁定在一起, 因此每次按增量鈕使 var 變數增量後, 標籤的內容也會同步改變, 結果如下 :
注意, Python 的指名函式需於呼叫前定義, 此例若將 click_count() 放在程式最後面將出現函式未定義錯誤. 其次, lambda 匿名函式只能允許一個敘述 (用分號隔開的一列算兩個敘述), 對於簡單的操作使用 lambda 可使程式更簡潔, 例如用來關閉視窗的指令 win.destroy() 就很適合 :
測試 2 : 按鈕綁定 lambda 函式的範例-關閉視窗 [看原始碼]
import tkinter as tk
def click_count():
var.set(var.get() + 1)
win=tk.Tk()
win.geometry("300x150")
var=tk.IntVar()
var.set(0)
label=tk.Label(win, textvariable=var)
label.pack()
button_1=tk.Button(text="增量", command=click_count)
button_1.pack()
button_2=tk.Button(text="關閉", command=lambda: win.destroy()) # 關閉視窗
button_2.pack()
win.mainloop()
結果如下 :
此例只是將按鈕文字改成關閉, 然後將 command 綁定到呼叫 win.destroy() 的 lambda 函式而已.
如果要傳參數倒 command 參數所綁定的處理函式也是要借助 lambda 來達成, 例如 :
測試 2 : 按鈕綁定 lambda 函式的範例-傳遞參數 [看原始碼]
import tkinter as tk
def click_count():
var.set(var.get() + 1)
def set_init(val):
var.set(val)
win=tk.Tk()
win.geometry("300x170")
var=tk.IntVar()
var.set(0)
label=tk.Label(win, textvariable=var)
label.pack()
button_1=tk.Button(text="增量", command=click_count)
button_1.pack()
button_2=tk.Button(text="關閉", command=lambda: win.destroy()) # 關閉視窗
button_2.pack()
button_3=tk.Button(text="設定", command=lambda: set_init(100))
button_3.pack()
win.mainloop()
此例按鈕 3 的 command 參數綁定了一個有傳入參數的 lambda 函式, 呼叫 set_init() 函式, 按 "設定" 鈕會透過 lambda 呼叫 set_init() 函式並傳入初始值參數, 此處為常數, 也可以是變數. 結果如下 :
Button 元件與 Label 一樣也可以利用 textvariable 參數綁定類別變數來控制按鈕文字的存取 (不限於綁定 StringVar 類別, 也可以是 IntVar, BoolVar, 或 DoubleVar 類別, 例如 :
測試 3 : 利用 textvariable 參數綁定類別變數以存取按鈕文字 [看原始碼]
import tkinter as tk
def click_count():
global count # 存取全域變數
count += 1 # 增量
label_var.set("您按了 " + str(count) + " 次")
if (button_var.get()=="增量"): # 透過類別變數變換按鈕文字
button_var.set("還要增量")
else:
button_var.set("增量")
count=0 # 計數器
win=tk.Tk()
win.geometry("300x150")
label_var=tk.StringVar()
label_var.set("您按了 0 次") # 設定類別變數之初始值
label=tk.Label(win, textvariable=label_var) # 標籤綁定類別變數
label.pack()
button_var=tk.StringVar()
button_var.set("增量") # 設定類別變數之初始值
button=tk.Button(win, textvariable=button_var, command=click_count)
button.pack()
win.mainloop()
此例中的標籤與按鈕都用 textvariable 參數綁定了一個字串類別變數, 用來控制標籤與按鈕上的文字. 然後利用 global 關鍵字在 click_count() 內將全域變數增量, 透過辨別目前與按鈕綁定之類別變數之值來切換按鈕文字內容, 結果如下 :
以下範例測試 Button 元件的參數設定. Tkinter 元件的參數設定方式有三種 :
- 建立物件時以關鍵字參數傳入
- 建立物件後以 [] 運算子設定物件參數
- 建立物件後呼叫 config() 或 configure() 方法傳入關鍵字參數設定
注意, Tkinter 物件的 config() 是 configure() 方法的別名, 兩者功能相同.例如 :
測試 4 : tk 設定元件參數的三種方法 [看原始碼]
import tkinter as tk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x150")
button1=tk.Button(win, text="12345", width=10, bg="cyan") # 建立物件同時設定參數
button1.pack()
button2=tk.Button(win) # 建立按鈕物件
button2["text"]="abcde" # 設定參數
button2["background"]="ivory"
button2["padx"]=10
button2["pady"]=10
button2["relief"]=tk.SOLID
button2.pack()
button3=tk.Button(win) # 建立按鈕物件
button3.config(width=6, fg="blue", relief="ridge") # 呼叫 config() 設定參數
button3.configure(text="你在說哈囉嗎") # 呼叫 configure() 設定參數
button3.pack()
win.mainloop()
此例在視窗中放置了三個按鈕, 分別採用三種方法來設定按鈕元件之參數, button1 於建立物件時傳入關鍵字設定參數; button2 於建立後以 [] 運算子設定. 注意, 例如 relief 之類有固定值的參數, 可以用字串 (例如 "ridge") 或 TK 的常數 (例如 tk.RIDGE) 表示, 結果如下 :
可見 width 與 height 的單位是 ASCII 字元數不是 px, 因此 button1 寬度設為 10 個字元比其內容 '12345' 大一倍, button3 寬度設為 6 個字元, 雖然其內容 "你在說哈囉嗎" 也是 6 個字元, 但中文一個字元比 ASCII 字元大, 因此無法完全顯示字串內容.
這三種設定參數的方式同樣適用於 ttk 子套件, 但要注意的是 tk 與 ttk 的部分參數名稱有差異, 例如 tk 按鈕的內文間隔使用 padx 與 pady 參數設定, 但 ttk 則是使用 padding (表示左, 上, 右, 下間距之元組或串列).
另外 ttk 按鈕不能像 Label 元件那樣用 background 與 foreground 來設定背景與前景色, 因為 ttk 沒有提供這樣的參數, 我參考了下面這篇文章用 Style 去改背景, 結果都被預設的灰色蓋掉, 僅露出邊框顏色而已:
事實上, ttk 的按鈕可用的參數不多, 呼叫 ttk 按鈕物件的 keys() 方法僅列出如下 14 個參數 :
>>> print(button1.keys())
['command', 'default', 'takefocus', 'text', 'textvariable', 'underline', 'width', 'image', 'compound', 'padding', 'state', 'cursor', 'style', 'class']
可見 ttk 的按鈕在尺寸上僅提供 width 而沒有 height, 顯然 ttk 對元件外觀的彈性較 tk 為少, 例如 :
測試 5 : ttk 設定元件參數的三種方法 [看原始碼]
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x150")
button1=ttk.Button(win, text="12345", width=10)
print(button1.keys())
button1.pack()
button2=ttk.Button(win)
button2["text"]="abcde"
#button2["background"]="ivory" #出現 unknown option "-background" 錯誤
button2["padding"]=[10, 10, 10, 10]
# button2["relief"]=tk.SOLID #出現 unknown option "-relief" 錯誤
button2.pack()
button3=ttk.Button(win)
button3.config(width=6)
#button3.config(foreground="blue") #出現 unknown option "-foreground" 錯誤
#button3.config(relief="ridge") #出現 unknown option "-relief" 錯誤
button3.configure(text="你在說哈囉嗎")
button3.pack()
win.mainloop()
此例中被 # 註解掉的敘述就是 ttk 按鈕沒有支援的參數, 存取這些參數會出現 unknown option 的錯誤, 結果如下 :
可見 ttk 都是以灰色為底色.
參考 :
沒有留言:
張貼留言