Home > Back-end >  How to limit the number of characters for several Entry widgets
How to limit the number of characters for several Entry widgets

Time:08-16

I am trying to limit the number of characters that can be input in a list of Entry widgets. I tried using the following:

def character_limit(entry_text):
    if len(entry_text.get()) > 0:
        entry_text.set(entry_text.get()[:10])

player_names = []

for i in range(num_players):
    player_names.append(tk.StringVar())
    player_names[i].trace("w", lambda *args: character_limit(player_names[i]))
    player_name_entry = tk.Entry(top, textvariable=player_names[i])
    player_name_entry.grid(row=i, column=0)

But this only limits the last Entry widget. How can I fix this?

CodePudding user response:

The looping problem is a very commonly seen problem and to fix it, you have to store the current value of the iteration within the lambda itself:

def character_limit(*args, entry_text):
    # if len(entry_text.get()) > 0: Can remove this line as it seems to not really be doing anything
    entry_text.set(entry_text.get()[:10])

for i in range(num_players):
    ...
    player_names[i].trace("w", lambda *args, i=i: character_limit(entry_text=player_names[i]))

The reason you use *args is because, trace passes 3 arguments to the function itself, that we don't need mostly.

But a more better method to do this will be to use validation for the entry widgets as this will prevent you needing to create a StringVar and trace its activity unnecessarily:

def character_limit(inp):
    if len(inp) > 10:
        return False
    
    return True

player_names = []
vcmd = (root.register(character_limit), '%P')
for i in range(num_players):
    player_name_entry = Entry(root, validate='key', validatecommand=vcmd)
    player_name_entry.grid(row=i, column=0)

    player_names.append(player_name_entry)

Read:

CodePudding user response:

The problem is not related to the widget. Variable i is not local to the lambda functions, so the last value of i is used for every function.

To create local variables change your lambda into:

player_names[i].trace("w", lambda *args, n=i: character_limit(player_names[n]))

For a good description see https://docs.python.org/3/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result

  • Related