Tkinter Checkedbox in python is returning False for all Machines eventhough boxes are checked

Question:

I created a tkinter checkedbox to receive input from user to see which machines from date_and_time_dictionary they want to delete. You then press a tkinter button "Print Checkbox States" and if a box was checked the program will print out the machine and the word "True" next to it and "False" otherwise. Even though some or all boxes are checked, I still get back all False for every machine.

date_and_time_dictionary = {'S120': {'Setup Start Time': 'March 28, 2023 1:55 PM', 'Loaded in Program': 'March 28, 2023 1:56 PM', 'Setup End Time': 'April 5, 2023 1:24 PM', 'Pending F/A (At-risk) Start': 'April 5, 2023 1:24 PM', 'Pending F/A (At-risk) End': 'April 7, 2023 11:51 AM'}, 'S109': {'Setup Start Time': 'April 3, 2023 9:56 AM', 'Setup End Time': 'April 4, 2023 4:59 AM'}, 'S112': {'Setup Start Time': 'April 5, 2023 7:03 AM', 'Loaded in Program': 'April 5, 2023 9:31 AM', 'Setup End Time': 'April 11, 2023 8:49 AM', 'Pending F/A (At-risk) Start': 'April 11, 2023 8:49 AM'}, 'S117': {'Setup Start Time': 'April 5, 2023 1:24 PM', 'Loaded in Program': 'April 5, 2023 1:28 PM', 'No QIP Available': 'April 6, 2023 10:20 AM', 'Setup End Time': 'April 6, 2023 3:25 PM', 'Pending F/A (At-risk) Start': 'April 6, 2023 3:25 PM', 'Pending F/A (At-risk) End': 'April 10, 2023 8:11 AM'}, 'S113': {'Setup Start Time': 'April 5, 2023 12:53 PM', 'Loaded in Program': 'April 6, 2023 6:42 AM', 'No QIP Available': 'April 5, 2023 1:02 PM', 'Setup End Time': 'April 11, 2023 5:57 AM'}, 'S101': {'Setup Start Time': 'April 4, 2023 9:25 AM', 'Setup End Time': 'April 6, 2023 6:11 AM'}, 'S119': {'Setup Start Time': 'April 7, 2023 9:13 AM', 'Loaded in Program': 'April 7, 2023 10:02 AM', 'Waiting For F/A Approval': 'April 11, 2023 8:48 AM', 'Setup End Time': 'April 10, 2023 3:32 PM', 'Pending F/A (At-risk) Start': 'April 10, 2023 3:32 PM'}, 'S111': {'Setup Start Time': 'April 3, 2023 9:30 AM', 'Waiting For F/A Approval': 'April 10, 2023 6:25 AM', 'Setup End Time': 'April 10, 2023 6:32 AM'}, 'S106': {'Setup Start Time': 'April 7, 2023 9:06 AM', 'Setup End Time': 'April 11, 2023 6:14 AM', 'Pending F/A (At-risk) Start': 'April 11, 2023 6:14 AM'}}


def delete_old_after_action_report_times():    
    # Create a Tkinter window
    root = tkinter.Tk()
    root.geometry("400x300")
    # Create a Text widget
    text_box = tkinter.Text(root)

    # Add some text to the widget
    Label(root, text ='Select which machine(s) you would like to delete?:').place(x = 65, y = 0)

    y_val = 20

    # Create a dictionary to store the state of each checkbox
    checkbox_states = {}

    # Iterate through the dictionary and create a Checkbutton for each key
    for key in date_and_time_dictionary.keys():
        var = tkinter.BooleanVar()  # Create a BooleanVar to store the checkbox state
        chk = tkinter.Checkbutton(root, text=key, variable=var)
        # chk.pack()  # Pack the Checkbutton into the window
        chk.place(x=175, y=y_val)
        y_val += 20

        # Add the checkbox state to the dictionary
        checkbox_states[key] = var

        # Add a button to print the state of each checkbox
    def print_checkbox_states():
        for key, var in checkbox_states.items():
            print(f"{key}: {var.get()}")


    button = tkinter.Button(root, text="Print Checkbox States", command=print_checkbox_states)
    button.place(x=150, y=y_val+20)
    

    root.mainloop()

What I tried and got back was:
S120: False
S109: False
S112: False
S117: False
S113: False
S101: False
S119: False
S111: False
S106: False

What I expected to get back if S120, S109, and S111 were selected was:
S120: True
S109: True
S112: False
S117: False
S113: False
S101: False
S119: False
S111: True
S106: False

Asked By: Alan Perez

||

Answers:

The way I create my buttons is by looping through each key in my date_and_time_dictionary. My program only references the last one I created, which it saves as self.key. When I call print_checkbox_states(), it only checks this button’s value. One way around this is to save all the references to these Buttons in a dictionary:

date_and_time_dictionary = {'S120': {'Setup Start Time': 'March 28, 2023 1:55 PM', 'Loaded in Program': 'March 28, 2023 1:56 PM', 'Setup End Time': 'April 5, 2023 1:24 PM', 'Pending F/A (At-risk) Start': 'April 5, 2023 1:24 PM', 'Pending F/A (At-risk) End': 'April 7, 2023 11:51 AM'}, 'S109': {'Setup Start Time': 'April 3, 2023 9:56 AM', 'Setup End Time': 'April 4, 2023 4:59 AM'}, 'S112': {'Setup Start Time': 'April 5, 2023 7:03 AM', 'Loaded in Program': 'April 5, 2023 9:31 AM', 'Setup End Time': 'April 11, 2023 8:49 AM', 'Pending F/A (At-risk) Start': 'April 11, 2023 8:49 AM'}, 'S117': {'Setup Start Time': 'April 5, 2023 1:24 PM', 'Loaded in Program': 'April 5, 2023 1:28 PM', 'No QIP Available': 'April 6, 2023 10:20 AM', 'Setup End Time': 'April 6, 2023 3:25 PM', 'Pending F/A (At-risk) Start': 'April 6, 2023 3:25 PM', 'Pending F/A (At-risk) End': 'April 10, 2023 8:11 AM'}, 'S113': {'Setup Start Time': 'April 5, 2023 12:53 PM', 'Loaded in Program': 'April 6, 2023 6:42 AM', 'No QIP Available': 'April 5, 2023 1:02 PM', 'Setup End Time': 'April 11, 2023 5:57 AM'}, 'S101': {'Setup Start Time': 'April 4, 2023 9:25 AM', 'Setup End Time': 'April 6, 2023 6:11 AM'}, 'S119': {'Setup Start Time': 'April 7, 2023 9:13 AM', 'Loaded in Program': 'April 7, 2023 10:02 AM', 'Waiting For F/A Approval': 'April 11, 2023 8:48 AM', 'Setup End Time': 'April 10, 2023 3:32 PM', 'Pending F/A (At-risk) Start': 'April 10, 2023 3:32 PM'}, 'S111': {'Setup Start Time': 'April 3, 2023 9:30 AM', 'Waiting For F/A Approval': 'April 10, 2023 6:25 AM', 'Setup End Time': 'April 10, 2023 6:32 AM'}, 'S106': {'Setup Start Time': 'April 7, 2023 9:06 AM', 'Setup End Time': 'April 11, 2023 6:14 AM', 'Pending F/A (At-risk) Start': 'April 11, 2023 6:14 AM'}}

checkbox_states = {}
checkbox_list = []

# Add a button to print the state of each checkbox
def print_checkbox_states():
    for key in checkbox_states:
        if checkbox_states[key].get():
            checkbox_list.append(key)
    return 

def delete_old_after_action_report_times():
    root = Tk()
    root.geometry("400x300")
    # # Create a Text widget
    # text_box = tkinter.Text(root)

    # Add some text to the widget
    Label(root, text ='Select which machine(s) you would like to delete?').place(x = 70, y = 0)

    y_val = 20
    
    for key in date_and_time_dictionary:
        is_selected = BooleanVar()
        checkbutton = Checkbutton(text=key, variable=is_selected)
        checkbutton.place(x=175, y=y_val)
        y_val += 20
        checkbox_states[key] = is_selected


    #checkbutton.pack()

    testbutton = Button(text='check test', command=print_checkbox_states)
    testbutton.place(x=165, y=y_val+20)
    
    root.mainloop() 

I took print_checkbox_states() out of delete_old_after_action_report_times(). I also moved checkbox_states outside of the function and made it a global variable dictionary. Then I made a global variable list checkbox_list. I fill in the checkbox_states dictionary in delete_old_after_action_report_times(), so that I can track whether a button has been selected or not. It’s easy to reference this table, because the keys are the items themselves. I then put the keys in a list to access later to know which machines I want to delete.

Answered By: Alan Perez