0

I tried to create a multiple checkboxes and get the information whether they are checked or not. I tried to use tkinter for this purpose. The number of checkboxes would be variable. Up to now, I found a way to create the checkboxes with the following code. With this, 10 checkboxes are created at which people can tick any of them

class Example(tk.Frame):
    def __init__(self, root, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)
        self.root = root

        self.vsb = tk.Scrollbar(self, orient="vertical")
        self.text = tk.Text(self, width=40, height=20, 
                            yscrollcommand=self.vsb.set)
        self.vsb.config(command=self.text.yview)
        self.vsb.pack(side="right", fill="y")
        self.text.pack(side="left", fill="both", expand=True)
        
        n=10
        for i in range(n):
            cb = tk.Checkbutton(self, text="Modul %s" % i)
            self.text.window_create("end", window=cb)
            self.text.insert("end", "\n")

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

However, the information are not saved in any variable. If I add variable to be dumped in the cb, the code will check every checkboxes. The edited code section is as follow (sorry that I couldn't highlight the addition):

class Example(tk.Frame):
    def __init__(self, root, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)
        self.root = root

        self.vsb = tk.Scrollbar(self, orient="vertical")
        self.text = tk.Text(self, width=40, height=20, 
                            yscrollcommand=self.vsb.set)
        self.vsb.config(command=self.text.yview)
        self.vsb.pack(side="right", fill="y")
        self.text.pack(side="left", fill="both", expand=True)
        
        n=10
        var1 = IntVar()
        val =[]
        for i in range(n):
            cb = tk.Checkbutton(self, text="Modul %s" % i, variable=var1)
            self.text.window_create("end", window=cb)
            self.text.insert("end", "\n") # to force one checkbox per line
            val.append(var1.get())

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

Could you help what can I add to the code in order to be able to get the checked Modules by the user? for instance I will get in "val" variable a list with [1, 0, 1, 0, 0, 0, 1, 0, 0, 0] if somebody tick module 0, 2, and 6

I look forward for your feedback.

0

3 Answers 3

3

Are you looking for something like this?

import tkinter as tk

def done():
    result = []
    for var in variables:
        result.append(var.get())
    print(result)

root = tk.Tk()

variables = []
check_buttons = []
for i in range(10):
    var = tk.IntVar(root)
    check_button = tk.Checkbutton(root, text="Modul %i" % i, variable=var)
    check_button.pack()

    variables.append(var)
    check_buttons.append(check_button)

done_button = tk.Button(root, text="Done", command=done)
done_button.pack()

root.mainloop()

I created 10 variables in a list called variables and connected them to each Checkbutton

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. need to add the mainloop in the code
@Fadri Forgot the mainloop :D. I edited my answer
3

This is quite simple, the mistake is you are creating one IntVar for all the checkbuttons, what you should be having is different IntVar for different buttons. Then what I want to add is, instead of val being the values from IntVar let it be the IntVar themselves, so later it can be reused. Here I am using bind to print the list, you can create a button and add command option to it.

self.val = [] # self.val if you want to access it outside __init__, or just val
for i in range(n):
    var1 = IntVar()
    cb = tk.Checkbutton(self, text="Modul %s" % i, variable=var1)
    self.text.window_create("end", window=cb)
    self.text.insert("end", "\n") # to force one checkbox per line
    self.val.append(var1)
self.text.bind('<Return>',lambda e:print([x.get() for x in self.val])) # Dummy function to just print a new list

What is [x.get() for x in self.val] ? It is simple List Comprehension which means:

temp = [] # Any empty list
for x in self.val:
    temp.append(x.get())

Comments

1

Here is another way of doing (tho probably other answers will better suit You depending on what You know):

from tkinter import Tk, Checkbutton, IntVar
from functools import partial


def func(n):
    print(f'Selected {n + 1}') if variables[n].get() == 1 else print(f'Deselected {n + 1}')


variables = []

root = Tk()

for i in range(10):
    variables.append(IntVar())
    Checkbutton(root, text=f'Option {i + 1}', variable=variables[i], command=partial(func, i)).pack()

root.mainloop()

(By suggestion @CoolCloud You can replace the shown command with this: command=lambda i=i: func(i), that should also work, also then You don't have to import functools)

However this is a pretty compact setup.

Explanation:

First there is an empty list, where all the Checkbox variables will be stored.

Then in range 10 which means that 10 Checkboxes will be created we do the following:

  1. First we append a variable to the list that will get assigned to each Checkbutton

  2. Then it creates a Checkbutton and adds to it the variable by using indexing and immediately packs it.

About that command:

The partial basically makes it so that the function given in its argument will always get executed with that variable. More about that here

func() function:

print number of option when selected, otherwise print the number when deselected (adding the correct 'selected: no' and 'deselected: no'). It can also be written as:

if all_checkboxes[n][0].get() == 1:
    print(f'Selected {n + 1}')
else:
    print(f'Deselected {n + 1}')

Hope this helps, if You have any questions ask them.

Source for information about Checkbox and its attributes and arguments.

4 Comments

Why does your 'You' always begin with capital?
@CoolCloud because it shows respect, doesn't it?(so it is from an ethical standpoint) Also I just understood how partial works and that allowed me to reduce my code even more.
lambda i=i does the same thing partial does over here but ok. No it does not look respectful, but if you feel so, then fine.
@CoolCloud well thanks for that information, didn't know that (about lambda). About 'You' well I thought it was the formal, the one one would use to write a formal letter, version of 'you' (since in my language similarly it would be) so that is why I used it. And it still feels like that would be the proper way to talk to people I don't know (even tho I also use it in everyday chatting with my friends (the formal of 'you' in my language))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.