![](/img/trans.png)
[英]Tkinter, Python: How do I save text entered in the Entry widget? How do I move a label?
[英]how do you restrict the length of a tkinter text widget in python by blocking the latest character entered?
我试图以一种非常具体的方式限制 Python 中 tkinter 文本小部件或条目小部件(任一小部件类型都可以)中的字符数量。 我有一个接近文本小部件的解决方案:
string = self.text.get("1.0","end-1c")
if len(string) >= 5:
self.text.delete('1.0', "end-1c")
string = string[:-1]
self.quantity_entry.insert(END, string)
但是上面的代码做了以下事情:如果我输入 123456,它会将内容变成 12346。它将现有字段的最后一个字符 (5) 砍掉,然后将输入的最后一个字符 (6) 放在最后。 所以它变成了 12346。
我想要的是 12345 保持 12345,这意味着现有的 12345 字符串应保持原样,并且有效地阻止附加任何新字符。 有没有办法做到这一点?
我尝试使用:
self.text.configure(state="disabled")
这确实阻止了后续字符的插入,因此 12345 保持为 12345。但这会阻止将来编辑该字段。 即使随后尝试使用:
self.text.configure(state="normal")
该字段保持锁定状态。 如果用户达到五个字符的限制,我希望用户能够编辑该字段。
谢谢你。
跟踪变量将更加整洁。 然后它甚至不会在屏幕上短暂闪烁。 您可以将其打包为一个整洁的子类,如下所示:
import tkinter as tk
class Lotfi(tk.Entry):
def __init__(self, master=None, max_len=5, **kwargs):
self.var = tk.StringVar()
self.max_len = max_len
tk.Entry.__init__(self, master, textvariable=self.var, **kwargs)
self.old_value = ''
self.var.trace('w', self.check)
def check(self, *args):
if len(self.get()) <= self.max_len:
self.old_value = self.get() # accept change
else:
self.var.set(self.old_value) # reject change
#demo code:
window = tk.Tk()
ent=Lotfi(window, max_len=5)
ent.pack()
window.mainloop()
我想出了解决方案。 在.bind方法中,我需要使用
"<KeyRelease>"
而不是
"<Key>"
然后,作为次要编辑,需要将> = 5更改为>5。现在可以使用。 当我输入123456时,它非常简短地在屏幕上显示123456,但是随后很快将其切掉6,所以它又回到了12345。
我知道这很旧,但认为它可以帮助一些人。
一直在寻找一个非常优雅的解决方案来解决这个问题。 但是还没有找到。 所以我想我会发布我的凌乱的。
如果你觉得这很有用,请投票,如果你对我如何更清楚地沟通有想法,我也很乐意。
这是“一个”答案。 但是,如果您解释为什么选择编写您所做的代码会有所帮助,这样我就可以更好地指导您思考得出解决方案的方法。
# IMPORT MODULES AND ALIAS THEM
import tkinter as tk
# This is a place holder to self.quantity_entry.insert(END, string) just to
# simulate the call to some other object
def OtherTextWidget(string):
print( f"{text1.index(tk.END)}, {string}" )
# This is the 'meat' of your solution that limits the input
def Restrict(e=None):
print(e.type) # just to proof that we are pressing a key
# If for some unknown reason this function gets called on key-release, it will
# terminate the function. Because it will break our desired behavior.
if int(e.type) == 3:
return
# The 'widget.bind()' event argument pass a reference to the widget that
# called it. Se we use that here to get the text from the caller
# "text1.bind()" as event.widget.get() note we have aliased 'event' as 'e'
# inside the function space.
# Get text from start to the current end length minus the '\n' character
string = e.widget.get("1.0","end-1c")
# If there are 5 or more characters go ahead with the limit
# Note len() starts at 0, so 4<= is equal to 5+ chars
if 4 <= len(string):
# Get the first five characters before the delete
OtherTextWidget( e.widget.get("1.0","1.5") )
# !!NOTES!!
# We are lazy and don't want to code a rejection for a 6th character. So
# we overwrite the 5th character, the result is the same for less work.
# we are operating during the key press, and the 6th character is not
# inserted until the key release. The 5th character is empty if you
# debug it after the delete. Again the 5th character will be replaced
# by the 6th on the key release.
# delete the 5th character to the '\n', remember we are counting from 0.
e.widget.delete('1.4', "end-1c")
# TKINTER OBJECTS SETUP:
root = tk.Tk()
text1 = tk.Text(root, width=7, height=1) # 7 chars long, 1 char high
# We give the "entry box" 5 +2 extra character for aesthetics spacing.
# It just looks better with a little room to breath.
text1.pack() # fits the widget in the minimum space within the frame/window
text1.focus_set() # because I'm lazy and I want the cursor already in the widget.
# BIND TEXT WIDGET KEY INPUT EVENT:
# Whenever there is a key press inside the text widget this will fire the
# Restrict() function with the 'kepress event' argument
# That events data is in key:value pairs and looks something like this:
# <KeyPress event state=Mod1 keysym=1 keycode=97 char='1' x=1959 y=69>
text1.bind('<Key>', Restrict)
# start the tkinter event loop and open a toplevel window
root.mainloop()
# The '<Key>' gives a e.type of 2 or key press/down
# if you use '<KeyRelease>' it gives a e.type of 3 release/up and we will have to
# change some code around to make it work. But the important difference is it will
# place the 6th character in the field then delete it, that doesn't look crisp.
# This is why we are operating on a key press rather than release, because we want
# to operate on the string before the character is insert into the text widget.
为了清楚起见,这里是有限的注释代码。 (更新:我认为拥有实际显示的字符串会很好,因此添加了此发布切换来捕获它。)
import tkinter as tk
def OtherTextWidget(string):
print("Key Press Phase:", string)
# Solution - Step 1. toggle full flag
global full #(update)
full = False
# Solution - Step 4. profit
def AfterRestrict(e=None): #(update)
global full
if True == full:
OtherTextWidget( e.widget.get("1.0","1.5") )
print("Key Release Phase:", e.widget.get("1.0","1.5") )
# Solution - Step 3. limit input
def Restrict(e=None):
global full #(update)
string = e.widget.get("1.0","end-1c")
if 4 <= len(string):
e.widget.delete('1.4', "end-1c")
full = True #(update)
else: #(update)
full = False
root = tk.Tk()
text1 = tk.Text(root, width=7, height=1)
text1.pack()
text1.focus_set()
# Solution - Step 2. get input event from widget
text1.bind('<Key>', Restrict)
text1.bind('<KeyRelease>', AfterRestrict) #(update)
root.mainloop()
很抱歉冗长很累,但希望这对一些人有所帮助。 :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.