0

I'm trying to use tkinter buttons to remove elements from the list. When I click on button it removes the last element in the list instead of the one it should: characters.remove(character). I think I know why is this happening but I don't know how to fix that. Example:

column = 1
characters = ['c1', 'c2', 'c3']
for character in characters:
    Button(frame, text=character,
           command=lambda: (click_sound(), characters.remove(character))).grid(row=1, column=column)
    column += 1

Code:

        def submit(number, player_index, username, character):
            for widget in window_frame.winfo_children():
                widget.grid_forget()
            settings[f'player_{player_index}_username'] = username.capitalize()
            settings[f'player_{player_index}_character'] = character
            with open('resources/settings.json', 'w') as f:
                dump(settings, f, indent=3)
            player_index += 1
            if player_index > number:
                window.destroy()
                for widget in TkinterClass.main_frame.winfo_children():
                    widget.grid_forget()
                Button(TkinterClass.main_frame, text='Play', command=lambda: (PygameClass.click_sound(), startfile('Monopoly.py'), quit()), width=30).grid()
            else:
                character_index = 1
                Label(window_frame, text=f'Enter player\'s {player_index} name: ').grid(row=0, column=0)
                name = Entry(window_frame, borderwidth=3)
                name.grid(row=0, column=1, columnspan=len(characters))
                Label(window_frame, text='Select your character: ').grid(row=1, column=0)
                for character in characters:
                    Button(window_frame, text=character.capitalize(),
                           command=lambda: (
                           PygameClass.click_sound(), characters.remove(character),
                           submit(number, player_index, name.get(), character))).grid(row=1, column=character_index)
                    character_index += 1

        window = Toplevel()
        window.title('Monopoly')
        window_frame = Frame(window, padx=5, pady=5)
        window_frame.grid(padx=5, pady=5)
        player_index = 1
        column = 1
        characters = ['cruise', 'car', 'cap', 'derby']

        Label(window_frame, text=f'Enter player\'s {player_index} name: ').grid(row=0, column=0)
        name = Entry(window_frame, borderwidth=3)
        name.grid(row=0, column=1, columnspan=len(characters))
        Label(window_frame, text='Select your character: ').grid(row=1, column=0)
        for character in characters:
            Button(window_frame, text=character.capitalize(),
                   command=lambda: (PygameClass.click_sound(), characters.remove(character), submit(number, player_index, name.get(), character)))\
                .grid(row=1, column=character_index)
            column += 1
BokiX
  • 412
  • 2
  • 14

1 Answers1

0

You can try iterating through a copy of the original list, rather than iterating though the list and altering it in the process:

column = 1
characters = ['c1', 'c2', 'c3']
for character in characters.copy():
    Button(frame, text=character,
           command=lambda: (click_sound(), characters.remove(character))).grid(row=1, column=column)
    column += 1

Note that the only change is that for character in characters: got replaced with for character in characters.copy():.

Red
  • 26,798
  • 7
  • 36
  • 58
  • So you are trying to say that I should have two identical lists and remove things using index instead of strings to remove elements? – BokiX Jan 21 '22 at 14:07
  • @BokiX The first one yes, but you can use strings over indexes. – Red Jan 21 '22 at 14:07
  • Can you give me an example? – BokiX Jan 21 '22 at 14:08
  • @BokiX Does the code above work? If not, I can come up with something else. – Red Jan 21 '22 at 14:08
  • It doesn't work, it still removes the last element in the list – BokiX Jan 21 '22 at 14:10
  • @BokiX Do you get 3 buttons, or only one? – Red Jan 21 '22 at 14:11
  • I'm pretty sure that it is because it saves the last element in character variable or something after the loop is finished because it is going through elements. – BokiX Jan 21 '22 at 14:11
  • I get 3 buttons, and when I click one it removes the last button – BokiX Jan 21 '22 at 14:12
  • @BokiX You might want to follow the suggestion to use `copy()` of list, or just `for character in characters[:]:` and then follow the duplicate question in the comments. – Delrius Euphoria Jan 21 '22 at 14:13
  • I use more code that is shown here, it doesn't refresh here but I have a function that removes all widgets from the screen and is putting new ones except the last button cuz it gets removed every time I click on any button. – BokiX Jan 21 '22 at 14:14
  • Both `copy()` and `[:]` are not working for me. I should try with indexes I guess. – BokiX Jan 21 '22 at 14:16
  • @BokiX Does creating each button separately have the same bug? Try `Button(frame, text=character, command=lambda: (click_sound(), characters.remove("c1"))).grid(row=1, column=1)`, `Button(frame, text=character, command=lambda: (click_sound(), characters.remove("c2"))).grid(row=1, column=2)` and `Button(frame, text=character, command=lambda: (click_sound(), characters.remove("c3"))).grid(row=1, column=3)`. If it doesn't work, then it might not be the `for` loop's problem. – Red Jan 21 '22 at 14:16
  • It does work that way because you put specific element in `remove()`, I need to run that through `for` loop and have a variable that will be different for each button, the problem is even though buttons have been created, that variable will change ever time it goes trough that `for` loop. – BokiX Jan 21 '22 at 14:22
  • @BokiX Can you post enough code so that we can run it and see the problem you're describing? – Red Jan 21 '22 at 14:24
  • I've edited the post, try to run it. – BokiX Jan 21 '22 at 14:30
  • @BokiX Did you try out the duplicate question I marked, it is a clear duplicate. – Delrius Euphoria Jan 21 '22 at 14:31
  • Not really, I'm not trying to see how it works, I saw how it works, I need to find a solution to this specific problem with list elements, not `tkinter` buttons in loop. – BokiX Jan 21 '22 at 14:33
  • @BokiX But you are using tkinter... – Delrius Euphoria Jan 21 '22 at 14:34
  • @BokiX We need more code. The code you posted wouldn't do anything if we just ran it like that. Please include the import statements, the function call with the necessary parameters, etc. – Red Jan 21 '22 at 14:35