-2

I am facing a problem with tkinter checkboxes.

So it goes like this: The user should be able to check multiple check-buttons, while the way I have coded this allows for only one check to be active at the time. I'd also like check boxes to not be checked by default and that doesn't happen even though I've set the offvalue at None. I also want the button function to check for the right inputs (i.e. make sure at least one of the check-boxes has been ticked, along with which ones have been ticked). Furthermore, I wanted to make the window to close only after at least one checkbox has been ticked by the user pressing the button, hence the enter_data_close() function.

After closing the window I'd like it to immediately call other functions depending on the check box selection. Python version: 3.11.1 IDE: VSCodium

import tkinter
from tkinter import *
from tkinter import ttk
from tkinter import messagebox

def enter_data_close():
    global fatigue_type

        try:
            if not fatigue_type.get():
                tkinter.messagebox.showwarning(title="Selection Error!", message="Please select at least one fatigue case!")
        except Exception as ex:
            tkinter.messagebox.showwarning(title="Error!", message=ex)

        window.destroy()

    else:
        tkinter.messagebox.showwarning(title="Error", message="Provide values for all entry boxes!")

#GUI 

window = tkinter.Tk()
window.title("Dimensions Data Entry")
window.resizable(0,0)

frame = tkinter.Frame(window)
frame.pack()

def disable_event():
    pass
window.protocol("WM_DELETE_WINDOW", disable_event)

#FATIGUE CASE

fatigue_type_frame =tkinter.LabelFrame(frame, text="Fatigue Type")
fatigue_type_frame.grid(row= 0, column=1, padx=20, pady=10)

fatigue_type_option=["Tension", "Compression"]

fatigue_type=StringVar()

for index in range(len(fatigue_type_option)):
    check_button= Checkbutton(fatigue_type_frame, 
    text=fatigue_type_option[index], 
    variable=fatigue_type, 
    onvalue=fatigue_type_option[index], 
    offvalue=None, 
    padx=20, 
    pady=10)

for widget in fatigue_type_frame.winfo_children():
    widget.grid_configure(padx=10, pady=5)

# ENTER DATA AND CLOSE BUTTON
button = tkinter.Button(frame, text="Enter Data", command=enter_data_close)
button.grid(row=3, column=0, sticky="news", padx=20, pady=10)

window.mainloop()

1 Answers1

0

The problem with your checkbuttons is that they all use the same variable. Since they all use the same variable, they will always all have the same value. For checkbuttons to work, each checkbutton needs its own variable.

An easy way to do this is to use a dictionary or list to store the variable instances.

The following example uses a dictionary, where the keys are the fatigue types (Tension, Compression) and the values are the variables.

fatigue_vars = {}
for fatigue_type in fatigue_type_option:
    var = StringVar(value="")
    fatigue_vars[fatigue_type] = var
    check_button= Checkbutton(
        fatigue_type_frame,
        text=fatigue_type,
        variable=var,
        onvalue=fatigue_type,
        offvalue="",
        padx=20,
        pady=10
    )

Later, when you need the selected checkboxes, you can iterate over the dictionary and pull out the keys that have a non-empty value:

fatigue_keys = [key for key, var in fatigue_vars.items() if var.get()]

If both checkbuttons are checked, you'll get a list with two values: ['Tension', 'Compression']. If only one is checked, you'll get a list of one value: ['Tension'] or ['Compression']. If none are checked, you'll get an empty list: [].

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685