Python Forum
Function assigned at a button in tkinter
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Function assigned at a button in tkinter
#1
for y in range(0, pnumplayers):#third list of hands_inputs filled with fold button
    self.hands_inputs[2].append(Button(self.window, text='Fold', command = lambda: pplayers[y].fold(self.hands_inputs[0:3])))
In the above extract of my code I'm trying to fill a list of length
pnumplayer 
with tkinter button to then show them in window i previously created. The problem I encountered is that when I assign the function that's called when the button is pressed i want to assign different function to every button using this instruction:
pplayers[y].fold(self.hands_inputs[0:3])
where
pplayers 
is an array of object of type player I prevously created and at each button I want to assing the function fold for each player, however when I click on a given button it execute the same function though I checked and the string id of the commands are all different. Someone know how to solve this issue? Thanks in advance.
Reply
#2
Hmm... Are you printing the id of the method or of the button? I imagine the mapping to the button is likely causing the change in id since each button needs to be identified separately.
Reply
#3
Thanks for answering, by string id of the command I mean this output
print(self.hands_inputs[2][0:pnumplayer])
, and as I said in the post the ids are all different but the all link to the same position in the array pplayers (the one filled with player objects)
Reply
#4
Okay. If I understand you correctly, the button command is performing the same operation on the same player. In that case, what is self.hands_inputs? It's evidently a list but you're assigning the button as an item in it and using that same index as part of the argument to player.fold(). That suggests to me that player.fold() is operating on the same object in all cases.
Reply
#5
The list self.hands_inputs holds the buttons and pplayers is another list but that one holds player object, the player class has a method called fold, I'm trying to assign to
self.hands_inputs[2][0]
a button with a command that calls the fold function of the zeroth player. To do so I created the list pplayers (it's a parameter but it doesn't matter) that holds in each place a player object. In the for statement y ranges from 0 to let's say 5, so it should assing at each iteration
self.handsinputs[2][y]
a button with the command
pplayers.[y].fold(parameters)
Reply
#6
I get that, what isn't making sense is why self.hands_inputs the argument to player.fold() and also the list containing the resulting button. That method Shouldn't need all that information, especially since that information includes all the buttons for the previous players.

On a side note, range(pnumplayers) is superfluous. This would work easier by iterating over pplayers instead.

for y in pplayers:
    self.hands_inputs[2].append(Button(self.window, text='Fold', command = lambda: y.fold(self.hands_inputs[0:3])))
Reply
#7
Thanks for the side note. self.hands_inputs is the argument of player.fold() because fold is the function that's supposed to delete from the tkinter window (usinf the command widget.grid_forget()) some widget: the list phands_inputs is a list with 3 items, the first and the second one are filled with the names of the two cards in the hand of the player, the third item is filled with a list filled with button, so I pass the first 3 items of self.hands_inputs to then use them in the fold function inside a for statement to delete the widget from the window. More clearly, in the window I have let's say 5 rows: each one has two labels with the names of the two cards and a fold button, when I hit the fold button the line should disappear.

EDIT!!!!!:
I just noticed that using the for statement like I show in the code above the command tied to every button is alway referring to the last player (in the case I'm testing now the player with index 4), but if I do not use the for statement and do it the 'dummy' way, like that to be clear:
        
    self.hands_inputs[2].append(Button(self.window, text='Fold', command = lambda: pplayers[0].fold(self.hands_inputs[0:3])))
    self.hands_inputs[2].append(Button(self.window, text='Fold', command = lambda: pplayers[1].fold(self.hands_inputs[0:3])))
    self.hands_inputs[2].append(Button(self.window, text='Fold', command = lambda: pplayers[2].fold(self.hands_inputs[0:3])))
    self.hands_inputs[2].append(Button(self.window, text='Fold', command = lambda: pplayers[3].fold(self.hands_inputs[0:3])))
    self.hands_inputs[2].append(Button(self.window, text='Fold', command = lambda: pplayers[4].fold(self.hands_inputs[0:3])))
it works perfectly, but I need to do it with a for statement because the number of player is variable.
Reply
#8
I'm glad you got that working-ish.

There's a problem with responsibilities here. When the fold button is pressed, the row with the player's cards and the button needs to be removed from the presentation. So, the GUI needs to know what to present. However, the player does not need to know what's presented; the player only needs to know that it folded.

This is the Single Responsibility Principle. As Uncle Bob puts it: "A class should have one and only one reason to change." The GUI should change when a change needs to be made to the GUI but the Player should remain unchanged in that case.

If we separate the front-end presentation and the back-end data flow, we can likely clear up the problem.

class Player:
    self.folded = False
    
    def fold(self):
        self.folded = True

class Presentation:
    def player_folds(self, index, player): # index is for removing the correct row of data
        player.fold()
        ...hide or forget the presented data...
When a new hand is dealt, the Presentation will need new information from the players. I recommend the players contain and manage their information and have a method for providing that to a caller.
Reply
#9
Thanks for the answer, I kinda understood what I have to do. As soon as I find some time to test the solution and make it work I'll flag the discussion as solved.
Reply
#10
So I tried to create a separate class to hold all the front-end presentation but the problem is still the same: when I tie the function player_folds to the buttons I have to pass them a different index and a different player object and the button are still all tued to the function that should be tied at the last one.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  how to open a popup window in tkinter with entry,label and button lunacy90 1 810 Sep-01-2023, 12:07 AM
Last Post: lunacy90
  Tkinter button images not showing up lunacy90 7 1,466 Aug-31-2023, 06:39 PM
Last Post: deanhystad
Bug tkinter.TclError: bad window path name "!button" V1ber 2 725 Aug-14-2023, 02:46 PM
Last Post: V1ber
  Closing Threads and the chrome window it spawned from Tkinter close button law 0 1,670 Jan-08-2022, 12:13 PM
Last Post: law
  tkinter auto press button kucingkembar 2 3,084 Dec-24-2021, 01:23 PM
Last Post: kucingkembar
  How to assigned value to each different binary in python... ZYSIA 2 1,991 Jul-12-2021, 11:01 AM
Last Post: Gribouillis
  Partial using Tkinter function chesschaser 10 6,652 Jul-03-2020, 03:57 PM
Last Post: chesschaser
  Problem using a button with tkinter SmukasPlays 6 3,200 Jul-02-2020, 08:06 PM
Last Post: SmukasPlays
  Use a button in Tkinter to run a Python function Pedroski55 4 3,196 Jun-28-2020, 05:02 AM
Last Post: ndc85430
  assigned variable fails to show up Skaperen 4 2,314 May-27-2019, 10:48 AM
Last Post: Skaperen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020