问题描述
我知道关于这方面的文档并不多,但是我想限制tkinter输入框中的输入。遵循在here上找到的一些代码,我目前正在这样做:
def float_only(self,S,d):
if d == '1': #insert
if not S in ['.','0','1','2','3','4','5','6','7','8','9']:
return False
return True
及更高版本:
mod_Box = tk.Toplevel(self.root)
self.priceVar = tk.StringVar(mod_Box)
self.priceVar.set('0.00')
vcmd = (mod_Box.register(self.float_only),'%s','%d')
priceEntry = tk.Entry(mod_Box,textvariable=self.priceVar,validate='key',validatecommand=vcmd)
这只允许使用小数和数字,但是我真的很想如果我能拥有它,那么按每个数字都将输入的数字放在最后一个小数位,然后将其余的数字向上移动,同时仍然只允许输入数字,例如收银机呢。例如,如果我输入2然后4然后0,则输入框将显示:
0.00-> 0.02-> 0.24-> 2.40
那么我就不需要允许小数点了(因此它们不能多次输入),这将是一个更加顺畅的体验。当然,当我说到现在的时候,我几乎不知道自己在做什么,所以将不胜感激。
解决方法
这是我的解决方法。
- 从
.
中删除pricevar.get()
并将其变成list
- 获取所按下键的
char
,并检查其是否为数字 - 如果是数字,请
append
到列表中 -
insert
小数从末尾回到列表的第二位 -
join
list
(不带0索引)并将其分配给pricevar.set
import tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.pricevar = tk.StringVar()
self.pricevar.set('0.00')
dflt = dict(width=5,font='Consolas 16 bold',insertontime=0)
self.priceEntry = tk.Entry(self,textvariable=self.pricevar,**dflt)
self.priceEntry.grid()
self.priceEntry.bind('<Key>',self.price)
def price(self,event):
o = list(self.pricevar.get().replace('.',''))
c = event.char
if c.isnumeric():
o.append(c)
o.insert(-2,'.')
self.pricevar.set(''.join(o[1:]))
return 'break'
if __name__ == '__main__':
app = App()
app.mainloop()
如果您想将其变成自己的小部件,则外观如下所示。在此示例中,我删除了StringVar
并直接设置了Entry
文本。我还包括一个重置按钮和一个标签。价格也有锁定,因此一旦“已满”,就不能再输入其他文本,除非将其重置。如果您在构造函数中更改了value
(例如value='00.00'
),它仍然可以正常工作,并且标签的大小将自动调整为适合value
import tkinter as tk
class PriceEntry(tk.Frame):
#focus in/out colors
FOC = '#FFFFFF'
FIC = '#DDDDFF'
def __init__(self,master,row=0,column=0,text='undefined',value='0.00'):
tk.Frame.__init__(self,master)
self.grid(row=row,column=column)
#price label
tk.Label(self,text=text,font='Calibri 12 bold').grid(row=0,padx=(6,2),pady=2)
#price entry
self.price = tk.Entry(self,background=PriceEntry.FOC,width=len(value),insertontime=0)
self.price.grid(row=0,column=1,padx=2,pady=2)
#insert start value
self.value = value
self.price.insert('end',value)
#capture all keypresses
self.price.bind('<Key>',self.keyHandler)
#since we turned the cursor off,use a different way to indicate focus
self.price.bind('<FocusOut>',self.indicate)
self.price.bind('<FocusIn>',self.indicate)
#price reset button
tk.Button(self,text=chr(10226),relief='flat',bd=0,font='none 12 bold',command=self.reset).grid(row=0,column=2)
def reset(self):
self.price.delete(0,'end') #delete old text
self.price.insert('end',self.value) #insert init value
def keyHandler(self,event):
o = list(self.price.get().replace('.','')) #remove decimal and return text as a list
if (c := event.char).isnumeric() and not int(o[0]): #if character is numeric and price isn't "full"
o.append(c) #append character to list
o.insert(-2,'.') #replace decimal
self.price.delete(0,'end') #delete old text
self.price.insert('end',''.join(o[1:])) #insert new text
return 'break' #stop further propagation
def indicate(self,event):
if str(event) == '<FocusOut event>':
self.price['background'] = PriceEntry.FOC
elif str(event) == '<FocusIn event>':
self.price['background'] = PriceEntry.FIC
class App(tk.Tk):
WIDTH,HEIGHT,TITLE = 800,600,'Price Busters'
def __init__(self):
tk.Tk.__init__(self)
#init widget at row0 column0
self.minimum = PriceEntry(self,'min')
#init widget at row0 column1 with a higher price potential
self.maximum = PriceEntry(self,1,'max','000.00')
if __name__ == '__main__':
app = App()
app.title(App.TITLE)
app.geometry(f'{App.WIDTH}x{App.HEIGHT}')
app.resizable(width=False,height=False)
app.mainloop()