Radio Button

A radiobutton lets you choose among a number of mutually exclusive options. Radiobuttons are used together in a set and are appropriate when the number of choices is fairly small (about 3-5).

A Radiobutton object has these attributes:

  • parent - the parent object
  • text - the text label to display
  • command - the callback function
  • variable - the variable shared among radiobuttons of a set
  • value - the specific value of the radiobutton

Standard Radiobutton

Let’s make a program which displays 3 radiobuttons to choose a language.

../_images/radio1.png
import tkinter as tk
root = tk.Tk()

var = tk.StringVar()
var.set('English')

def cb():
    print(var.get())

tk.Radiobutton(root, text='English', variable=var, value='English', command=cb).pack()
tk.Radiobutton(root, text='German', variable=var, value='German', command=cb).pack()
tk.Radiobutton(root, text='French', variable=var, value='French', command=cb).pack()

root.mainloop()

radio1.py

The radiobutton code consists of 7 lines and has a lot of repeated parts.

Using a list

A better way would be to use a list. The code still has 7 lines, but when we increase the number of items, the code length remains constant.

import tkinter as tk
root = tk.Tk()

items = ('English', 'German', 'French', 'Italian', 'Spanish')
var = tk.StringVar()
var.set(items[0])

def cb():
    print(var.get())

for x in items:
    tk.Radiobutton(root, text=x, variable=var, value=x, command=cb).grid()

root.mainloop()

radio2.py

A better Radiobutton class

It’s time now to redefine the Radiobutton class to create everything in just one line:

Radiobutton('English;German;French', 'print(self.item)')
  • the items are declared as a semicolon-separated list
  • the command is a string to be evaluated in the Radiobutton environment
  • the selected value is available in self.item
  • the selection index is available in self.val (could be used as a list index)
"""Create radiobuttons."""
from tklib import *

app = App()
Radiobutton('English;German;French', 'print(self.item)')
app.run()

radio3.py

Now let’s see how this class is defined

class Radiobutton:
    """Create a list-based Radiobutton object."""

    def __init__(self, items='Radiobutton', cmd='', val=0, **kwargs):
        self.items = items.split(';')
        self.cmd = cmd
        self.val = tk.IntVar()
        self.val.set(val)
        for i, item in enumerate(self.items):
            r = ttk.Radiobutton(App.stack[-1], text=item, variable=self.val,
                                value=i, command=self.cb, **kwargs)
            r.grid(sticky='w')

    def cb(self):
        """Evaluate the cmd string in the Radiobutton context."""
        self.item = self.items[self.val.get()]
        exec(self.cmd)

The item string is split at the semicolon into a regular list. The shared variable is a IntVar object. Each radiobutton has an integer value (0, 1, 2, …). The callback function finds the selected item by looking up this integer value in the items list.

Let’s look at another exemple. This time we add another language (Italian) and initialize the default button to 2 (French).

../_images/radio4.png
from tklib import *

app = App('Radiobuttons')
Radiobutton('English;German;French;Italian', 'print(self.item)', 2)
app.run()

radio4.py

If something goes wrong

Let’s see what happens if there are errors in the options.

../_images/radio5.png

If there is no items list, there will be a single item called Radiobutton. If there is an error in the expression, this message is written to the console:

File "/Users/raphael/GitHub/tk-tutorial/docs/radio/tklib.py", line 238, in cb
    exec(self.cmd)
File "<string>", line 1
    print(self.item
                ^
SyntaxError: unexpected EOF while parsing
from tklib import *

app = App('Radiobuttons')
Radiobutton()                           # no item list
Radiobutton('A;B', 'print(self.item')   # error in command
Radiobutton('a;b', 'print(self.item)')  # correct

app.run()

radio5.py