Annie
Annie

Reputation: 11

How to make a menu widow within the for loop?

So I am trying to make a matrix 6x6 with buttons. When I right click on the a button, the menu window should pop up with a list of options. In this case, it's mix and escape. When I click on any of the two options, The corresponding E or M should display on the button that I created. But the problem is, when I right click on a button and select an option, the letter will only display on the last row and column of the matrix I have created, not the one I clicked on. I know that tkinker use mainloop that only change when event is happened. How do I make the menu window setup within the for loop so it knows the coordinate of the button I clicked. It seems like mainloop has done creating all the buttons before I right click, that's why the letter only display on the last element of the matrix. How do I solve this issue? thanks! enter image description here

for col in range(0,6):
        
            row_matrix = []
            for row in range(0,6):
                btn = tk.Button(frame2, bg = 'white', height =2, width= 4, command =lambda x = row, y = col: self.update(x,y), highlightthickness=0)
                btn.grid(row = row, column = col, padx=0, pady=0, sticky='e')

               

                popup = tk.Menu(master,tearoff=1)
                popup.add_separator()
                popup.add_command(label="Mix",command =lambda x=row, y=col:self.getM(x,y))
                popup.add_command(label="Escape",command =lambda x=row, y=col:self.getE(x,y))
                def menu_popup(event):
                    popup.tk_popup(event.x_root, event.y_root)

                btn.bind("<Button-2>",menu_popup)
                row_matrix.append(btn)  

            self._btn_matrix.append(row_matrix)
           
                    
    def getE(self,col,row):
            self._btn_matrix[col][row].config(text = "E")

    def getM(self,col,row):
        self._btn_matrix[col][row].config(text = "M")

Upvotes: 0

Views: 29

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 385910

Every time through your loop you are destroying and recreating the popup. Thus, the popup will always represent the last item in the loop.

The simplest solution is to move the definition of the popup and function outside of the loop, and pass in the row and column.

class Whatever():
...
        btn.bind("<Button-2>", lambda event, col=col, row=row: self.menu_popup(event, col, row))
...
    def menu_popup(self, event, col, row):
        popup = tk.Menu(self,tearoff=1)
        popup.add_separator()
        popup.add_command(label="Mix",command =lambda col=col, row=row:self.getM(col,row))
        popup.add_command(label="Escape",command =lambda col=col, row=row:self.getE(col, row))

        popup.tk_popup(event.x_root, event.y_root)
        popup.destroy()

Upvotes: 0

Related Questions