我想验证两个tkinter条目。一个称为最小值,另一个称为最大值。当然,我要确保最小值不超过最大值。还有第三个条目,称为增量,必须小于最大值。我正在尝试验证一组15个此类条目。
我尝试使用for循环并跟踪每个条目的textvariable。但是在for循环中,我只能验证单个输入框。另外,当我跳过对名为txtCab的特定条目的验证时,它会引发以下异常:如果我对所有小部件都进行了验证,则它确实可以工作,但有时会失败。
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\beejb\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\PROSAIL_5B_Fortran\PROSAIL_5B_FORTRAN\PROSAIL.py", line 191, in min_max
minVar = eval("self.txtVar_"+ str(wid)+ "_min.get()")
File "<string>", line 1, in <module>
NameError: name 'self' is not defined
我使用的验证功能是:
def min_max(*args):
alltextFields = ["N","Cab","Car","Cw","Cm","Cbrown", "rsoil0","LIDFa","LIDFb","TypeLIDF","LAI","hspot","tts","tto","psi" ]
for wid in alltextFields:
if eval("self." + wid + "_variable.get()"):
minVar = eval("self.txtVar_"+ str(wid)+ "_min.get()")
maxVar = eval("self.txtVar_"+ str(wid) + "_max.get()")
rangeVar = eval("self.txtVar_"+ str(wid) + "_range.get()")
##
## print((minVar))
## print((maxVar))
## print((rangeVar))
if len(minVar) > 0 and len(maxVar):
if (minVar) > (maxVar):
messagebox.showinfo("Input Error", "Minimum should not be greater than maximum")
if len(rangeVar) > 0 and len(maxVar) > 0:
if (rangeVar) > (maxVar) :
messagebox.showinfo("Input Error", "Increment cannot exceed maximum limit")
## print(self.txtVar_Cab_min.get()); print(self.txtVar_Cab_max.get());
## print(self.txtVar_N_min.get()); print(self.txtVar_N_max.get());
if len(self.txtVar_Cab_min.get()) > 0 and len(self.txtVar_Cab_max.get()) > 0 and len(self.txtVar_Cab_range.get()) > 0:
if (self.txtVar_Cab_min.get()) > (self.txtVar_Cab_max.get()):
messagebox.showinfo("Input Data Error", "Minimum should not be greater than maximum!!")
if (self.txtVar_Cab_range.get()) > (self.txtVar_Cab_max.get()):
messagebox.showinfo("Error", "Increment cannot exceed maximum!!")
我尝试过的另一个验证功能是:
def validateMRM(self,value, text,W):
vMin,vMax,vRange;
entry = self.controller.nametowidget(W)
print(entry)
if entry == self.txt_N_min:
print(entry.get())
print(self.txtVar_N_max.get())
print(self.txtVar_N_range.get())
alltextFields = ["txt_N","txt_Cab","txt_Car","txt_Cab","txt_Cw","txt_Cw","txt_Cm","txt_Cbrown","txt_Cm", "txt_rsoil0",
"txt_LIDFa","txt_LIDFb","txt_TypeLIDF","txt_LAI","txt_hspot","txt_hspot","txt_tts","txt_tto","txt_psi"
]
for wid in alltextFields:
typeOfVar = wid.split("_")
if entry == eval("self.txt_" + str(typeOfVar[1])+ "_min"):
vMin = eval("self.txtVar_" + str(typeOfVar[1])+ "_min.get()")
print(eval("self.txtVar_" + str(typeOfVar[1])+ "_min.get()"))
vMax = eval("self.txtVar_" + str(typeOfVar[1])+ "_max.get()")
print(eval("self.txtVar_" + str(typeOfVar[1])+ "_max.get()"))
vRange = eval("self.txtVar_" + str(typeOfVar[1])+ "_range.get()")
print(eval("self.txtVar_" + str(typeOfVar[1])+ "_range.get()"))
print(vMin); print(vMax); print(vRange)
if len(vMin) > 0 and len(vMax) > 0 and len(vRange) > 0:
if (vMin) > (vMax):
messagebox.showinfo("Error", "Minimum cannot be greater than maximum")
if (vRange) > (vMax) :
messagebox.showinfo("Error", "Increment cannot exceed the maximum limit")
print(len(entry.get()))
if len(entry.get())>2:
这是所有条目的创建方式:
self.lbl_N = tk.Label(self,text="Structure Coefficient(N)",anchor="w",width=40,bg='white'); self.lbl_N.grid(row=3,column=4,padx=4,pady=4);
self.N_variable = tk.BooleanVar()
self.chk_N = tk.Checkbutton(self,variable=self.N_variable, command=lambda:self.show_hide()); self.chk_N.grid(row=3,column=6,padx=4,pady=4);
self.txt_N = tk.Entry(self,width=10,validate = 'key', validatecommand = vcmd); self.txt_N.grid(row=3,column=7,padx=4,pady=4);
self.txtVar_N_min = tk.StringVar(); self.txtVar_N_max = tk.StringVar(); self.txtVar_N_range = tk.StringVar();
self.txtVar_N_min.trace("w", min_max); self.txtVar_N_max.trace("w", min_max); self.txtVar_N_range.trace("w", min_max);
self.txt_N_min = tk.Entry(self,width=5,validate = 'key',textvariable=self.txtVar_N_min, validatecommand = vcmd_min_max);
self.txt_N_max = tk.Entry(self,width=5,validate = 'key', textvariable=self.txtVar_N_max,validatecommand = vcmd_min_max);
self.txt_N_range = tk.Entry(self,width=5,validate = 'key', textvariable=self.txtVar_N_range,validatecommand = vcmd_min_max);
一共有14个这样的条目,我需要对其进行验证。
但是这些都没有给出我想要的实际输出。它有时会工作,而有时会失败。 我不确定为什么会这样,我花了很多时间进行验证。
答案 0 :(得分:0)
我不确定这是否能回答您的问题,但这应该为您指明正确的方向。
我对您的代码不太了解。我制作了一个15行x 4列的网格。 第4列是一则消息,指示其旁边的3个字段为“确定”,否则显示为问题。验证在每个按键的整个网格上运行。如果太慢,可以使用验证按钮启动验证。
import tkinter as tk
from tkinter import ttk
def rec(): return {'lo': 0, 'hi': 0, 'step': 0, 'ok': '' }
root = tk.Tk()
root.title('SO Question')
def entry(id, ent_dict, var_dict, v=0):
""" Add an Entry Widget to the root, with associated StringVar."""
var_dict[id] = tk.StringVar()
var_dict[id].set(str(v))
ent_dict[id] = ttk.Entry(root, textvariable= var_dict[id], width = 10 )
return ent_dict[id]
def do_validate(lo, hi, step):
""" Return OK if lo, hi and step are consistent else an error string. """
if lo < hi and step < hi: return 'OK'
txt = ''
if lo >= hi:
txt = 'lo >= hi. '
if step >= hi:
txt += 'step >= hi.'
return txt
def conv(txt):
""" Convert text to float. Return 0.0 if not valid float e.g "" or 'a' """
try:
return float(txt)
except ValueError:
return 0.0
def oklabel(ent_dict, var_dict):
""" Add an OK Label to a row. """
lo = conv(var_dict['lo'].get())
hi = conv(var_dict['hi'].get())
step = conv(var_dict['step'].get())
var_dict['ok'] = tk.StringVar()
var_dict['ok'].set(do_validate(lo, hi, step))
ent_dict['ok'] = ttk.Label(root, textvariable = var_dict['ok'], width = -17)
return ent_dict['ok'] # Return the Label object for gridding.
def do_check(*args):
""" Loop through the rows setting the validation string in each one. """
for var_dict in stringvars:
lo = conv(var_dict['lo'].get())
hi = conv(var_dict['hi'].get())
step = conv(var_dict['step'].get())
var_dict['ok'].set(do_validate(lo, hi, step))
# Add column labels
ttk.Label(root, text='Minimums').grid(row=0, column=0)
ttk.Label(root, text =' Maximums').grid(row=0, column=1)
ttk.Label(root, text='Increment').grid(row=0, column=2)
ttk.Label(root, text='Valid').grid(row=0, column=3)
# Create containers for he Entries and Stringvars
entries =[]
stringvars = []
# Add 15 rows of Entries / Validation Labels to the UI.
for row in range(1, 16):
tempe=rec()
tempv=rec()
entry('lo', tempe, tempv, 0).grid(row = row, column=0)
entry('hi', tempe, tempv, 0).grid(row = row, column=1)
entry('step', tempe, tempv, 0).grid(row = row, column=2)
oklabel(tempe, tempv).grid(row = row, column = 3)
entries.append(tempe)
stringvars.append(tempv)
# Bind do_check to all Entry widgets.
root.bind_class('TEntry', '<KeyPress>', do_check, add='+')
root.bind_class('TEntry', '<BackSpace>', do_check, add='+')
root.bind_class('TEntry', '<Delete>', do_check, add='+')
root.mainloop()
过去,我一直在尝试通过不允许不一致的条目来验证多个字段。用户很难按照要求更正字段。他们必须以正确的顺序工作。例如lo = 100,hi = 9,step =1。UI是否应允许删除100中的最后一个零,而保留gt 9是10?
只有在所有行都正确的情况下,才能将其扩展为激活“下一步”按钮。
编辑1-对评论的回复
这具有创建和激活显示的每一行的功能。每行都有自己的变量和检查功能。它们是由三个Entry StringVars上的跟踪触发的,无需使用验证。
import tkinter as tk
from tkinter import ttk
def to_float(txt):
""" Safely convert any string to a float. Invalid strings return 0.0 """
try:
return float(txt)
except ValueError:
return 0.0
def row_n( parent, n, init_show = 0 ):
""" Create one row of the display. """
# tk.Variables
v_show = tk.IntVar()
v_min = tk.StringVar()
v_max = tk.StringVar()
v_incr = tk.StringVar()
v_message = tk.StringVar()
# Initialise variables
v_min.set('0')
v_max.set('1')
v_incr.set('1') # Can the increment be zero?
v_show.set(init_show)
v_message.set("OK")
def do_trace(*args):
""" Runs every time any of the three Entries change value.
Sets the message to the appropriate text.
"""
lo = to_float(v_min.get())
hi = to_float(v_max.get())
inc = to_float(v_incr.get())
if lo < hi and inc <=hi:
v_message.set('OK')
else:
txt = ''
if lo >= hi:
txt += 'Min >= Max'
if inc > hi:
if len(txt): txt += ' & '
txt += 'Incr > Max'
v_message.set(txt)
# Set trace callback for changes to the three StringVars
v_min.trace('w', do_trace)
v_max.trace('w', do_trace)
v_incr.trace('w', do_trace)
def activation(*args):
""" Runs when the tickbox changes state """
if v_show.get():
e_min.grid(row = n, column = 1)
e_max.grid(row = n, column = 2)
e_inc.grid(row = n, column = 3)
message.grid(row = n, column = 4)
else:
e_min.grid_remove()
e_max.grid_remove()
e_inc.grid_remove()
message.grid_remove()
tk.Checkbutton(parent,
text = 'Structure Coefficient {} :'.format(n),
variable = v_show, command = activation ).grid(row = n, column = 0)
e_min = tk.Entry(parent, width=5, textvariable = v_min)
e_max =tk.Entry(parent, width=5, textvariable = v_max)
e_inc = tk.Entry(parent, width=5, textvariable = v_incr)
message = tk.Label(parent, width=-15, textvariable = v_message)
activation()
return { 'Min': v_min, 'Max': v_max, 'Inc': v_incr }
def show_results():
print('Min Max Inc')
for row in rows:
res = '{} {} {}'.format(row['Min'].get(), row['Max'].get(), row['Inc'].get())
print( res )
root = tk.Tk()
root.title('SO Question')
ttk.Label(root, text='Minimums').grid(row=0, column=1)
ttk.Label(root, text =' Maximums').grid(row=0, column=2)
ttk.Label(root, text='Step', width = 5 ).grid(row=0, column=3)
ttk.Label(root, text='Valid', width = 15 ).grid(row=0, column=4)
rows = []
for r in range(1,16):
rows.append(row_n(root, r, init_show=r%3 == 0 ))
tk.Button(root, command=show_results, text = ' Show Results ').grid(column=1, pady = 5)
root.mainloop()
这是另一种方法。这有帮助吗?
答案 1 :(得分:0)
这是另一个建议。将标签和条目合并到第n行功能中。在激活功能中包括激活/禁用条目。通过所需的描述列表循环执行row_n函数。
import tkinter as tk
row_names = [ "Structure Coefficient(N)", "Chlorophyll Content(Cab) (µg.cm-2)",
"Carotenoid content(Car) (µg.cm-2)", "Brown pigment content(Cbrown)(arbitrary units)"]
def row_n(parent, desc, n, init_show = 0 ):
""" Create one row of the display. """
# tk.Variables
v_show = tk.IntVar()
v_min = tk.StringVar()
v_max = tk.StringVar()
v_incr = tk.StringVar()
v_fixed = tk.StringVar() # New StringVar
v_message = tk.StringVar()
v_show.set(init_show)
v_message.set("OK")
def do_trace(*args):
""" Runs every time any of the three Entries change value.
Sets the message to the appropriate text.
"""
lo = to_float(v_min.get())
hi = to_float(v_max.get())
inc = to_float(v_incr.get())
if lo < hi and inc <=hi:
v_message.set('OK')
else:
txt = ''
if lo >= hi:
txt += 'Min >= Max'
if inc > hi:
if len(txt): txt += ' & '
txt += 'Incr > Max'
v_message.set(txt)
# Set trace callback for changes to the three StringVars
v_min.trace('w', do_trace)
v_max.trace('w', do_trace)
v_incr.trace('w', do_trace)
def activation(*args):
""" Runs when the tickbox changes state """
if v_show.get():
e_min.grid(row = n, column = 8)
e_max.grid(row = n, column = 9)
e_inc.grid(row = n, column = 10)
message.grid(row = n, column = 11)
e_fixed.config(state = 'disabled') # Disable the base Entry
else:
e_min.grid_remove()
e_max.grid_remove()
e_inc.grid_remove()
message.grid_remove()
e_fixed.config(state = 'normal') # Enable the base Entry Widget
tk.Label(parent, text = desc ).grid(row = r+1, column = 4 ) # Add the desc. Label
e_fixed = tk.Entry(parent, textvariable = v_fixed) # Add the new Entry widget
e_fixed.grid(row = r+1, column = 5)
tk.Checkbutton(parent,
text = ' '.format(n),
variable = v_show, command = activation ).grid(row = n, column = 6)
e_min = tk.Entry(parent, width=5, textvariable = v_min)
e_min.config(font=('Candara', 15))
e_max =tk.Entry(parent, width=5, textvariable = v_max)
e_max.config(font=('Candara', 15))
e_inc = tk.Entry(parent, width=5, textvariable = v_incr)
e_inc.config(font=('Candara', 15))
message = tk.Label(parent, width=-15, textvariable = v_message)
message.config(font=('Candara', 15))
activation()
return { 'Min': v_min, 'Max': v_max, 'Inc': v_incr, 'Fixed': v_fixed }
# The 'Fixed' field added to the dictionary to return
def print_row(row):
fmt = 'Min: {}, Max: {}, Inc: {}, Fixed: {}'
print(fmt.format(
row['Min'].get(), row['Max'].get(), row['Inc'].get(), row['Fixed'].get()
))
def to_float(txt):
""" Safely convert any string to a float. Invalid strings return 0.0 """
try:
return float(txt)
except ValueError:
return 0.0
# GUI Start
root = tk.Tk()
root.title('Validation wth Trace')
# Header Labels
tk.Label(root,text="Min").grid(row=0,column=8,padx=4,pady=4)
tk.Label(root,text="Max").grid(row=0,column=9,padx=4,pady=4)
tk.Label(root,text="Inc").grid(row=0,column=10,padx=4,pady=4)
# Body of rows
rows = []
for r, r_text in enumerate(row_names):
rows.append(row_n( root, r_text, r+1))
root.mainloop()
print("Strings in the Entry fields")
for r, row in enumerate(rows):
print('Row: ', r, 'Data:', end=' ')
print_row(row)
HTH。在墨水问题中查看代码,您可能希望将row_n设为类。