Hi,

I was trying to use Checkbutton widget from Tkinter and I searched here in the forum for example code how to apply it, and I couldnt find any. So I have to test it myself using some documentation of Tkinter.

Since I couldnt find any relevant code in this forum, I want to share what I learned how to use Checkbutton.

# I put the result in a list
import tkinter as tk

root = tk.Tk()

def choose():
    # for value (1&2) just put in what you need for it
    # for example, I just put a string '101' and '102' in value1 & 2
    # the control variable cb(n)_v would hold 1 if its checked and 0 if not

    result = []
    if cb1_v == 1:
        result.append(value1)
    if cb2_v == 1:
        result.append(value2)
    return result

# each checkbutton have to use different control variable
# otherwise when you checked one, all other checkbutton will be checked too
cb1_v = tk.IntVar()
cb2_v = tk.IntVar()

cb1 = tk.Checkbutton(root, text='cb1', variable=cb1_v)
cb2 = tk.Checkbutton(root, text='cb2', variable=cb2_v)
btn1 = tk.Button(root, text='Choose',command=choose)

cb1.grid(row=0,column=0)
cb2.grid(row=1, column=0)
btn1.grid(row=2, column=0)

root.mainloop()

I hope this would help others!

If anyone else with more Tkinter experience know some other tips, tricks or techniques, I would really appreciate if you share the knowledge since I'm also new with Python and Tkinter. Thanks.

Recommended Answers

All 11 Replies

You can also use callbacks, which are pretty handy. This is an example. The "buttons" function is the significant part of the code for callbacks. You define a function that is attached to each button, so when that button is pressed you can perform some action based upon which button is checked. This example code just prints something and keeps track of which buttons are on and which are off. It does require the Pmw extension to Tkinter. If you do not have it installed you may want to as it has additional widgets.

from Tkinter import *
import Pmw

class CB:
   def __init__(self, master):
      master.geometry("290x200+5+10" )
      self.master = master
      self.button_num = 0
      self.button_dic = {}
      self.maps_list = self.retrieve_maps()
      self.var_list = []
      self.cb_list = []
      self.choice_list = []

      ##   frame to contain the list boxes
      self.frame = self.scrolled_frame('Available', 150)

      self.exit_button()
      self.label_box()
      self.buttons()


   ##-------------------------------------------------------------------
   def buttons(self):
      """ one checkbutton for each item in the list
      """
      for map_c in self.maps_list:
         self.button_dic[self.button_num] = map_c
         var = IntVar()
         var.set(0)          ## off=default
         self.var_list.append(var)

         b = Checkbutton(self.frame, text = map_c, variable=var)
         b.pack()
         self.cb_list.append ( b )
         def handler ( event, self=self, button_num=self.button_num ):
                return self.cb_handler( event, button_num )
         b.bind ( "<Button-1>", handler )

         self.button_num += 1


   ##-------------------------------------------------------------------
   def cb_handler( self, event, cb_number ):
      store_name = self.button_dic[cb_number]
      if store_name not in self.choice_list :
         self.choice_list.append(store_name)   ## add to selected
      else:
         self.choice_list.remove(store_name)   ## remove from selected
      self.choice_list.sort()

      text_label = "\n".join(self.choice_list)
      self.label_box.configure(text="---Print These---\n" + text_label)

   ##-------------------------------------------------------------------
   def exit_button(self):
      """  Print and Exit buttons
      """
      but_frame=Frame(self.master)
      prt =  Button(but_frame, text='PRINT',
             command=self.finished, bg='blue', fg='white' )
      prt.pack(side="left", fill=X, expand=1)

      exit=  Button(but_frame, text='CANCEL',
             command=self.master.quit, bg='red', fg='white' )
      exit.pack(side="right", fill=X, expand=1)

      but_frame.pack()

   ##-------------------------------------------------------------------
   def finished(self):
      """  called from the print button
      """
      ctr = 0
      for var in self.var_list:
         v = var.get()
         print ctr
         if v:
            print "button is on ", self.maps_list[ctr]
         else:
            print "OFF"
         ctr += 1
      self.master.quit()


   ##-------------------------------------------------------------------
   def label_box(self):
      # Create a label to display the selected items
      self.label_box = Label(self.frame,
                    text = '---Print These---',
                    relief = 'sunken', padx = 10, pady = 10)
      self.label_box.pack(side="right", fill = 'both', expand = 1, \
                          padx = 10, pady = 10)

   ##-------------------------------------------------------------------
   def retrieve_maps(self):
      maps_list = ["Los Angeles", "San Francisco", "Burbank", \
                   "Pasadena", "Hollywood", "Long Beach", \
                   "Catalina", "Alhambra", "Huntington" ]
      longest = max(maps_list)
      len_longest = len(longest)
      for map in maps_list:
         str_append = " "*(len_longest-len(map))
         map += str_append
      maps_list.sort()
      return maps_list

   ##-------------------------------------------------------------------
   def scrolled_frame(self, lit, height=150):
      self.sf = Pmw.ScrolledFrame(self.master,
                                 labelpos = 'n',
                                 label_text = lit,
                                 usehullsize = 1,
                                 hull_width = 200,
                                 hull_height = height,
                                 )

      self.sf.pack(padx=5, pady=3, fill='both', expand=1)
      frame = self.sf.interior()
      return frame

##======================================================================
if __name__ == "__main__":
   root = Tk()
   xx=CB(root)
   root.mainloop()

There is a working example of Tkinter's radio buttons and also a comparative look at check buttons at:
http://www.daniweb.com/forums/showpost.php?p=966368&postcount=58

Hi Ene Uran,

Thanks for the adding, but your code doesn't work for Python 3.1.
It gives error:
Traceback (most recent call last):
File "E:/myPython/tkinter-checkbutton.py", line 36, in <module>
cb_v[ix] = tk.IntVar()
TypeError: 'range' object does not support item assignment

So I changed the code a bit to make it works:
(The changed are marked with '### ...' and '# Changed to this')

# exploring multiple Tkinter check buttons
# check buttons allow more than one item to be selected/checked
# ene

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def cb_checked():
    # show checked check button item(s)
    label['text'] = ''
    for ix, item in enumerate(cb):
        if cb_v[ix].get():
            label['text'] += '%s is checked' % item['text'] + '\n'


root = tk.Tk()

mylist = [
'apple',
'orange',
'banana',
'pear',
'apricot'
]

###cb = range(len(mylist))
cb = []     # Changed to this instead
###cb_v = range(len(mylist))
cb_v = []   # Changed to this instead
for ix, text in enumerate(mylist):
    # IntVar() tracks checkbox status (1=checked, 0=unchecked)
    ###cb_v[ix] = tk.IntVar()
    cb_v.append(tk.IntVar())    # Changed to this instead
    # command is optional and responds to any cb changes
    ###cb[ix] = tk.Checkbutton(root, text=text, variable=cb_v[ix], command=cb_checked)
    # Changed to this instead
    cb.append(tk.Checkbutton(root, text=text, variable=cb_v[ix], command=cb_checked))
    
    cb[ix].grid(row=ix, column=0, sticky='w')

label = tk.Label(root, width=20)
label.grid(row=ix+1, column=0, sticky='w')

# you can preset check buttons (1=checked, 0=unchecked)
cb_v[3].set(1)
# show initial selection
cb_checked()

root.mainloop()

The same thing can be applied to the radiobutton sample in that post since it doesn't work either in Python 3.1.

commented: good observation +14

TypeError: 'range' object does not support item assignment

Usually, you can fix this by replacing range(*args) with list(range(*args)) .

commented: thanks for the note +14

Thanks Gribouillis.

What I do before is the way I always do. So I learned something new today :)

Ouch! Thanks Lingson, I overlooked that range() does not return a list in Python3. So I give you the correct version here:

# exploring multiple Tkinter check buttons
# check buttons allow more than one item to be selected/checked
# ene

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def cb_checked():
    # show checked check button item(s)
    label['text'] = ''
    for ix, item in enumerate(cb):
        if cb_v[ix].get():
            label['text'] += '%s is checked' % item['text'] + '\n'


root = tk.Tk()

mylist = [
'apple',
'orange',
'banana',
'pear',
'apricot'
]

# list(range()) needed for Python3
cb = list(range(len(mylist)))
cb_v = list(range(len(mylist)))
for ix, text in enumerate(mylist):
    # IntVar() tracks checkbox status (1=checked, 0=unchecked)
    cb_v[ix] = tk.IntVar()
    # command is optional and responds to any cb changes
    cb[ix] = tk.Checkbutton(root, text=text,
        variable=cb_v[ix], command=cb_checked)
    cb[ix].grid(row=ix, column=0, sticky='w')

label = tk.Label(root, width=20)
label.grid(row=ix+1, column=0, sticky='w')

# you can preset check buttons (1=checked, 0=unchecked)
cb_v[3].set(1)
# show initial selection
cb_checked()

root.mainloop()

Now it works with Python2 and Python3 as planned. I downloaded the Editra IDE, now I can easily check my code in both Python versions.

I will contact vegaseat to correct the sample code, since the error appears in both samples.

There will be a ton of these gotchas as people switch from Python2 to Python3, or like in Ene's case try to make code work in both versions.

Here is a little test using the 2 versions ...

x = range(3)
print(x, type(x))

"""
my output (Python 2.5.4) -->
([0, 1, 2], <type 'list'>)

my output (Python 3.1.1) -->
range(0, 3) <class 'range'>
"""

The later type is an iterator not a list.

If I'm not mistaken, the function range() in python 3.x is equivalent with the function xrange() in python 2.x?

If I'm not mistaken, the function range() in python 3.x is equivalent with the function xrange() in python 2.x?

exactly.

If you are used to Python2 code, then Python3 is full of surprises. However they all make the language better! So, keep an open mind, use the 2to3.py utility and try to make the old code work.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.