Mal*_*olm 74 python validation textbox tkinter
在tkinter Entry
小部件中交互式验证内容的推荐技术是什么?
我已经阅读了关于使用validate=True
和的帖子validatecommand=command
,并且看起来这些功能受限于它们在validatecommand
命令更新Entry
小部件的值时被清除的事实.
鉴于这种行为,我们应该绑定的KeyPress
,Cut
以及Paste
事件和监视/更新我们的Entry
小部件的价值,通过这件事情?(以及我可能错过的其他相关事件?)
或者我们是否应该完全忘记交互式验证并仅对FocusOut
事件进行验证?
Bry*_*ley 186
正确答案是,使用validatecommand
小部件的属性.不幸的是,这个特征在Tkinter世界中严重缺乏记录,尽管在Tk世界中有足够的记录.尽管它没有很好地记录,但它具有您需要进行验证所需的一切,而无需借助绑定或跟踪变量,或者在验证过程中修改小部件.
诀窍是要知道你可以让Tkinter将特殊值传递给validate命令.这些值为您提供了确定数据是否有效所需的所有信息:编辑前的值,编辑后编辑后的值以及其他几个信息.但是,要使用这些,您需要执行一些voodoo以将此信息传递给validate命令.
注:这是很重要的验证命令返回无论是True
或False
.其他任何操作都会导致窗口小部件的验证被关闭.
这是一个只允许小写的示例(并打印所有那些时髦的值):
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()
Run Code Online (Sandbox Code Playgroud)
use*_*793 11
在研究和试验Bryan的代码之后,我制作了一个最小版本的输入验证.以下代码将显示一个Entry框并仅接受数字.
from tkinter import *
root = Tk()
def testVal(inStr,acttyp):
if acttyp == '1': #insert
if not inStr.isdigit():
return False
return True
entry = Entry(root, validate="key")
entry['validatecommand'] = (entry.register(testVal),'%P','%d')
entry.pack()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
也许我应该补充一点,我仍在学习Python,我很乐意接受任何和所有意见/建议.
使用a Tkinter.StringVar
来跟踪Entry小部件的值.您可以StringVar
通过设置a 来验证其值trace
.
这是一个简短的工作程序,只接受Entry小部件中的有效浮点数.
from Tkinter import *
root = Tk()
sv = StringVar()
def validate_float(var):
new_value = var.get()
try:
new_value == '' or float(new_value)
validate.old_value = new_value
except:
var.set(validate.old_value)
validate.old_value = ''
# trace wants a callback with nearly useless parameters, fixing with lambda.
sv.trace('w', lambda nm, idx, mode, var=sv: validate_float(var))
ent = Entry(root, textvariable=sv)
ent.pack()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
定义一个返回布尔值的函数,该布尔值指示输入是否有效。
将其注册为 Tcl 回调,并将回调名称作为validatecommand
.
例如:
import tkinter as tk
def validator(P):
"""Validates the input.
Args:
P (int): the value the text would have after the change.
Returns:
bool: True if the input is digit-only or empty, and False otherwise.
"""
return P.isdigit() or P == ""
root = tk.Tk()
entry = tk.Entry(root)
entry.configure(
validate="key",
validatecommand=(
root.register(validator),
"%P",
),
)
entry.grid()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
参考。
在研究Bryan Oakley 的答案时,我发现可以开发一个更通用的解决方案。以下示例介绍了模式枚举、类型字典和用于验证目的的设置函数。请参阅第 48 行,了解示例用法及其简单性演示。
#! /usr/bin/env python3
# /sf/ask/289830621/
import enum
import inspect
import tkinter
from tkinter.constants import *
Mode = enum.Enum('Mode', 'none key focus focusin focusout all')
CAST = dict(d=int, i=int, P=str, s=str, S=str,
v=Mode.__getitem__, V=Mode.__getitem__, W=str)
def on_validate(widget, mode, validator):
# http://www.tcl.tk/man/tcl/TkCmd/ttk_entry.htm#M39
if mode not in Mode:
raise ValueError('mode not recognized')
parameters = inspect.signature(validator).parameters
if not set(parameters).issubset(CAST):
raise ValueError('validator arguments not recognized')
casts = tuple(map(CAST.__getitem__, parameters))
widget.configure(validate=mode.name, validatecommand=[widget.register(
lambda *args: bool(validator(*(cast(arg) for cast, arg in zip(
casts, args)))))]+['%' + parameter for parameter in parameters])
class Example(tkinter.Frame):
@classmethod
def main(cls):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Validation Example')
cls(root).grid(sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
def __init__(self, master, **kw):
super().__init__(master, **kw)
self.entry = tkinter.Entry(self)
self.text = tkinter.Text(self, height=15, width=50,
wrap=WORD, state=DISABLED)
self.entry.grid(row=0, column=0, sticky=NSEW)
self.text.grid(row=1, column=0, sticky=NSEW)
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
on_validate(self.entry, Mode.key, self.validator)
def validator(self, d, i, P, s, S, v, V, W):
self.text['state'] = NORMAL
self.text.delete(1.0, END)
self.text.insert(END, 'd = {!r}\ni = {!r}\nP = {!r}\ns = {!r}\n'
'S = {!r}\nv = {!r}\nV = {!r}\nW = {!r}'
.format(d, i, P, s, S, v, V, W))
self.text['state'] = DISABLED
return not S.isupper()
if __name__ == '__main__':
Example.main()
Run Code Online (Sandbox Code Playgroud)
小智 5
Bryan 的回答是正确的,但是没有人提到 tkinter 小部件的“invalidcommand”属性。
一个很好的解释在这里:http : //infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html
在链接断开的情况下复制/粘贴文本
Entry 小部件还支持一个 invalidcommand 选项,该选项指定每当 validatecommand 返回 False 时调用的回调函数。此命令可以通过使用小部件关联的文本变量上的 .set() 方法来修改小部件中的文本。设置此选项的工作方式与设置验证命令相同。您必须使用 .register() 方法来包装您的 Python 函数;此方法以字符串形式返回包装函数的名称。然后,您将作为 invalidcommand 选项的值传递该字符串,或者作为包含替换代码的元组的第一个元素。
注意:只有一件事我不知道该怎么做:如果向条目添加验证,并且用户选择文本的一部分并键入新值,则无法捕获原始值并重置入口。这是一个例子
归档时间: |
|
查看次数: |
57005 次 |
最近记录: |