Mutable Variables

There is a better way to manage the interactions between a program's GUi and its variables, and the reason it's better brings us face to face with the biggest difference between the applications we have seen in previous chapters and event-driven GUI applications. Suppose we want to display a string, such as the current time, in several places in a GUIā€”the application's status bar, some dialog boxes, and so on. Assigning a new value to each widget each time the string changes isn't

Immutable Type Tkinter Mutable Type int string bool double

IntVar StringVar BooleanVar DoubleVar

Figure 14.4: Tkinter mutable types hard, but as the application grows, so too do the odds that we'll forget to update at least one of the widgets that's displaying the string. What we really want is a string that "knows" which widgets care about its value and can update them itself when that value changes.

Since Python's strings, integers, doubles, and Booleans are immutable, Tkinter provides types of its own that can be updated in place and that can notify widgets whenever their values change (see Figure 14.4). Rather than set the text of the label using an immutable type such as string, we can set it using the corresponding mutable type, such as StringVar. Whenever a new value is assigned to that StringVar, it tells the label, and any other widgets it has been assigned to, that it's time to update.

The values in Tkinter mutable types are set and retrieved using the set and get methods. To show how they work, the following code creates a Tkinter string variable called data and sets its value to "Data to display". it then creates a label to display the contents of data:

Download gui/label-variable.py

from Tkinter import *

data = StringVar()

data.set("Data to display")

label = Label(window, textvariable=data)

label.pack()

window.mainloop()

Notice that this time we set the textvariable attribute of the label rather than the text attribute. Any time the program changes the contents of data, the text the label is displaying will automatically change as well. The relationships between the three main variables in this program are shown in Figure 14.5, on the next page.

window label window label

Figure 14.5: Widgets and mutable variables

There is one small trap here for newcomers: because of the way the Tkinter module is structured, you cannot create a StringVar or any other mutable variable until you have called the Tk() function to create the top-level window. This doesn't make much difference in this case, but as we'll see in a moment, it sometimes forces programmers to do things in an unintuitive order.

Frame

To show the real power of mutable variables, we need to create a GuI that has several widgets. We will use this as an opportunity to introduce another widget called Frame. A frame isn't directly visible on the screen; instead, its purpose is to organize other widgets. To create a GUI that displays three labels, for example, the following code puts a frame in the root window and then adds the labels to the frame one by one:

Download gui/frame.py

from Tkinter import *

frame = Frame(window)

frame.pack()

first = Label(frame, text="First label") first.pack()

second = Label(frame, text="Second label") second.pack()

third = Label(frame, text="Third label")

third.pack()

window.mainloopQ

First label Second label Third labei

Figure 14.6: A window with a frame and three labels

The resulting GUI is shown in Figure 14.6, while in Figure 14.7, on the next page, we can see how the five widgets are organized. Note that we call pack on every widget; if we omit one of these calls, that widget will not be displayed.

Putting the three labels in the same frame is equivalent to putting the labels directly into the main window widget, but we can use multiple frames to format the window's layout. Here we use two frames containing the three labels and put a border around the second frame. We specify the border width using the borderwidth attribute (0 is the default) and the border style using relief (FLAT is the default). The other border styles are SUNKEN, RAISED, GROOVE, and RIDGE.

Download gui/frame2.py

frame = Frame(window)

frame.pack()

frame2 = Frame(window, borderwidth=4, relief=GROOVE) frame2.pack()

first = Label(frame, text="First label") first.pack()

second = Label(frame2, text="Second label") second.pack()

third = Label(frame2, text="Third label")

third.pack()

window.mainloop()

Was this article helpful?

0 0

Post a comment