經過複習暖身後, 準備打鐵趁熱繼續 tkinter 的學習. 本篇測試 GUI 視窗應用程式中最常見的 Label 元件 (widget).
# Python 內建 GUI 模組 tkinter 測試 (一) : 建立視窗
# Python 內建 GUI 模組 tkinter 測試 (二) : 對話框
# Python 內建 GUI 模組 tkinter 測試 (三) : 版面管理員
1. Lebel (標籤) 元件 :
Label 物件用來建立文字或圖片標籤, 主要功能是作為引導說明之用, 例如表單欄位名稱標示, 或顯示狀態結果等, 只能看而無法互動.
其語法如下 :
Label(父容器, **參數列)
參考 :
Label 元件常用參數如下表 :
Label 元件常用屬性 | 說明 |
text | 標籤文字內容, 多行文字可用 "\n" 跳行 |
width | 寬度 (單位=字元數) |
height | 高度 (單位=字元數) |
bg/background | 背景色, 可用標準顏色名稱字串例如 'blue' 或 "#0000ff" |
fg/foreground | 前景色 (文字顏色), 可用標準顏色名稱字串例如 'blue' 或 "#0000ff" |
font | 字型與尺寸 (px), 粗體 (bold) 或斜體 (italic), 底線或刪除線等 |
padx | 元件與容器的水平間距 (px) |
pady | 元件與容器的垂直間距 (px) |
textvariable | 綁定標籤文字內容的 StringVar 物件之變數名稱 |
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) 換行 |
這些參數可以在建立 Label 物件時傳入, 也可以在建立物件後呼叫其 config() 方法設定. 其中最重要的是 text 參數, 用來設定標籤文字. 其次是 image 參數, 用來設定圖片標籤, 其值為一個 PhotoImage 物件, 可呼叫 tkinter 的 PhotoImage() 函數並傳入圖檔名稱 file 來建立此物件 :
image=tk.PhotoImage(file="myphoto.png")
tkinter 僅支持四種圖片格式 :
- gif
- pgm
- ppm
- png (8.6 板以上)
如果要使用 jpg 或 bmp, 則需要用例如 Pillow 等套件進行轉換.
除了可用 image 參數建立圖片標籤外, 也可以用 bitmap 參數設定位元圖示, 以下是在各作業系統都可用的通用 bitmap 名稱 (字串) :
bitmap 位元圖示名稱 | 說明 |
"error" | 錯誤 |
"hourglass" | 沙漏 |
"info" | 訊息 (i) |
"questhead" | 問號與人頭 |
"question" | 問號 |
"warning" | 驚嘆號 |
"gray12" | 淡灰階 |
"gray25" | 淺灰階 |
"gray50" | 次暗灰階 |
"gray75" | 暗灰階 |
注意, ttk 不支援 bitmap 參數, 只有 tk 可用 bitmap, 其次, bitmap 與 image 這兩個參數不能同時設定.
Label 元件的常用方法如下表 :
Label 元件常用方法 | 說明 |
config(**options) | 設定物件屬性 options |
keys() | 傳回 Label 物件的屬性串列 (元件共通方法) |
其中 keys() 是所有 tkinter 元件都有的共通方法, 它會傳回物件的屬性串列, 如下例所示 :
測試 1 : 比較 tk 與 ttk 的 Label 物件屬性 [看原始碼]
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
tk_label=tk.Label(win, text="Hello World!", bg="ivory") # 建立 tk 的標籤文字物件
tk_label.pack()
ttk_label=ttk.Label(win, text="你是在說哈囉嗎?", background="aqua") # 建立 ttk 的Label 物件
ttk_label.pack()
print(tk_label.keys()) # 呼叫 keys() 傳回 tk 的 Label 物件屬性串列
print(ttk_label.keys()) # 呼叫 keys() 傳回 ttk 的 Label 物件屬性串列
win.mainloop()
此例分別建立一個 tk 與 ttk 的 Label 元件, 並呼叫其 keys() 方法來檢視屬性串列, 結果如下 :
>>> %Run Label_1.py
['activebackground', 'activeforeground', 'anchor', 'background', 'bd', 'bg', 'bitmap', 'borderwidth', 'compound', 'cursor', 'disabledforeground', 'fg', 'font', 'foreground', 'height', 'highlightbackground', 'highlightcolor', 'highlightthickness', 'image', 'justify', 'padx', 'pady', 'relief', 'state', 'takefocus', 'text', 'textvariable', 'underline', 'width', 'wraplength']
['background', 'foreground', 'font', 'borderwidth', 'relief', 'anchor', 'justify', 'wraplength', 'takefocus', 'text', 'textvariable', 'underline', 'width', 'image', 'compound', 'padding', 'state', 'cursor', 'style', 'class']
上方是 tk 的 Label 物件屬性, 下方則是 ttk 的 Label 物件屬性, 可見 ttk 可用的屬性參數比 tk 少很多, 例如它沒有 bg, padx, pady 等參數 (ttk 的背景色要用 background, 不能用 bg). 由於 Label 元件外觀在 tk 與 ttk 沒有明顯差別, 因此對於 Label 元件而言, 其實只要使用 tkinter 版的即可.
其次, 標籤文字外圍預設沒有框邊 (因為 relief 參數預設為 "flat"), 如果要讓 Label 有框邊, 則在建立物件時要傳入 relief 參數, 如下面範例所示 :
測試 2 : 建立標籤文字並設定參數 [看原始碼]
import tkinter as tk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x200")
label1=tk.Label(win, text="Hello World")
label1.pack()
label2=tk.Label(win, text="你是在說哈囉嗎?", underline=3)
label2.pack()
label3=tk.Label(win, text="洪車瑛(全汝斌)", padx=5, pady=5, relief="solid")
label3.pack()
label4=tk.Label(win, text="文森佐(宋仲基)", bg="aqua", fg="blue")
label4.pack()
label5=tk.Label(win, text="黑道律師文森佐", font="微軟正黑體 16 bold")
label5.config(bd=3, relief="solid")
label5.pack()
win.mainloop()
此例測試了一些 Label 元件的參數, 例如 relief (邊框樣式), underline (底線字元索引), bg (背景), fg (前景), padx (水平間距), pady (垂直間距), 以及 font (字型樣式) 等, 結果如下 :
注意 label2 元件將參數 underline 設為 3 (字元索引), 表示要將第 4 個字元 "說" 加上底線. 由上面的範例可知, Label 元件預設無邊框 (relief="flat"), 下面範例測試 6 種 relief 參數值 :
import tkinter as tk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x200")
label1=tk.Label(win, text="relief='flat'", relief="flat") # 預設無邊框
label1.pack()
label2=tk.Label(win, text="relief='sunken'", relief="sunken") # 標籤凹下
label2.pack()
label3=tk.Label(win, text="relief='groove'", relief="groove") # 邊框凹下
label3.pack()
label4=tk.Label(win, text="relief='raised'", relief="raised") # 標籤凸起
label4.pack()
label5=tk.Label(win, text="relief='ridge'", relief="ridge") # 邊框凸起
label5.pack()
label6=tk.Label(win, text="relief='solid'", relief="solid") # 實線邊框
label6.pack()
win.mainloop()
結果如下 :
下面範例改用 ttk 來測試 6 種邊框效果 :
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x200")
label1=ttk.Label(win, text="relief='flat'", relief="flat") # 預設無邊框
label1.pack()
label2=ttk.Label(win, text="relief='sunken'", relief="sunken") # 標籤凹下
label2.pack()
label3=ttk.Label(win, text="relief='groove'", relief="groove") # 邊框凹下
label3.pack()
label4=ttk.Label(win, text="relief='raised'", relief="raised") # 標籤凸起
label4.pack()
label5=ttk.Label(win, text="relief='ridge'", relief="ridge") # 邊框凸起
label5.pack()
label6=ttk.Label(win, text="relief='solid'", relief="solid") # 實線邊框
label6.pack()
win.mainloop()
結果如下 :
與上面的 tk 標籤比較, 主要差別是 ttk 的 solid 邊框較細顏色較淡, 而 tk 的邊框是較粗的黑線, 其餘的邊框效果看來差不多.
邊框預設粗細為 1px, 可以用 borderwidth 加以設定, 注意, 在 tk 可以用 bd 或 borderwidth, 但在 ttk 只能用 borderwidth. 另外因為預設的垂直與水平間距為 1px, 這讓標籤文字與邊框太過於接近, 下面範例用 config() 方法加以設定. 注意, tk 用 padx 與 pady 設定間距 (整數); 而 ttk 則用 paading 參數, 是格式為 [left, top, right, bottom] 的串列 (元組也可以), 例如 :
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x250")
# tk
tk_label1=tk.Label(win, text="relief='flat'", relief="flat")
tk_label1.config(bd=3, padx=5, pady=5) # tk 邊框用 bd 或 borderwidth 均可
tk_label1.grid(row=0, column=0)
tk_label2=tk.Label(win, text="relief='sunken'", relief="sunken")
tk_label2.config(bd=3, padx=5, pady=5)
tk_label2.grid(row=1, column=0)
tk_label3=tk.Label(win, text="relief='groove'", relief="groove")
tk_label3.config(bd=3, padx=5, pady=5)
tk_label3.grid(row=2, column=0)
tk_label4=tk.Label(win, text="relief='raised'", relief="raised")
tk_label4.config(bd=3, padx=5, pady=5)
tk_label4.grid(row=3, column=0)
tk_label5=tk.Label(win, text="relief='ridge'", relief="ridge")
tk_label5.config(bd=3, padx=5, pady=5)
tk_label5.grid(row=4, column=0)
tk_label6=tk.Label(win, text="relief='solid'", relief="solid")
tk_label6.config(bd=3, padx=5, pady=5)
tk_label6.grid(row=5, column=0)
# ttk
ttk_label1=ttk.Label(win, text="relief='flat'", relief="flat")
ttk_label1.config(borderwidth=3, padding=[5, 5, 5, 5]) # ttk 邊框只能用 borderwidth
ttk_label1.grid(row=0, column=1)
ttk_label2=ttk.Label(win, text="relief='sunken'", relief="sunken")
ttk_label2.config(borderwidth=3, padding=[5, 5, 5, 5])
ttk_label2.grid(row=1, column=1)
ttk_label3=ttk.Label(win, text="relief='groove'", relief="groove")
ttk_label3.config(borderwidth=3, padding=[5, 5, 5, 5])
ttk_label3.grid(row=2, column=1)
ttk_label4=ttk.Label(win, text="relief='raised'", relief="raised")
ttk_label4.config(borderwidth=3, padding=[5, 5, 5, 5])
ttk_label4.grid(row=3, column=1)
ttk_label5=ttk.Label(win, text="relief='ridge'", relief="ridge")
ttk_label5.config(borderwidth=3, padding=[5, 5, 5, 5])
ttk_label5.grid(row=4, column=1)
ttk_label6=ttk.Label(win, text="relief='solid'", relief="solid")
ttk_label6.config(borderwidth=3, padding=(5, 5, 5, 5)) # padding 用元組亦可
ttk_label6.grid(row=5, column=1)
win.mainloop()
此例改用 grid() 排版以利比較 tk 與 ttk 的差異, 結果如下 :
奇怪的是, ttk 的 borderwidth 參數似乎無效, 不管設定為多少都沒變, why? 不過 ttk 的 padding 有個好處是設定較靈活, 上下左右都可以不同值, tk 的 padx, pady 使左右間距一樣, 上下間距一樣.
從以上範例可知, 標籤文字預設是置中 ("center") 對齊, 可用 justify 參數設定向左 ("left") 或向右 ("right") 對齊. 下面範例同時也測試 wraplength 參數, 它可指定標籤文字每幾個 px 強制跳行 :
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x200")
msg="人生就像騎腳踏車,想保持平衡就得往前走。"
label1=ttk.Label(win, text=msg, wraplength=200)
label1.config(relief="ridge")
label1.pack()
label2=ttk.Label(win, text=msg, wraplength=300, justify="left")
label2.config(relief="ridge")
label2.pack()
label3=ttk.Label(win, text=msg, wraplength=300, justify="right")
label3.config(relief="ridge")
label3.pack()
win.mainloop()
此例利用 wraplength 參數強制每 300px 換行顯示以測試 justify 參數之左中右對齊效果, 同時也設定邊框以利觀察, 可見 label1 預設置中對齊, label2 為向左對齊, 而 label 為向右對齊, 結果如下 :
Label 元件除了可以利用 text 參數放置標籤文字外, 還可以利用 image 參數放置圖片標籤, 此參數需要一個 PhotoImage 物件, tkinter 提供了 PhotoImage() 函數可將 gif 或 png 等圖檔轉成 PhotoImage 物件 (目前尚不支援 jpeg 檔).
下面範例使用的圖檔取自維基百科中的 Lenna 圖, 原圖為 300x300 的 jpeg 檔, 下載後用小畫家更改解析度為 200x200 並存成 png 檔 :
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x300")
lenna=tk.PhotoImage(file="200x200-Lenna.png") # 從指定知圖檔建立 PhotoImage 物件
print(type(lenna)) # 輸出 <class 'tkinter.PhotoImage'>
label1=ttk.Label(win, image=lenna) # 用 image 參數建立圖片標籤
label1.config(relief="solid", padding=10)
label1.pack()
win.mainloop()
此例呼叫 tk 的 PhotoImage() 函數並傳入 file 參數指定圖檔路徑與名稱來建立一個 PhotoImage 物件, 然後將此 PhotoImage 物件傳入 Label() 函數的 image 參數即可. 注意, PhotoImage() 是放在 tk 底下的函數, ttk 並未重複支援, 不能呼叫 ttk.PhotoImage(). 結果如下 :
Label 元件的標籤內容也可以同時使用圖片與文字, 這需要用 compound 參數來指定文字與圖片的相對關係 (compound="left"/"center"/"right"/"top"/"bottom", 分別表示圖片靠左, 中, 與右). 例如 :
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("500x700")
lenna=tk.PhotoImage(file="200x200-Lenna.png")
print(type(lenna))
msg="""影像處理教科書上著名的 Lenna 圖,取自於 1972 年 Playboy 雜誌上
模特兒 Lenna Söderberg 的照片。"""
label1=ttk.Label(win, text=msg, justify="left", image=lenna, compound="right")
label1.config(relief="solid", padding=10, wraplength=200)
label1.pack()
label2=ttk.Label(win, text=msg, justify="left", image=lenna, compound="left")
label2.config(relief="solid", padding=10, wraplength=200)
label2.pack()
label3=ttk.Label(win, text=msg, justify="left", image=lenna, compound="center")
label3.config(relief="solid", padding=10, wraplength=200)
label3.pack()
win.mainloop()
此例在視窗中建立了三個圖文標籤, 利用 compound 參數分別設定圖片靠右, 左, 以及在中央, 文字則利用 wraplength 強制 200px 換行顯示, 結果如下 :
參數 compound 也可以指定圖片靠上 (="top") 或靠下 (="bottom"), 例如 :
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("500x400")
lenna=tk.PhotoImage(file="200x200-Lenna.png")
print(type(lenna))
msg="""影像處理教科書上著名的 Lenna 圖,取自於 1972 年 Playboy 雜誌上
模特兒 Lenna Söderberg 的照片。"""
label1=ttk.Label(win, text=msg, justify="left", image=lenna, compound="top")
label1.config(relief="solid", padding=10, wraplength=200)
label1.grid(row=0, column=0)
label2=ttk.Label(win, text=msg, justify="left", image=lenna, compound="bottom")
label2.config(relief="solid", padding=10, wraplength=200)
label2.grid(row=0, column=1)
win.mainloop()
結果如下 :
但是如果同時指定了 text 與 image 參數, 卻沒指定 compound 參數, 則 text 會被忽略, 僅顯示圖片, 換句話說, text 相當於無效, 如下範例所示 :
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("500x700")
lenna=tk.PhotoImage(file="200x200-Lenna.png")
print(type(lenna))
msg="""影像處理教科書上著名的 Lenna 圖,取自於 1972 年 Playboy 雜誌上
模特兒 Lenna Söderberg 的照片。"""
label1=ttk.Label(win, text=msg, justify="left", image=lenna)
label1.config(relief="solid", padding=10, wraplength=200)
label1.pack()
win.mainloop()
此例同時指定了 text 與 image 參數, 卻沒有指定 compound 參數, 結果只顯示圖片 :
除了可在標籤中放置自訂的圖片外, Tkinter 也內建了 10 個圖示可透過 bitmap 參數放置在 Label 上, 但此功能僅 tk 有, ttk 並沒有 bitmap 參數可用, 例如 :
import tkinter as tk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x250")
label1=tk.Label(win, text="訊息", bitmap="info") # 使用 bitmap 時 text 無效
label1.config(relief="groove", width=200)
label1.pack()
label2=tk.Label(win, bitmap="warning")
label2.config(relief="groove", width=200)
label2.pack()
label3=tk.Label(win, bitmap="error")
label3.config(relief="groove", width=200, height=30)
label3.pack()
label4=tk.Label(win, bitmap="question")
label4.config(relief="groove", width=200)
label4.pack()
label5=tk.Label(win, bitmap="questhead")
label5.config(relief="groove", padx=10, pady=10) # padx 與 pady 無效
label5.pack()
label6=tk.Label(win, bitmap="gray12")
label6.config(relief="groove", width=200)
label6.pack()
label7=tk.Label(win, bitmap="gray25")
label7.config(relief="groove", width=200)
label7.pack()
label8=tk.Label(win, bitmap="gray25")
label8.config(relief="groove", width=200)
label8.pack()
label9=tk.Label(win, bitmap="gray50")
label9.config(relief="groove", width=200)
label9.pack()
label10=tk.Label(win, bitmap="gray75")
label10.config(relief="groove", width=200)
label10.pack()
win.mainloop()
結果如下 :
可見 text 與 bimap 參數同時使用時 text 參數無效 (如 label1 所示); 同時 padx 與 pady 對 bitmap 標籤也是無效 (如 label5 所示).
還有一個元件共通參數 anchor, 當元件的尺寸大於內容 (文字或圖片) 時, 此參數用來定位內容在在元件中的 9 個方位, 即 "n" (北), "e" (東), "s" (南), "w" (西), "nw" (西北), "ne" (東北), "sw" (西南), "se" (東南), "center" (中央) :
注意, anchor 參數的值除了上述的方位字串外, 也可以用 tk 的常數, 例如 "sw" 可用 tk.SW, 例如 :
import tkinter as tk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("600x600")
label1=tk.Label(win, text="Hello", anchor="nw")
label1.config(relief="groove", width=15, height=7)
label1.grid(row=0, column=0)
label2=tk.Label(win, text="Hello", anchor="n")
label2.config(relief="groove", width=15, height=7)
label2.grid(row=0, column=1)
label3=tk.Label(win, text="Hello", anchor="ne")
label3.config(relief="groove", width=15, height=7)
label3.grid(row=0, column=2)
label4=tk.Label(win, text="Hello", anchor="w")
label4.config(relief="groove", width=15, height=7)
label4.grid(row=1, column=0)
label5=tk.Label(win, text="Hello", anchor="center")
label5.config(relief="groove", width=15, height=7)
label5.grid(row=1, column=1)
label6=tk.Label(win, text="Hello", anchor="e")
label6.config(relief="groove", width=15, height=7)
label6.grid(row=1, column=2)
label7=tk.Label(win, text="Hello", anchor="sw")
label7.config(relief="groove", width=15, height=7)
label7.grid(row=2, column=0)
label8=tk.Label(win, text="Hello", anchor=tk.S)
label8.config(relief="groove", width=15, height=7)
label8.grid(row=2, column=1)
label9=tk.Label(win, text="Hello", anchor=tk.SE)
label9.config(relief="groove", width=15, height=7)
label9.grid(row=2, column=2)
win.mainloop()
此例使用 grid 排版了 3x3 的九宮格, 每格放一個大小較文字內容 "Hello" 還大的 Label 元件, 並以 anchor 參數指定了相對應的方位, 結果如下 :
可見文字內容顯示在 anchor 所指定的方位上.
參考 :
2 則留言 :
非常詳細的教學
程式碼測試和預覽圖都很貼心
受益良多
Hi, 感謝您的讚美, 這其實都是為了避免自己忘記, 能快速恢復功力而邊學邊整理, Python 測試總目錄如下:
https://yhhuang1966.blogspot.com/2019/02/python_24.html
張貼留言