如何通过阻止输入的最新字符来限制python中的tkinter文本小部件的长度?

时间:2018-08-24 02:54:48

标签: python text tkinter widget

我正在尝试以一种非常特定的方式来限制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")

该字段保持锁定状态。我希望用户如果达到五个字符的限制,就能够编辑该字段。

谢谢。

3 个答案:

答案 0 :(得分:1)

跟踪变量将更加整洁。然后它甚至不会在屏幕上短暂闪烁。您可以将其打包为一个整洁的子类,如下所示:

<?php 
session_start();
error_reporting(0);
$user=$_SESSION['user'];
$right=$_SESSION['right'];
if($user==true){
?>

答案 1 :(得分:0)

我想出了解决方案。在.bind方法中,我需要使用

"<KeyRelease>"

而不是

"<Key>"

然后,作为一个较小的编辑,> = 5需要更改为>5。现在可以使用了。当我输入123456时,它会非常短暂地在屏幕上显示123456,但是随后很快将其切掉6,因此它又回到了12345。是的!

答案 2 :(得分:0)

我知道这很旧,但我认为它可以帮助一些人。

一直在寻找一个非常优雅的解决方案来解决这个问题。但是还没有找到。所以我想我会发布我的凌乱的。

如果你觉得这有用,请投票,如果你对我如何更清晰地沟通有想法,我也很乐意。

这是“一个”答案。但是,如果您解释为什么选择编写您所做的代码会有所帮助,这样我就可以更好地指导您思考得出解决方案的方法。

# 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()

很抱歉我很累,但希望这对一些人有所帮助。 :)