Python 用“validatecommand”选项替换ttk.Entry小部件中的选定条目
下面的脚本创建了一个Python 用“validatecommand”选项替换ttk.Entry小部件中的选定条目,python,tkinter,Python,Tkinter,下面的脚本创建了一个ttk.Entry小部件,它只接受可以转换为浮点类型的条目。当我使用鼠标指针选择键入的条目,然后按new numeric entries(新的数字条目)时,我希望新的数字条目替换选定的条目。目前,这种行为并未发生。相反,新的数字条目将显示在所选数字的左侧。如何获得所需的替换行为 import tkinter as tk # python 3.x import tkinter.ttk as ttk # python 3.x class Example(ttk.Frame)
ttk.Entry
小部件,它只接受可以转换为浮点类型的条目。当我使用鼠标指针选择键入的条目,然后按new numeric entries(新的数字条目)时,我希望新的数字条目替换选定的条目。目前,这种行为并未发生。相反,新的数字条目将显示在所选数字的左侧。如何获得所需的替换行为
import tkinter as tk # python 3.x
import tkinter.ttk as ttk # python 3.x
class Example(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# %P = value of the entry if the edit is allowed
# %S = the text string being inserted or deleted, if any
vcmd = (self.register(self.onValidate),'%P', '%S')
self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
self.entry.pack(side="top", fill="x")
def onValidate(self, P, S):
# Disallow anything but '0123456789.+-'
if S in '0123456789.+-':
try:
float(P)
print('float(P) True')
return True
except ValueError:
print('float(P) False')
return False
else:
print('S in 0123456789.+- False')
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
更新:使用'
事件上的.bind
方法,我发现ttk.Entry
小部件中所选的键入条目可以通过.selection\u get()
方法获得。然而,我还没有弄清楚如何将这些方法联系起来以获得所需的行为
将这些句子附加到\uuuu init\uuu()
方法的末尾
self.entry.bind( '<ButtonRelease>', self.selecttext )
def selecttext(self, event):
try:
print( 'selection = ', self.entry.selection_get() )
except tk.TclError:
pass
self.entry.bind(“”,self.selecttext)
def selecttext(自我、事件):
尝试:
打印('selection=',self.entry.selection_get())
除了tk.TclError:
通过
我想分享我在下面得出的解决方案。我发现,当选择ttk.Entry
text字段中的字符串/子字符串时,tkinter将默认分两步执行验证。(1) 将所选字符串/子字符串视为要进行的第一次编辑。(2) 将按键输入视为要进行的第二次编辑。因此,validatecommand
将被调用两次。我还在脚本中添加了一些注释
import tkinter as tk # python 3.x
import tkinter.ttk as ttk # python 3.x
class Example(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# %P = value of the entry if the edit is allowed
# %S = the text string being inserted or deleted, if any
# %s = value of entry prior to editing
vcmd = (self.register(self.onValidate),'%P', '%S', '%s')
self.text = tk.StringVar()
self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
self.entry.pack(side="top", fill="x")
def onValidate(self, P, S, s):
# Disallow anything but '0123456789.+-'
selected = None
print('\nP={}, S={}, s={}'.format(P, S, s) )
try:
if S in '0123456789.+-' or float(S):
if self.entry.selection_present():
print('With Selection')
selected = self.entry.selection_get()
print('selected = ', selected )
# Notes:
# - When .selection_present()=True, I discovered that
# tkinter will return by default:
# P = s w/o 'selected'
# S = 'selected' and not the keypressed
# s = value of entry prior to editing.
# - I should "return True" so that tkinter will trigger method
# self.onValidate() again. This time,
# P = value of the entry if the keypress edit is allowed.
# S = the key pressed
# s = P from previous attempt.
# As such satisfy .selection_present()=False.
return True
else:
print('No Selection')
try:
float(P); print('True')
return True
except ValueError:
print(ValueError, 'float({}) False'.format(P))
return False
else:
print('S in 0123456789.+- False')
return False
except ValueError:
print('Try with Exception')
print(ValueError, 'float({}) False'.format(P))
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
更新:
下面的脚本显示了一个改进的算法,它只允许在tkinter条目
小部件中使用浮点型条目(包括带有指数的条目)。请用这个
优点:
.selection\u present()
方法,因为
它使用%d
,这是的固有回调替换代码
validatecommand
<代码>%d的值指示与删除(或选择)、插入和其他相关的场景(即“聚焦输入”、“聚焦输出”或“文本变量值的更改”)import tkinter as tk # python 3.x
import tkinter.ttk as ttk # python 3.x
class Example(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# %d = Type of action (1=insert, 0=delete, -1 for others)
# %P = value of the entry if the edit is allowed
# %S = the text string being inserted or deleted, if any
vcmd = (self.register(self.onValidate_Float), '%d','%P','%S')
self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
self.entry.pack(side="top", fill="x")
def onValidate_Float(self, d, P, S):
'''Allow only float type insertions (including exponents).
Notes: 1. The culminated insertions can fail to convert to a float.
This scenario occurs ONLY when the exponent entry is not
completed, i.e. when 'e-' and 'e+' are supplied only.
2. User of this method should remember that when they bind a
handle and '<KeyPress-Return>' to the tkinter Entry widget,
the handle can encounter error associated with processing
"float(numeric)" when numeric=1.4e- or 1.4e+ (as example).
3. I discovered that validatecommand uses %d to determine
the type of actions it take. As such, it is useful to
structure validatecommand instructions according to scenarios
d='0', d='1' and d='-1'.
'''
def _checkDecimal(P):
'''Return True when decimal does not occur in exponent.'''
decimal_index = P.find('.')
exponent_index = P.find('e')
if exponent_index > decimal_index:
return True
else:
return False
print('\nd={}, P={}, S={}'.format(d, P, S) )
if d == '0': #Delete Selection or keypress "Delete"/"Backspace"
print('Allow delete action regardless of keypress.')
return True
elif d == '1': #Insert keypress
print('d==1, Insert keypress.')
try:
if S in '0123456789e.+-':
float(P); print('True')
return True
else:
print('False')
return False
except ValueError:
print('float({}) ValueError.'.format(P))
if P.count('e')>1: return False
if P.count('e.')>0: return False
if P.count('-e')>0: return False
if P.count('+e')>0: return False
if P.find('e') == 0: return False
if P.count('.')>1: return False
if P[0]=="-":
print('P[0]=="-"')
if P.count("e-")>=1:
print('P.count("e-")>=1')
if P.count("-")>2: return False
if P.count("+")>0: return False
if not _checkDecimal(P): return False
elif P.count("e+")>=1:
print('P.count("e+")>=1')
if P.count("+")>1: return False
if P.count("-")>1: return False
if not _checkDecimal(P): return False
else:
print('no e- or e+')
if P.find('.') == 1: return False #disallow '-.'
if P.find('+') >= 1: return False #disallow '-+'
if P.find('-') >= 1: return False #disallow '--'
if P.count("-")>1: return False
if P.count("+")>1: return False
elif P[0]=="+":
print('P[0]=="+"')
if P.count("e-")>=1:
print('P.count("e-")>=1')
if P.count("-")>1: return False
if P.count("+")>1: return False
if not _checkDecimal(P): return False
elif P.count("e+")>=1:
print('P.count("e+")>=1')
if P.count("+")>2: return False
if P.count("-")>0: return False
if not _checkDecimal(P): return False
else:
print('no e- or e+')
if P.find('.') == 1: return False #disallow '+.'
if P.find('+') >= 1: return False #disallow '++'
if P.find('-') >= 1: return False #disallow '+-'
if P.count("-")>1: return False
if P.count("+")>1: return False
else:
print('P[0] is a number')
if P.count("e-")>=1:
print('P.count("e-")>=1')
if P.count("-")>1: return False
if P.count("+")>0 : return False
if not _checkDecimal(P): return False
elif P.count("e+")>=1:
print('P.count("e+")>=1')
if P.count("+")>1: return False
if P.count("-")>0: return False
if not _checkDecimal(P): return False
else:
print('no e- or e+')
if P.count("-")>0: return False
if P.count("+")>0: return False
return True #True for all other insertion exceptions.
elif d == '-1': #During focus in, focus out, or textvariable changes
print('d==-1, During focus in, focus out, or textvariable changes')
return True
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
将tkinter作为tk#python 3.x导入
将tkinter.ttk作为ttk#python 3.x导入
类示例(ttk.Frame):
定义初始化(自身,父级):
super()。\uuuu init\uuuu(父级)
#%d=操作类型(1=插入,0=删除,-1表示其他)
#%P=如果允许编辑,则该条目的值
#%S=正在插入或删除的文本字符串(如果有)
vcmd=(self.register(self.onValidate_Float)、“%d”、“P”、“S”)
self.entry=ttk.entry(self,validate=“key”,validatecommand=vcmd)
自进式包装(side=“top”,fill=“x”)
def onValidate_浮动(自身、d、P、S):
''只允许浮点类型插入(包括指数)。
注意:1.最终插入可能无法转换为浮点。
只有当指数项不可用时,才会出现这种情况
已完成,即仅提供“e-”和“e+”时。
2.此方法的用户应记住,当他们绑定
tkinter条目小部件的句柄和“”,
句柄可能会遇到与处理相关的错误
当数值=1.4e-或1.4e+(例如)时,“浮点(数值)”。
3.我发现validatecommand使用%d来确定
它所采取的操作类型。因此
根据场景对命令和指令进行结构验证
d='0',d='1'和d='1'-1'。
'''
def_checkDecimal(P):
''当指数中未出现小数时返回True''
十进制索引=P.find('.'))
指数=P.find('e')
如果指数指数>十进制指数:
返回真值
其他:
返回错误
打印('\nd={},P={},S={}'。格式(d,P,S))
如果d='0':#删除所选内容或按键“删除”/“退格”
打印('允许删除操作而不考虑按键')
返回真值
elif d=='1':#插入按键
打印('d==1,插入按键')
尝试:
如果在'0123456789e.+-'中:
浮点数(P);打印('True')
返回真值
其他:
打印('False')
返回错误
除值错误外:
打印('float({})ValueError.'.format(P))
如果P.count('e')>1:返回False
如果P.count('e')>0:返回False
如果P.count('-e')>0:返回False
如果P.count('+e')>0:返回False
如果P.find('e')==0:返回False
如果P.count('.')>1:返回False
如果P[0]=“-”:
打印('P[0]==“-”)
如果P.count(“e-”>=1:
打印('P.count(“e-”>=1'))
如果P.count(“-”)大于2:返回False
如果P.count(“+”)大于0:返回False
如果不是_checkDecimal(P):返回False
elif P.count(“e+”)>=1:
打印('P.count(“e+”)>=1')
如果P.count(“+”)大于1:返回False
如果P.count(“-”)大于1:返回False
如果不是_checkDecimal(P):返回False
其他:
打印('无e-或e+')
如果P.find('.')==1:返回False#disallow'-.'
import tkinter as tk # python 3.x
import tkinter.ttk as ttk # python 3.x
class Example(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# %P = value of the entry if the edit is allowed
vcmd = (self.register(self.onValidate),'%P')
self.entry = ttk.Entry(self, validate="key", validatecommand=vcmd)
self.entry.pack(side="top", fill="x")
def onValidate(self, P):
if P.strip() == "":
# allow blank string
return True
try:
float(P)
return True
except:
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()