Check buttons allow a user to select any number of choices from a group. While this gives the user a lot of flexibility, it actually gives the programmer greater control by limiting to a specific list what the user can choose.
The Movie Chooser program lets the user choose his or her favorite movie types from a list of three: comedy, drama, and romance. Since the program uses check buttons, the user can select as many (or as few) as he or she wants. The program displays the results of the user's selections in a text box. Figure 10.14 shows off the program.
Figure 10.14: The results of the user's selections show up in the text box.
I set up the Movie Chooser program by importing Tkinter and starting my Application class definition:
# Movie Chooser # Demonstrates check buttons # Michael Dawson - 6/8/03 from Tkinter import * class Application(Frame): """ GUI Application for favorite movie types. """ def __init__(self, master): Frame.__init__(self, master) self.grid() self.create_widgets()
Next, I create a label that describes the program:
def create_widgets(self): """ Create widgets for movie type choices. """ # create description label Label(self, text = "Choose your favorite movie types" ).grid(row = 0, column = 0, sticky = W)
There's one important difference between this label and others I've created: I don't assign the resulting Label object to a variable. Normally, this would be a big mistake, rendering the object useless because it wouldn't be connected to the program in any way. But with Tkinter, a Label object is connected to the program, like all GUI elements, by its master. What this means is that if I know I won't need to directly access a widget, then I don't need to assign the object to a variable. The main benefit of this approach is shorter, cleaner code.
So far, I've been pretty conservative, always assigning each new widget to a variable. But in this case, I know that I'm not going to need to access this label, so I don't assign the Label object to a variable. Instead, I let its master maintain the only reference to it.
Next, I create another label in much the same way:
# create instruction label Label(self, text = "Select all that apply:" ).grid(row = 1, column = 0, sticky = W)
This label provides instructions, telling the user that he or she can select as many movie types as apply.
Next, I create the check buttons, one for each movie type. I first tackle the Comedy check button.
Every check button needs a special object associated with it that automatically reflects the check button's status. The special object must be an instance of the BooleanVar class from the Tkinter module. So, before I create the Comedy check button, I instantiate a BooleanVar object and assign it to a new object attribute, likes_comedy:
# create Comedy check button self.likes_comedy = BooleanVar()
A Boolean variable is a special kind of variable that can be only true or false. Programmers often call such a variable simply a "Boolean." The term is always capitalized because it's derived from the name of the English mathematician George Boole.
Next, I create the check button itself:
Checkbutton(self, text = "Comedy", variable = self.likes_comedy, command = self.update_text ).grid(row = 2, column = 0, sticky = W)
This code creates a new check button with the text Comedy. By passing self.likes_comedy to the parameter variable, I associate the check button's status (selected or unchecked) with the likes_comedy attribute. By passing self.update_text() to the parameter command, I bind the activation of the check button with the update_text() method. This means that whenever the user selects or clears the check button, the update_text() method is invoked. Finally, I place the check button on the next row, all the way to the left.
Notice that I don't assign the resulting Checkbutton object to a variable. This is fine, because what I really care about is the status of the button, which I can access from the likes_comedy attribute.
I create the next two check buttons in the same way:
# create Drama check button self.likes_drama = BooleanVar() Checkbutton(self, text = "Drama", variable = self.likes_drama, command = self.update_text ).grid(row = 3, column = 0, sticky = W) # create Romance check button self.likes_romance = BooleanVar() Checkbutton(self, text = "Romance", variable = self.likes_romance, command = self.update_text ).grid(row = 4, column = 0, sticky = W)
So, whenever the user selects or clears the Drama or Romance check buttons, the update_text() method is invoked. And even though I don't assign the resulting Checkbutton objects to any variables, I can always see the status of the Drama check button through the likes_drama attribute, and I can always see the status of the Romance check button through the likes_romance attribute.
Finally, I create the text box that I use to show the results of the user's selections:
# create text field to display results self.results_txt = Text(self, width = 40, height = 5, wrap = WORD) self.results_txt.grid(row = 5, column = 0, columnspan = 3)
Next, I write the update_text() method, which updates the text box to reflect the check buttons the user has selected:
def update_text(self): """ Update text widget and display user's favorite movie types. """ likes = "" if self.likes_comedy.get(): likes += "You like comedic movies.\n" if self.likes_drama.get(): likes += "You like dramatic movies.\n" if self.likes_romance.get(): likes += "You like romantic movies." self.results_txt.delete(0.0, END) self.results_txt.insert(0.0, likes)
You can't access the value of a BooleanVar object directly. Instead, you must invoke the object's get() method. In the previous code, I use the get() method of the BooleanVar object referenced by likes_comedy to get the object's value. If the value evaluates to true, that means the Comedy check button is selected, and I add the string "You like comedic movies.\n" to the string I'm building to display in the text box. I perform similar operations based on the status of the Drama and Romance check buttons. Finally, I delete all of the text in the text box and then insert the new string, likes, which I just built.
I finish the program with the familiar main section. I create a root window and a new Application object with the root window as its master. Then, I start the window's event loop.
# main root = Tk() root.title("Movie Chooser") app = Application(root) root.mainloop()