Python Tkinker, checkbox append string value to list?

The following code allows me to add/remove France/Italy from a list when clicked on a tkinter checkbox. Rather than passing 0 or 1 to the Add_France function, is it possible to pass through a string "France"? Thanks

My_list = []

root = Tk()

Country_Variable1 = tkinter.IntVar()
Country_Variable2 = tkinter.IntVar()

def Add_France():
    if Country_Variable1.get() == 1:
        My_list.append("France")
    if Country_Variable1.get() == 0:
        My_list.remove("France")
    print (My_list)

def Add_Italy():
    if Country_Variable2.get() == 1:
        My_list.append("Italy")
    if Country_Variable2.get() == 0:
        My_list.remove("Italy")
    print (My_list)

check1 = Checkbutton(root, text='France',variable=Country_Variable1, onvalue=1, offvalue=0, command=Add_France)
check2 = Checkbutton(root, text='Italy',variable=Country_Variable2, onvalue=1, offvalue=0, command=Add_Italy)

check1.pack()
check2.pack()

root.mainloop()

Solution 1:

You have control over onvalue and offvalue with Checkbutton, so you can play around with the value that it returns in each state. In the below example, you can see how to make checkbutton based on inputs inside the list(assuming it is a list of strings of characters always):

from tkinter import *

root = Tk()

def process(var,text):
    try:
        val = int(var.get()) # If not selected it will give 0 as int, which will trigger `else` block
    except ValueError:
        val = var.get()

    if val: # if val is not empty, ie, if val is any selected value
        slct_ctry_lst.append(val)
    else: # if val is 0 
        slct_ctry_lst.remove(text) # Remove the corresponding text from the list

    print(slct_ctry_lst)

slct_ctry_lst = []
countries = ['France','Italy','China','Russia','India']

for idx,i in enumerate(countries):
    var = StringVar(value=" ")
    Checkbutton(root,text=i,variable=var,command=lambda i=i,var=var: process(var,i),onvalue=i).grid(row=0,column=idx)

root.mainloop()

Thought it would be easier, but maybe not suitable, with ttk.Combobox:

def process(e):
    val = e.widget.get()
    if val in slct_ctry_lst: # If val present inside the list
        slct_ctry_lst.remove(val) # Remove it
    else: 
        slct_ctry_lst.append(val)
    
    print(slct_ctry_lst)

slct_ctry_lst = []
countries = ['France','Italy','China','Russia','India']

cbox = ttk.Combobox(root,values=countries,state='readonly')
cbox.pack(padx=10,pady=10)
cbox.set('Select a country')

cbox.bind('<<ComboboxSelected>>',process)

Solution 2:

If the objective here is to make the code reusable for multiple countries, here is initial idea, this can be improved further. Basically, I am using lambda expression here to the callback command function and passing the country name. Created a separate function to create a checkbox which is generic for all the countries. Now to add a new country to the list all you need to do is add an element to the available_country_list You can make available_country_list global or can pass that as an argument to the list_countries function.

import tkinter
from tkinter import Checkbutton

selected_country_list = []


def select_country(country_name, variable):
    global selected_country_list
    print(variable)
    if variable.get() == 1:
        selected_country_list.append(country_name)
    elif variable.get() == 0:
        selected_country_list.remove(country_name)
    print (selected_country_list)


def create_checkbox(parent, country_name):
    country_var = tkinter.IntVar()
    country_check = Checkbutton(parent, text=country_name, variable=country_var,
                                onvalue=1, offvalue=0,
                                command=lambda: select_country(country_name, country_var))
    country_check.pack()


def list_countries(root):
    available_country_list = ["France", "Italy"]
    for country in available_country_list:
        create_checkbox(root, country)


def load(root):
    # Create list of country checkboxes
    list_countries(root)


def start():
    root = tkinter.Tk()
    root.after(100, load, root)  # Enable lazy loading of your components
    root.mainloop()


if __name__ == '__main__':
    start()