1. ホーム
  2. python

[解決済み] tkinter の Entry ウィジェットの内容を対話的に検証する

2023-02-08 18:59:09

質問

tkinterのコンテンツを対話的に検証するために推奨されるテクニックは何ですか? Entry ウィジェットでインタラクティブにコンテンツを検証するために推奨されるテクニックは何ですか?

を使用することについての投稿を読みました。 validate=Truevalidatecommand=command を指定するとクリアされてしまうので、これらの機能は制限されているようです。 validatecommand コマンドが Entry ウィジェットの値を更新します。

この振る舞いを考えると KeyPress , Cut そして Paste イベントを監視・更新し Entry ウィジェットの値を監視・更新するのですか?(そして、私が見逃しているかもしれない他の関連するイベント?)

あるいは、インタラクティブなバリデーションを完全に忘れて FocusOut イベントでのみ検証すべきでしょうか?

どのように解決するのですか?

正解は validatecommand 属性を使うことです。残念ながら、この機能はTkの世界では十分に文書化されていますが、Tkinterの世界ではひどく文書化されていません。ドキュメントが不十分でも、バインディングやトレース変数に頼らずに検証を行ったり、検証手順の中からウィジェットを修正したりするために必要なものはすべて揃っています。

トリックは、Tkinterがvalidateコマンドに特別な値を渡すことができることを知っていることです。これらの値は、データが有効かどうかを決定するために知る必要のあるすべての情報を提供します: 編集前の値、編集が有効である場合の編集後の値、および他のいくつかの情報です。しかし、これらを使用するには、これらの情報をvalidateコマンドに渡すために、ちょっとした魔術を使う必要があります。

注意: バリデーションコマンドは、以下のどちらかを返すことが重要です。 True または False . それ以外の場合は、ウィジェットのバリデーションがオフになります。

ここでは、小文字のみを許可する例を示します。また、説明のためにすべての特殊な値の値を表示しています。これらはすべて必要ではありません。1つか2つ以上必要になることはほとんどありません。

import tkinter as tk  # python 3.x
# import Tkinter as tk # python 2.x

class Example(tk.Frame):

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        # valid percent substitutions (from the Tk entry man page)
        # note: you only have to register the ones you need; this
        # example registers them all for illustrative purposes
        #
        # %d = Type of action (1=insert, 0=delete, -1 for others)
        # %i = index of char string to be inserted/deleted, or -1
        # %P = value of the entry if the edit is allowed
        # %s = value of entry prior to editing
        # %S = the text string being inserted or deleted, if any
        # %v = the type of validation that is currently set
        # %V = the type of validation that triggered the callback
        #      (key, focusin, focusout, forced)
        # %W = the tk name of the widget

        vcmd = (self.register(self.onValidate),
                '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
        self.entry = tk.Entry(self, validate="key", validatecommand=vcmd)
        self.text = tk.Text(self, height=10, width=40)
        self.entry.pack(side="top", fill="x")
        self.text.pack(side="bottom", fill="both", expand=True)

    def onValidate(self, d, i, P, s, S, v, V, W):
        self.text.delete("1.0", "end")
        self.text.insert("end","OnValidate:\n")
        self.text.insert("end","d='%s'\n" % d)
        self.text.insert("end","i='%s'\n" % i)
        self.text.insert("end","P='%s'\n" % P)
        self.text.insert("end","s='%s'\n" % s)
        self.text.insert("end","S='%s'\n" % S)
        self.text.insert("end","v='%s'\n" % v)
        self.text.insert("end","V='%s'\n" % V)
        self.text.insert("end","W='%s'\n" % W)

        # Disallow anything but lowercase letters
        if S == S.lower():
            return True
        else:
            self.bell()
            return False

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

を呼び出したときにボンネットの下で何が起こるかについての詳細は、 この章で説明します。 register メソッドを呼び出したときに起こることについては なぜtkinterの入力検証ではregister()を呼び出す必要があるのですか?

標準的なドキュメントは Tcl/Tk Entry man pageのValidationセクションを参照してください。