0

I have a loop that creates buttons from a list. I've been able to get it to create the buttons and return values when clicked. I'm running into an issue on changing the other button options such as enabling and disabling the button. The code that I have just disables the last button in the list regardless of which one was clicked. I have tried a number of fixes, listed below, but they either just don't plain work or they "work" but don't function as a normal button does in things like hover and enable/disable.

Any and all help will be appreciated.

Create a list or dictionary of Tkinter buttons to use in different frames

tkinter creating buttons in for loop passing command arguments

https://www.geeksforgeeks.org/looping-through-buttons-in-tkinter/#

Python: Assign commnds to buttons using a for loop when using Tkinter,

Here's my code

import customtkinter

class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        bn = 0

        schedule_list = ["On", "Off", "NA"]
        button_dict = {}

# create scrollable frame

        self.scrollable_frame = customtkinter.CTkScrollableFrame(self, width=750, height=385)
        self.scrollable_frame.grid(row=0, column=0, sticky="nsew")
        self.scrollable_frame.grid_columnconfigure(0, weight=1)
        self.scrollable_frame_switches = []

#   setup the schedule list

        c = 0
        l = 0
        r = 0

        for j in range(3):
            bn += 1
    # create the buttons
            self.button = customtkinter.CTkButton(self.scrollable_frame, command=lambda bn=bn: self.button_event(bn))
            self.button.grid(row=r, column=c, padx=20, pady=(10, 10))
            self.button.configure(text=schedule_list[l])
            self.scrollable_frame_switches.append(self.button)

            l += 1
            c += 1


    def button_event(self,button_num):

        self.button.configure(state="disabled")

        print(button_num)

#      if buttonNum == 1:

if __name__ == "__main__":
    app = App()
    app.mainloop()

*Update

I figured it out. Had to change the following code:

self.button = customtkinter.CTkButton(self.scrollable_frame, command=lambda bn=bn: self.button_event(bn))

to

self.button = customtkinter.CTkButton(self.scrollable_frame, command=lambda bn=bn: self.button_event(bn,self.scrollable_frame_switches))

Then change the button_event from

def button_event(self, button_num):
        self.button_change.configure(state="disabled")

#      if buttonNum == 1:

to

def button_event(self, button_num, switches):
        button_change=self.scrollable_frame_switches[button_num]
        button_change.configure(state="disabled")
        self.scrollable_frame_switches.append(button_change)

Not an elegant way to do it, but it works. Thanks for the guidance all.

Greg W
  • 31
  • 6
  • 2
    Each time through the loop you reassign `self.button`. When the loop is done, it contains the last button. – Barmar Aug 18 '23 at 00:39
  • All your lambdas use the same `bn` variable, you don't get a different scope for each iteration. See https://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture for how to solve this. – Barmar Aug 18 '23 at 00:42
  • Once you solve that, put the buttons in a list, and use the parameter as the index. – Barmar Aug 18 '23 at 00:43
  • 1
    You have already a list (`self.scrollable_frame_switches`) storing those buttons, use the list and the index to disable the required button. – acw1668 Aug 18 '23 at 00:47
  • self.scrollable_frame_switches D'oh. – Greg W Aug 18 '23 at 03:35
  • You don't need to pass `self.scrollable_frame_swithces` to `self.button_event()`. Also why do you append `button_change` to `self.scrollable_frame_switches`? Finally `button_num` starts from 1, but index for a *list* starts from 0. – acw1668 Aug 18 '23 at 03:54
  • Took both of them out, thanks, it's late and I'm tired. The button_num has been fixed. Again, many thanks. – Greg W Aug 18 '23 at 04:15

0 Answers0