Tkinter 元件詳解之Entry

Entry(輸入框)元件通常用於獲取使用者的輸入文字。

何時使用 Entry 元件?

Entry 元件僅允許用於輸入一行文字,如果用於輸入的字串長度比該元件可顯示空間更長,那內容將被滾動。這意味著該字串將不能被全部看到(你可以用滑鼠或鍵盤的方向鍵調整文字的可見範圍)。

如果你希望接收多行文字的輸入,可以使用 Text 元件(後面介紹)

用法

使用程式碼為 Entry 元件新增文字,可以使用 insert() 方法。如果要替換當前文字,可以先使用 delete() 方法,再使用 insert() 方法實現:

import tkinter as tk

master = tk.Tk()

e = tk.Entry(master)
e.pack(padx=20, pady=20)

e.delete(0, "end")
e.insert(0, "預設文字...")

master.mainloop()

獲取當前輸入框的文字,可以使用 get() 方法:

s = e.get()

你也可以繫結 Entry 元件到 Tkinter 變數(StringVar),並通過該變數設定和獲取輸入框的文字:

v = tk.StringVar()
e = tk.Entry(master, textvariable=v)
e.pack()

v.set("I love Python!")
s = v.get()

下邊的例子演示將 Entry 元件和 Button 元件配合,點選 “獲取資訊” 按鈕時自動清空輸入框並將內容輸出:

import tkinter as tk

master = tk.Tk()

tk.Label(master, text="作品:").grid(row=0)
tk.Label(master, text="作者:").grid(row=1)

e1 = tk.Entry(master)
e2 = tk.Entry(master)
e1.grid(row=0, column=1, padx=10, pady=5)
e2.grid(row=1, column=1, padx=10, pady=5)

def show():
    print("作品:《%s》" % e1.get())
    print("作者:%s" % e2.get())
    e1.delete(0, "end")
    e2.delete(0, "end")

tk.Button(master, text="獲取資訊", width=10, command=show).grid(row=3, column=0, sticky="w", padx=10, pady=5)
tk.Button(master, text="退出", width=10, command=master.quit).grid(row=3, column=1, sticky="e", padx=10, pady=5)

master.mainloop()

最後需要提到的是 Entry 元件允許通過以下幾種方式指定字元的位置:

  • 數字索引號
  • "anchoe"
  • "end"
  • "insert"
  • 滑鼠座標("@x")

數字索引號:常規的 Python 索引號,從 0 開始

"anchor":對應第一個被選中的字元(如果有的話)

"end":對應已存在文字的後一個位置

"insert":對應插入游標的當前位置

滑鼠座標("@x"):x 是滑鼠位置與 Entry 左側邊緣的水平距離,這樣就可以通過滑鼠相對地定位字元的位置

引數

Entry(master=None, **options) (class)

master -- 父元件

**options -- 元件選項,下方表格詳細列舉了各個選項的具體含義和用法:

選項 含義
background 1. 設定 Entry 的背景顏色
2. 預設值由系統指定
bg 跟 background 一樣
borderwidth 1. 設定 Entry 的邊框寬度
2. 預設值是 1 或 2 畫素
bd 跟 borderwidth 一樣
cursor 1. 指定當滑鼠在 Entry 上飄過的時候的滑鼠樣式
2. 預設值由系統指定
exportselection 1. 指定選中的文字是否可以被複制到剪貼簿
2. 預設值是 True
3. 可以修改為 False 表示不允許複製文字
font 1. 指定 Entry 中文字的字型
2. 預設值由系統指定
foreground 1. 設定 Entry 的文字顏色
2. 預設值由系統指定
fg 跟 foreground 一樣
highlightbackground 1. 指定當 Entry 沒有獲得焦點的時候高亮邊框的顏色
2. 預設值由系統指定
highlightcolor 1. 指定當 Entry 獲得焦點的時候高亮邊框的顏色
2. 預設值由系統指定
highlightthickness 1. 指定高亮邊框的寬度
2. 預設值是 1 或 2 畫素
insertbackground 指定輸入游標的顏色
insertborderwidth 1. 指定輸入游標的邊框寬度
2. 如果被設定為非 0 值,游標樣式會被設定為 RAISED
3. 小甲魚溫馨提示:將 insertwidth 設定大一點才能看到效果哦
insertofftime 1. 該選項控制游標的閃爍頻率(滅)
2. 單位是毫秒
insertontime 1. 該選項控制游標的閃爍頻率(亮)
2. 單位是毫秒
insertwidth 1. 指定游標的寬度
2. 預設值是 1 或 2 畫素
invalidcommand 1. 指定當輸入框輸入的內容“非法”時呼叫的函式
2. 也就是指定當 validateCommand 選項指定的函式返回 False 時的函式
3. 詳見本內容最下方小甲魚關於驗證詳解
invcmd 跟 invalidcommand 一樣
justify 1. 定義如何對齊輸入框中的文字
2. 使用 "left","right" 或 "center"
3. 預設值是 "left"
relief 1. 指定邊框樣式
2. 預設值是 "sunken"
3. 其他可以選擇的值是 "flat","raised","groove" 和 "ridge"
selectbackground 1. 指定輸入框的文字被選中時的背景顏色
2. 預設值由系統指定
selectborderwidth 1. 指定輸入框的文字被選中時的邊框寬度(選中邊框)
2. 預設值由系統指定
selectforeground 1. 指定輸入框的文字被選中時的字型顏色
2. 預設值由系統指定
show 1. 設定輸入框如何顯示文字的內容
2. 如果該值非空,則輸入框會顯示指定字串代替真正的內容
3. 將該選項設定為 "*",則是密碼輸入框
state 1. Entry 元件可以設定的狀態:"normal","disabled" 或 "readonly"(注意,它跟 "disabled" 相似,但它支援選中和拷貝,只是不能修改,而 "disabled" 是完全禁止)
2. 預設值是 "normal"
3. 注意,如果此選項設定為 "disabled" 或 "readonly",那麼呼叫 insert() 和 delete() 方法都會被忽略
takefocus 1. 指定使用 Tab 鍵可以將焦點移動到輸入框中
2. 預設是開啟的,可以將該選項設定為 False 避免焦點在此輸入框中
textvariable 1. 指定一個與輸入框的內容相關聯的 Tkinter 變數(通常是 StringVar)
2. 當輸入框的內容發生改變時,該變數的值也會相應發生改變
validate 1. 該選項設定是否啟用內容驗證 
2. 詳見本內容最下方小甲魚關於驗證詳解
validatecommand 1. 該選項指定一個驗證函式,用於驗證輸入框內容是否合法
2. 驗證函式需要返回 True 或 False 表示驗證結果
3. 注意,該選項只有當 validate 的值非 "none" 時才有效
3. 詳見本內容最下方小甲魚關於驗證詳解
vcmd 跟 validatecommand 一樣
width 1. 設定輸入框的寬度,以字元為單位
2. 預設值是 20
3. 對於變寬字型來說,元件的實際寬度等於字型的平均寬度乘以 width 選項的值
xscrollcommand 1. 與 scrollbar(滾動條)元件相關聯
2. 如果你覺得使用者輸入的內容會超過該元件的輸入框寬度,那麼可以考慮設定該選項
3. 使用方法可以參考:Scrollbar 元件

方法

delete(first, last=None) 

-- 刪除引數 first 到 last 範圍內(包含 first 和 last)的所有內容
-- 如果忽略 last 引數,表示刪除 first 引數指定的選項
-- 使用 delete(0, END) 實現刪除輸入框的所有內容

get()

-- 獲得當前輸入框的內容

icursor(index)

-- 將游標移動到 index 引數指定的位置
-- 這同時也會設定 INSERT 的值

index(index) 

-- 返回與 index 引數相應的選項的序號(例如 e.index(END))

insert(index, text) 

-- 將 text 引數的內容插入到 index 引數指定的位置
-- 使用 insert(INSERT, text) 將 text 引數指定的字串插入到游標的位置
-- 使用 insert(END, text) 將 text 引數指定的字串插入到輸入框的末尾

scan_dragto(x) 

--  見下方 scan_mark(x)

scan_mark(x)

-- 使用這種方式來實現輸入框內容的滾動
-- 需要將滑鼠按下事件繫結到 scan_mark(x) 方法(x 是滑鼠當前的水平位置),然後再將 <motion> 事件繫結到 scan_dragto(x) 方法(x 是滑鼠當前的水平位置),就可以實現輸入框在當前位置和 sacn_mack(x) 指定位置之間的水平滾動

select_adjust(index)
-- 與 selection_adjust(index) 相同,見下方解釋

select_clear()
-- 與 selection_clear() 相同,見下方解釋

select_from(index)
-- 與 selection_from(index) 相同,見下方解釋

select_present()
-- 與 selection_present() 相同,見下方解釋

select_range(start, end)
-- 與 selection_range(start, end) 相同,見下方解釋

select_to(index)
-- 與 selection_to(index) 相同,見下方解釋

selection_adjust(index)
-- 該方法是為了確保輸入框中選中的範圍包含 index 引數所指定的字元
-- 如果選中的範圍已經包含了該字元,那麼什麼事情也不會發生
-- 如果選中的範圍不包含該字元,那麼會從游標的位置將選中的範圍擴充套件至該字元

selection_clear()
-- 取消選中狀態

selection_from(index)
-- 開始一個新的選中範圍
-- 會設定 ANCHOR 的值

selection_present()
-- 返回輸入框是否有處於選中狀態的文字
-- 如果有則返回 True,否則返回 False

selection_range(start, end)
-- 設定選中範圍
-- start 引數必須必 end 引數小
-- 使用 selection_range(0, END) 選中整個輸入框的所有內容

selection_to(index)
-- 選中 ANCHOR 到 index 引數的間的所有內容

xview(index)
-- 該方法用於確保給定的 index 引數所指定的字元可見
-- 如有必要,會滾動輸入框的內容

xview_moveto(fraction)
-- 根據 fraction 引數給定的比率調整輸入框內容的可見範圍
-- fraction 引數的範圍是 0.0 ~ 1.0,0.0 表示輸入框的開始位置,1.0 表示輸入框的結束位置

xview_scroll(number, what)
-- 根據給定的引數水平滾動輸入框的可見範圍
-- number 引數指定滾動的數量,如果是負數則表示反向滾動
-- what 引數指定滾動的單位,可以是 UNITS 或 PAGES(UNITS 表示一個字元單元,PAGES 表示一頁)

關於驗證詳解

由於查看了不少資料,很多在這裡都沒有解釋清楚,所以這裡單獨列出來詳細講解下。

Entry 元件是支援驗證輸入內容的合法性的,比如要求輸入數字,你輸入了字母那就是非法。實現該功能,需要通過設定 validate、validatecommand 和 invalidcommand 選項。

 

首先啟用驗證的“開關”是 validate 選項,該選項可以設定的值有:

含義
'focus' 當 Entry 元件獲得或失去焦點的時候驗證
'focusin' 當 Entry 元件獲得焦點的時候驗證
'focusout' 當 Entry 元件失去焦點的時候驗證
'key' 當輸入框被編輯的時候驗證
'all' 當出現上邊任何一種情況的時候驗證
'none' 1. 關閉驗證功能
2. 預設設定該選項(即不啟用驗證)
3. 注意,是字串的 'none',而非 None

其次是為 validatecommand 選項指定一個驗證函式,該函式只能返回 True 或 False 表示驗證的結果。一般情況下驗證函式只需要知道輸入框的內容即可,可以通過 Entry 元件的 get() 方法獲得該字串。

下邊的例子中,在第一個輸入框輸入“CSDN” 並通過 Tab 鍵或者滑鼠將焦點轉移到第二個輸入框的時候,驗證功能被成功觸發:

import tkinter as tk

master = tk.Tk()

def test():
    if e1.get() == "CSDN":
        print("正確!")
        return True
    else:
        print("錯誤!")
        e1.delete(0, "end")
        return False

v = tk.StringVar()

e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=test)
e2 = tk.Entry(master)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)

master.mainloop()

然後,invalidcommand 選項指定的函式只有在 validatecommand 的返回值為 False 的時候才被呼叫。

下邊的例子中,在第一個輸入框輸入“csdn”,並通過 Tab 鍵將焦點轉移到第二個輸入框,validatecommand 指定的驗證函式被觸發並返回 False,接著 invalidcommand 被觸發:

import tkinter as tk

master = tk.Tk()

def test():
    if e1.get() == "CSDN":
        print("正確!")
        return True
    else:
        print("錯誤!")
        e1.delete(0, "end")
        return False

def test2():
    print("我被呼叫了......")
    return True

v = tk.StringVar()

e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=test, invalidcommand=test2)
e2 = tk.Entry(master)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)

master.mainloop()

最後,其實 Tkinter 還有隱藏技能,不過需要冷卻才能觸發,請聽我一一道來......

Tkinter 為驗證函式提供一些額外的選項:

額外選項 含義
'%d' 操作程式碼:0 表示刪除操作;1 表示插入操作;2 表示獲得、失去焦點或 textvariable 變數的值被修改
'%i' 1. 當用戶嘗試插入或刪除操作的時候,該選線表示插入或刪除的位置(索引號)
2. 如果是由於獲得、失去焦點或 textvariable 變數的值被修改而呼叫驗證函式,那麼該值是 -1
'%P' 1. 當輸入框的值允許改變的時候,該值有效
2. 該值為輸入框的最新文字內容
'%s' 該值為呼叫驗證函式前輸入框的文字內容
'%S' 1. 當插入或刪除操作觸發驗證函式的時候,該值有效
2. 該選項表示文字被插入和刪除的內容
'%v' 該元件當前的 validate 選項的值
'%V' 1. 呼叫驗證函式的原因
2. 該值是 'focusin','focusout','key' 或 'forced'(textvariable 選項指定的變數值被修改)中的一個
'%W' 該元件的名字

為了使用這些選項,你可以這樣寫:validatecommand=(f, s1, s2, ...)

其中,f 就是你“冷卻後”的驗證函式名,s1、s2、s3 這些是額外的選項,這些選項會作為引數依次傳給 f 函式。我們剛剛說了,使用隱藏技能前需要冷卻,其實就是呼叫 register() 方法將驗證函式包裝起來:

import tkinter as tk

master = tk.Tk()

v = tk.StringVar()

def test(content, reason, name):
    if content == "CSDN":
        print("正確!")
        print(content, reason, name)
        return True
    else:
        print("錯誤!")
        print(content, reason, name)
        return False

testCMD = master.register(test)
e1 = tk.Entry(master, textvariable=v, validate="focusout", validatecommand=(testCMD, '%P', '%v', '%W'))
e2 = tk.Entry(master)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)

master.mainloop()

當我故意輸入“CSDN我愛你”的時候,DUANG的一下,是錯誤的,後來我果斷刪除了“我愛你”,嘿,又正確了: