【tkinter】ttk.entryでバリデーションを設定する

ttk.entryのテキストボックスにバリデーションを設定します。
半角英数字のみ受け付けるよう設定します。

環境

python : 3.12.3
tkinter:8.6

コード

import re
import tkinter as tk
from tkinter import ttk

# 検証関数
def validate_half_width_alphanumeric(d, i, P, s, S, v, V, W) -> bool:
    print(f"d:{d}, i:{i}, P:{P}, s:{s}, S:{S}, v:{v}, V:{V}, W:{W}")
    # 空の場合も許可
    if P == "":
        return True
    # 半角英数字かチェック
    return bool(re.match("^[a-zA-Z0-9]+$", P))


# メインウィンドウの作成
root = tk.Tk()
root.title("Validation Example")
root.geometry("300x100")

# コールバック関数を登録
validate_command = (
    root.register(validate_half_width_alphanumeric),
    "%d",
    "%i",
    "%P",
    "%s",
    "%S",
    "%v",
    "%V",
    "%W",
)

# ttk.Entryの作成とバリデーションの設定
entry = ttk.Entry(root, validate="key", validatecommand=validate_command)
entry.pack(pady=10, padx=10)

# ウィンドウを表示
root.mainloop()

説明

ttk.Entryウィジェットを作成してvalidateに"key"を、validatecommandにコールバック関数validate_commandを渡します。

# ttk.Entryの作成とバリデーションの設定
entry = ttk.Entry(root, validate="key", validatecommand=validate_command)

validateではバリデーションのトリガーを指定でき、下記の値を設定できます。

説明
"none" バリデーション無効
"focus" ウィジェットにフォーカスが当たったとき、またはフォーカスが外れたとき
"focusin" ウィジェットにフォーカスが当たったとき
"focusout" ウィジェットからフォーカスが外れたとき
"key" キーボード入力
"all" 全てのトリガー("focusin"、"focusout"、"key")


validatecommandにはコールバック関数を設定します。
コールバック関数validate_commandは、第一引数に親ウィジェットのメソッドregisterを使用し、検証関数を登録します。今回はrootが親ウィジェットです。

# コールバック関数を登録
validate_command = (
    root.register(validate_half_width_alphanumeric),
    "%d",
    "%i",
    "%P",
    "%s",
    "%S",
    "%v",
    "%V",
    "%W",
)


第二引数には特殊引数を渡します。設定できるのは下記の値です。

説明
"%d" 変更の種類(0は削除、1は挿入)
"%i" 挿入または削除が発生する文字インデックス(0から始まる)
"%P" エントリウィジェットに設定される新しい値(入力後の内容)
"%s" 現在のエントリウィジェットの値(入力前の内容)
"%S" 挿入または削除される文字
"%v" validateオプションの現在の値(例: key, focusなど)
"%V" バリデーションイベントの種類(例: key, focusin, focusoutなど)
"%W" エントリウィジェットの名前(例: .entry1)

今回は"%P"を使用して、テキストボックスに入力した値に対してバリデーションを行います。



バリデーション関数です。空文字もしくは半角英数字の場合のみ受け付けるようにしています。

# 検証関数
def validate_half_width_alphanumeric(d, i, P, s, S, v, V, W) -> bool:
    print(f"d:{d}, i:{i}, P:{P}, s:{s}, S:{S}, v:{v}, V:{V}, W:{W}")
    # 空の場合も許可
    if P == "":
        return True
    # 半角英数字かチェック
    return bool(re.match("^[a-zA-Z0-9]+$", P))

1つ注意が必要で、バリデーション関数はbool型を返さないと正常に動きません。

例えば上記のreturnを「re.match("^[a-zA-Z0-9]+$", P)」にするとバリデーションが働かず、全角かなを入力できてしまいます。(re.matchはマッチオブジェクト、またはNoneを返す)

動作確認をしてみます。
半角英数字のみ受け付けるテキストボックスになっています。

この状態でQを入力してみるとバリデーションで弾かれて入力されません。
Qを入力したときの特殊変数は以下となります。
d:1
i:6
P:1111ssQ
s:1111ss
S:Q
v:key
V:key
W:.!entry

特殊変数Pで「1111ssQ 」が取得され、Qが全角のためにバリデーションにかかることで入力されていないことが確認できます。