Tkinter 功夫已經練到第 11 層了, 今天要練第 12 層的 Scale 元件 (又稱 Slider 滑桿).
本系列之前的文章參考 :
Scale 元件具有可滑動的滑桿, 用來在限定的連續範圍內設定一個數值, 此元件 tk 與 ttk 中均有提供. 建立 Scale 元件之語法如下 :
參考 :
Scale 元件常用參數如下表 :
Scale 常用參數 | 說明 |
from_ | 滑桿之起始值 (預設 0) |
to | 滑桿之結束值 (tk 預設100, ttk 預設 1) |
orient | 滑桿之方向=tk.HORIZONTAL (tk 預設) / tk.VERTICAL (ttk 預設) |
command | 當滑桿被捲動時要呼叫之函式名稱 |
length | 滑桿長度 (預設 100 px) |
digits | 設定滑桿數值之數字位數 (ttk 無) |
label | 設定顯示於水平滑桿左上角與垂直滑桿右上角之標籤 (預設無) |
resolution | 設定滑桿滑動一格的數值變動長度 (ttk 無) |
showvalue | 是否顯示目前滑桿之值, True (顯示)/False (預設不顯示, ttk 無) |
width | 滑桿柄的寬度 (水平滑桿) 或高度 (垂直滑桿), 預設 10px (ttk 無) |
tickinterval | 顯示於滑桿旁邊的刻度間隔長度 (ttk 無) |
variable | 與 Scale 綁定之類別變數名稱 (IntVar, DoubleVar, 或 StringVar) |
其中有些參數例如 label, digit, showvalue, tickinterval 等 ttk 不支援, 參考 :
參數 orient 用來設定滑桿方向, 其值可以用 tk.VERTICAL/tk.HORIZONTAL 設定, 也可以使用字串 "vertical"/"horizontal". 注意, tk 與 ttk 版本預設方位剛好相反, tk 版的預設滑桿是垂直的; 而 ttk 版預設是水平滑桿.
參數 variable 用來綁定一個類別參數, 可以是 IntVar, DoubleVar, 或 StringVar (值會被轉成字串). 注意, tk 與 ttk 的 Scale 預設值範圍
注意, 有些參數例如 showvalue 2等只能在 tk 使用, ttk 不支援.
Scale 常用方法 | 說明 |
get() | 傳回目前 Scale 滑桿之值 |
set() | 設定 Scale 尺規滑桿之值 |
測試 1 : 預設的尺規滑桿 tk 版 [看原始碼]
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x200")
scale_h=tk.Scale(win) # 垂直滑桿 (預設)
scale_h.pack()
scale_v=tk.Scale(win, orient=tk.HORIZONTAL) # 水平滑桿
scale_v.pack()
win.mainloop()
此例建立了兩個尺規滑桿, 預設是垂直滑桿, 水平則需指定 orient 參數為 tk.HORIZONTAL (亦可用字串 "horizontal"), 結果如下 :
可見垂直滑桿左方與水平滑桿上方都會顯示目前的滑桿值, 預設為 0~100. 其 ttk 版範例如下 :
測試 2 : 預設的尺規滑桿 ttk 版 [看原始碼]
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x200")
scale_h=ttk.Scale(win) # 預設水平滑桿
scale_h.pack()
scale_v=ttk.Scale(win, orient=tk.VERTICAL) # 指定為垂直滑桿
scale_v.pack()
win.mainloop()
因為 ttk 預設是水平滑桿, 故垂直滑桿需指定 orient 參數為 tk.VERTICAL, 結果如下 :
可見 ttk 版的滑桿預設不會在旁邊顯示目前滑桿之值, 若要在 ttk 滑桿旁邊顯示其值須另行添加一個 Label 元素才行, 而存取滑桿值的方法則有下列三種 :
- 透過與 Scale 的 variable 參數綁定的類別變數之 get() 與 set() 方法
- 利用與 command 參數呼叫的函式之傳入參數 (只能取得不能設定)
- 利用 Scale 物件的 get() 或 set() 方法
其中第二種方法最簡單, 使用 command 參數去呼叫一個函式, 但與其他元件不同的是, 此函式必須帶一個位置參數 (否則會出現錯誤), 此參數之值就是滑桿之值, 但是這方法只能取得滑桿值, 不能設定滑桿值. 例如 :
測試 3 : 取得與顯示 ttk 滑桿值的方法 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_h1(value): # 使用類別變數的 get() 方法取得滑桿值
label_h1.set(var_h1.get())
def show_value_h2(value): # 使用函式的傳入參數取得滑桿值
label_h2.set(value)
def show_value_v(value): # 使用 Scale 物件的 get() 取得滑桿值
label_v.set(scale_v.get())
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x250")
var_h1=tk.DoubleVar() # ttk 滑桿應該綁定 DoubleVar 類別變數
scale_h1=ttk.Scale(win, variable=var_h1, command=show_value_h1) # 第一個水平滑桿
scale_h1.pack()
label_h1=tk.StringVar() # 顯示第一個水平滑桿值之 Label
tk.Label(win, textvariable=label_h1).pack()
scale_h2=ttk.Scale(win, command=show_value_h2) # 第二個水平滑桿
scale_h2.pack()
label_h2=tk.StringVar() # 顯示第二個水平滑桿值之 Label
tk.Label(win, textvariable=label_h2).pack()
scale_v=ttk.Scale(win, command=show_value_v, orient="vertical") # 垂直滑桿
scale_v.pack()
label_v=tk.StringVar()
tk.Label(win, textvariable=label_v).pack() # 顯示垂直滑桿值之 Label
win.mainloop()
此例是有兩個水平滑桿與一個垂直滑桿, 分別用來演示三種取得滑桿值的方法, 其中第一個水平滑桿透過綁定的 DoubleVar 類別變數之 get() 方法來取得滑桿值; 第二個水平滑桿則直接使用 command 參數所呼叫的函式傳入參數來取得; 而垂直滑桿則是直接呼叫 Scale 物件的 get() 方法. 每一個滑桿都有一個 Label 搭配顯示其值. 注意, 不論使用哪一種方式, command 參數所呼叫的函式都必須有一個傳入參數. 結果如下 :
可見與 tk 滑桿預設值域 0~100 整數不同的是, ttk 滑桿的值域為 0~1 的浮點數, 這就是為什麼第一個滑桿綁定的是 DoubleVar 類別變數的原因, 如果綁定 IntVar 變數將永遠取得 0.
tk 滑桿雖然自帶數值顯示, 但要取得其值也是使用這三種方式, 不過使用類別變數綁定時應該使用 IntVar, 若使用 DoubleVar 將取得一個帶一位小數 .0 之數值, 但這沒用處. 例如 :
測試 4 : 取得與顯示 tk 滑桿值的方法 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_h1(value):
label_h1.set(var_h1.get())
def show_value_h2(value):
label_h2.set(value)
def show_value_v(value):
label_v.set(scale_v.get())
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x300")
var_h1=tk.IntVar() # tk 滑桿應該綁定 IntVar 類別變數
scale_h1=tk.Scale(win,
variable=var_h1,
orient="horizontal",
command=show_value_h1) # 第一個水平滑桿
scale_h1.pack()
label_h1=tk.StringVar()
tk.Label(win, textvariable=label_h1).pack()
scale_h2=tk.Scale(win,
orient="horizontal",
command=show_value_h2) # 第二個水平滑桿
scale_h2.pack()
label_h2=tk.StringVar()
tk.Label(win, textvariable=label_h2).pack()
scale_v=tk.Scale(win, command=show_value_v) # tk 預設是垂直滑桿
scale_v.pack()
label_v=tk.StringVar()
tk.Label(win, textvariable=label_v).pack()
win.mainloop()
此例與上例差別僅在於與 tk 滑桿綁定之類別變數應該使用 IntVar, 以及 tk 滑桿預設是垂直,而 ttk 預設是水平, 結果如下 :
Scale 元件的數值預設值都是 0, 如果要改變此域設值必須透過與其綁定之類別變數 IntVar (tk) 或 DoubleVar(ttk), 因為 Scale 元件並未提供參數來設定預設值, 例如 :
測試 5 : 利用類別變數的 set() 方法設定滑桿初始值 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_tk(value):
label_tk.set(value)
def show_value_ttk(value):
label_ttk.set(value)
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x250")
var_tk=tk.IntVar()
var_tk.set(20) # 透過綁定之類別變數設定 tk 滑桿初始值
scale_tk=tk.Scale(win,
variable=var_tk,
command=show_value_tk)
scale_tk.pack()
label_tk=tk.StringVar()
tk.Label(win, textvariable=label_tk).pack()
var_ttk=tk.DoubleVar()
var_ttk.set(0.7071) # 透過綁定之類別變數設定 ttk 滑桿初始值
scale_ttk=ttk.Scale(win,
variable=var_ttk,
command=show_value_ttk)
scale_ttk.pack()
label_ttk=tk.StringVar()
label_ttk.set(0.7071)
tk.Label(win, textvariable=label_ttk).pack()
win.mainloop()
此例建立了兩個類別變數 var_tk 與 var_ttk 經由 variable 參數分別綁定到 tk 與 ttk 的 Scale 元件, 只要呼叫類別變數的 set() 方法即可設定滑桿的初始值, 結果如下 :
可見程式一開始執行, 兩個滑桿初始值就不是預設的 0, 而是所設定之值 20 與 0.7071 了.
從以上的範例可知, tk 的 Scale 數值是預設傳回 0~100 的整數, 而 ttk 的 Scale 數值是預設傳回 0~1 的浮點數, 這預設範圍可以用 from_ 與 to 參數更改, 例如 :
測試 6 : 用 from_ 與 to 參數更改滑桿範圍 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_tk(value): # 顯示 tk 滑桿值
label_tk.set(value)
def show_value_ttk(value): # 顯示 ttk 滑桿值
label_ttk.set(value)
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x250")
scale_tk=tk.Scale(win,
from_=-10.0,
to=10.0,
command=show_value_tk)
scale_tk.pack()
label_tk=tk.StringVar()
tk.Label(win, textvariable=label_tk).pack()
scale_ttk=ttk.Scale(win,
from_=-10,
to=10,
command=show_value_ttk)
scale_ttk.pack()
label_ttk=tk.StringVar()
tk.Label(win, textvariable=label_ttk).pack()
win.mainloop()
此例兩個 Scale 一個是 tk 的, 另一個是 ttk 的, 都可以用 from_ 與 to 參數設定範圍, 結果如下 :
可見兩個滑桿值的範圍都被改成 -10~10 了.
滑桿的長度預設是 100px, 柄的寬度預設是 10px, 可以分別用 length 與 width 參數設定, 下面範例除了測試 length 與 width 外, 還測試了一些共同的參數如 bg 與 relief 等 :
測試 7 : 用 width 與 length 參數設定滑桿長度與柄的寬度 (tk) [看原始碼]
import tkinter as tk
from tkinter import ttk
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x250")
scale_h=tk.Scale(win, width=40, length=150) # 設定滑桿長度與柄之寬度
scale_h["bg"]="ivory"
scale_h["relief"]="ridge"
scale_h.pack()
scale_v=tk.Scale(win,
width=40,
length=250,
bg="cyan")
scale_v["orient"]="horizontal" # 用 [] 設定參數
scale_v.config(relief="sunken", bg="cyan") # 呼叫 config() 設定參數
scale_v.pack()
win.mainloop()
此例的 tk 滑桿使用了三種方式設定參數, 一是在建立 Slider 物件時值皆傳入參數, 二是建立參數後用 [] 運算子設定, 三是呼叫 Scale 物件的 config() 方法設定, 結果如下 :
可見 bg 的效果主要是在自帶數值顯示標籤上, 滑桿本身還是一樣灰色.
但 bg/backgroun, relief, 以及 width 等參數在 ttk 版的 Slider 元件均不支援, 僅 length 可用, 例如 :
測試 8 : 用 length 參數設定滑桿長度 (ttk) [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_h(value): # 顯示水平滑桿值
label_h.config(text=value)
def show_value_v(value): # 顯示垂直滑桿值
label_v.config(text=value)
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x250")
scale_h=ttk.Scale(win, length=250) # 設定水平滑桿長度
scale_h["command"]=show_value_h # 使用 [] 運算子設定參數
scale_h.pack()
label_h=ttk.Label(win)
label_h.pack()
scale_v=ttk.Scale(win, length=150) # 設定垂直滑桿長度
scale_v["orient"]="vertical" # 使用 [] 運算子設定參數
scale_v.config(command=show_value_v) # 呼叫 config() 設定參數
scale_v.pack()
label_v=ttk.Label(win)
label_v.pack()
win.mainloop()
此例主要是測試 ttk 版 Slider 元件的 length 長度參數, 同樣也是使用了三種方式設定滑桿參數, 且在滑桿的滑動事件處理函式 show_value_h() 與 show_value_v() 中改用呼叫 Label 物件的 conffig() 方法來更新標籤文字, 結果如下 :
下面範例測試 showvalue 參數, 此參數 showvalue 只能在 tk 的 Scale 使用, ttk 不支援, 例如 :
測試 9 : 將 showvalue 設為 False 關閉 tk 滑桿自帶之數值顯示功能 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_v(value):
label_v.config(text=value)
def show_value_h(value):
label_h.config(text=value)
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x250")
scale_v=tk.Scale(win, showvalue=False, command=show_value_v) # 關閉數值顯示
scale_v.pack()
label_v=tk.Label(win)
label_v.pack()
scale_h=tk.Scale(win, orient="horizontal", command=show_value_h) # 預設開啟數值顯示
scale_h.pack()
label_h=tk.Label(win)
label_h.pack()
win.mainloop()
此例在建立垂直滑桿 scale_v 時將 showvalue 參數設為 False 關閉了數值顯示功能, 但透過添加的 Label 標籤元件同樣可顯示其值 (差別是這數值不會跟著滑桿的柄滑動), 而水平滑桿因為 tk 的 Scale 預設就是顯示數值, 不須設定 showvalue=Ture, 結果如下 :
測試 10 : 用 tickinterval 參數設定刻度單位並顯示滑桿刻度 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_h(value):
label_h.config(text=value)
def show_value_v(value):
label_v.config(text=value)
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x450")
scale_h=tk.Scale(win,
length=280,
orient="horizontal",
tickinterval=10,
command=show_value_h)
scale_h.pack()
label_h=tk.Label(win)
label_h.pack()
scale_v=tk.Scale(win,
length=280,
tickinterval=10,
command=show_value_v)
scale_v.pack()
label_v=tk.Label(win)
label_v.pack()
win.mainloop()
此例垂直與水平滑桿之 tickinterval 均設為 10, 表示刻度值將是 0, 10, 20, 30, .... 100, 但注意須配合使用 length 參數指定夠長的長度才能顯示期待之刻度, 結果如下 :
若將 length 設為 200 將不足以容納這些刻度而得到非預期的結果 :
以上 tk 滑桿滑動時預設滑動解析度步階是 1, 亦即滑桿滑動時數值跳動的間隔, 此步階可用 resolution 參數設定, 但只能在 tk 的滑桿使用, ttk 不支援此 resolution 參數, 例如 :
import tkinter as tk
from tkinter import ttk
def show_value_h(value):
label_h.config(text=value)
def show_value_v(value):
label_v.config(text=value)
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x450")
scale_h=tk.Scale(win,
length=280,
orient="horizontal",
tickinterval=10,
resolution=5,
command=show_value_h)
scale_h.pack()
label_h=tk.Label(win)
label_h.pack()
scale_v=tk.Scale(win,
length=280,
tickinterval=10,
resolution=20,
command=show_value_v)
scale_v.pack()
label_v=tk.Label(win)
label_v.pack()
win.mainloop()
此例兩個滑桿都設定了 resolution 參數, 同時也配合設定了 tickinterval 參數, 當 resolution 比 tickinterval 還小時, 刻度顯示不會受影響 (例如此例之水平滑桿, tickinterval=10, resolution=5, 刻度顯示仍以 tickinterval 為準); 但若 resolution 比 tickinterval 大時 (例如垂直滑桿刻度顯示 tickinterval 為 10, 但 resolution 為 20, 會以 resolution 為刻度顯示間隔), 刻度會以 resolution 為準, 結果如下 :
可見雖然垂直滑桿的 tickinterval 設為 10, 但因為 resolution 設為 20, 滑動一個步階就差 20, 因此刻度顯示 tickinterval 被忽視, 改以 resolution 為刻度單位.
下面測試 digits 參數, 用來設定滑桿數值之數字位數, 預設為 0, 表示不控制顯示位數, 若設為 5 表示控制顯示位數含整數與小數共 5 個數字, 要配合 from_, to, 與 resolution 參數使用才有意義. 例如 from_1=-10, to=10, resolution=5, 表示整數最多占 2 位, 小數應占 5-2=3 位, 故 resolution 應設 0.00x 比較有意義. 此參數僅 tk 有, ttk 不支援, 例如 :
測試 12 : 用 digits 參數設定 tk 滑桿值顯示數字位數 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_h(value):
label_h.config(text=value)
def show_value_v(value):
label_v.config(text=value)
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("400x450")
var=tk.StringVar()
scale_h=tk.Scale(win,
length=280,
orient="horizontal",
from_=-10.0,
to=10.0,
digits=5,
resolution=0.005,
command=show_value_h)
scale_h.pack()
label_h=tk.Label(win)
label_h.pack()
scale_v=tk.Scale(win,
length=280,
from_=-10.0,
to=10.0,
digits=4,
resolution=0.1,
command=show_value_v)
scale_v.pack()
label_v=tk.Label(win)
label_v.pack()
win.mainloop()
此例上方水平滑桿 digits 設 5, from_=-10, to=10, 整數占掉兩位, 小數剩三位, 故 resolution 要設到小數第三位 (例如此處 0.005) 較有意義, 若設 0.05 則小數第三位總是為 0 就變得冗餘了. 下方的垂直滑桿即是如此, digits 設 4, 表示小數位數有兩位, 但 resolution 設 0.1 就使得小數第二位總是為 0, 結果如下 :
最後來測試 label 參數, 它會在滑桿旁邊顯示一個標籤文字, 但是只能在 tk 使用, ttk 並不支援. 所以上面 tk 範例中用來顯示滑桿數值的 Label 元件其實可以用 Scale 自帶的 Label 來取代, 例如上面的測試 4 可以簡化為如下程式碼 :
測試 13 : 用 label 參數設定 tk 滑桿值顯示標籤內容 [看原始碼]
import tkinter as tk
from tkinter import ttk
def show_value_h1(value):
scale_h1.config(label=var_h1.get())
def show_value_h2(value):
scale_h2["label"]=value
def show_value_v(value):
scale_v.configure(label=scale_v.get())
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("300x300")
var_h1=tk.IntVar()
scale_h1=tk.Scale(win,
variable=var_h1,
orient="horizontal",
command=show_value_h1)
scale_h1.pack()
scale_h2=tk.Scale(win,
orient="horizontal",
command=show_value_h2)
scale_h2.pack()
scale_v=tk.Scale(win, command=show_value_v)
scale_v.pack()
win.mainloop()
此例是將上面測試 4 中的三個 Label 去除, 然後修改三個滑動是件處理函式, 使用 config() 與 configure() 方法以及 [] 運算子動態修改 label 參數值, 效果與測試 4 是一樣的, 結果如下 :
可見 lebel 參數所設定之標籤文字是在水平滑桿是顯示於左上方, 在垂直滑桿則是顯示在右上方, 此例它會跟自帶的數值標籤一樣動態顯示滑桿之值, 但不會隨柄移動.
下面 RGB 調色盤範例是把 label 參數拿來顯示固定提示訊息 :
測試 14 : 用 label 參數顯示固定提示訊息 [看原始碼]
import tkinter as tk
from tkinter import ttk
def change_color(value):
r=hex(scale_r.get())[2:]
g=hex(scale_g.get())[2:]
b=hex(scale_b.get())[2:]
if len(r) < 2: # 個位數顏色碼前面補 "0"
r += "0"
if len(g) < 2: # 個位數顏色碼前面補 "0"
g += "0"
if len(b) < 2: # 個位數顏色碼前面補 "0"
b += "0"
color="#" + str(r) + str(g) + str(b) # 組合完整 RGB 顏色碼
label.config(bg=color, text=color) # 更新 Label 元件底色
win=tk.Tk()
win.title("tkinter GUI 測試")
win.geometry("250x250")
scale_r=tk.Scale(win,
from_=0,
to=255,
label="R",
orient="horizontal",
command=change_color)
scale_r.set(0)
scale_r.grid(row=0, column=0)
scale_g=tk.Scale(win,
from_=0,
to=255,
label="G",
orient="horizontal",
command=change_color)
scale_g.set(0)
scale_g.grid(row=1, column=0)
scale_b=tk.Scale(win,
from_=0,
to=255,
label="B",
orient="horizontal",
command=change_color)
scale_b.set(0)
scale_b.grid(row=2, column=0)
label=tk.Label(win, bg="white", width=10, height=10)
label.grid(row=0, rowspan=3, column=1)
win.mainloop()
此例使用 grid 排版, 用來調整三原色 RGB 的三個水平 Scale 元件放在第一欄, 顯示顏色的 Label 放第二欄 (用 rospan=3 合併三列). 三個滑桿都用 label 參數分別設定了 R, G, B 的固定提示標籤文字, 數值範圍均為 0~255, 且 command 參數都是呼叫 change_color() 函式.
當任一滑桿滑動時會呼叫各滑桿的 get() 方法取得 0~255 現值, 然後傳給內建函式 hex() 將十進位數轉成十六進位字串, 但它前面會冠上 "0x" 例如 255 會轉成 "0xff", 這 "0x" 可用切片 [2:] 去除, 方便組成 bg 參數所需之顏色碼, 其完整格式為 "#rrggbb", 因此必須將個位數前面補 "0" 才能組合成完整顏色碼 (格式不完整會出現錯誤), 用來設定 Label 的底色與文字, 結果如下 :
只要滑動 RGB 滑桿右方的 Label 背景色就會立即動態改變.
參考:
沒有留言:
張貼留言