Customizing the Visual Style

Every windowing system has its own look and feel—square or rounded corners, particular colors, and so on. In this section, we’ll see how to change the appearance of GUI widgets to make applications look more distinctive.

A note of caution before we begin: the default styles of some windowing systems have been chosen by experts trained in graphic design and human-computer interaction. The odds are that any radical changes on your part will make things worse, not better. In particular, be careful about color (Roughly 8% percent of the male population with Northern European ancestry have red-green color blindness[9]) and font size (many people, particularly the elderly, cannot read small text).

Changing Fonts

Let’s start by changing the size, weight, slant, and family of the font used to display text. To specify the size, we provide the height as an integer in points. We can set the weight to either bold or normal and the slant to either italic (slanted) or roman (not slanted).

The font families we can use depend on what system the program is running on. Common families include Times, Courier, and Verdana, but dozens of others are usually available. One note of caution, though: if you choose an unusual font, people running your program on other computers might not have it, so your GUI might appear different than you’d like for them. Every operating system has a default font that will be used if the requested font isn’t installed.

The following sets the font of a button to be 14 point, bold, italic, and Courier.

 import​ tkinter
 
 window = tkinter.Tk()
 button = tkinter.Button(window, text=​'Hello'​,
  font=(​'Courier'​, 14, ​'bold italic'​))
 button.pack()
 window.mainloop()

Here is the resulting GUI:

images/gui/font.png

Using this technique, you can set the font of any widget that displays text.

Changing Colors

Almost all background and foreground colors can be set using the bg and fg keyword arguments, respectively. As the following code shows, we can set either of these to a standard color by specifying the color’s name, such as white, black, red, green, blue, cyan, yellow, or magenta:

 import​ tkinter
 
 window = tkinter.Tk()
 button = tkinter.Label(window, text=​'Hello'​, bg=​'green'​, fg=​'white'​)
 button.pack()
 window.mainloop()

Here is the resulting GUI:

images/gui/color.png

As you can see, white text on a bright green background is not particularly readable.

We can choose more colors by specifying them using the RGB color model. RGB is an abbreviation for “red, green, blue”; it turns out that every color can be created using different amounts of these three colors. The amount of each color is usually specified by a number between 0 and 255 (inclusive).

These numbers are conventionally written in hexadecimal (base 16) notation; the best way to understand them is to play with them. Base 10 uses the digits 0 through 9; base 16 uses those ten digits plus another six: A, B, C, D, E, and F. In base 16, the number 255 is written FF.

The following color picker does this by updating a piece of text to show the color specified by the red, green, and blue values entered in the text boxes; choose any two base-16 digits for the RGB values and click the Update button:

 import​ tkinter
 def​ change(widget, colors):
 """ Update the foreground color of a widget to show the RGB color value
  stored in a dictionary with keys 'red', 'green', and 'blue'. Does
  *not* check the color value.
  """
 
  new_val = ​'#'
 for​ name ​in​ (​'red'​, ​'green'​, ​'blue'​):
  new_val += colors[name].get()
  widget[​'bg'​] = new_val
 
 # Create the application.
 window = tkinter.Tk()
 frame = tkinter.Frame(window)
 frame.pack()
 
 # Set up text entry widgets for red, green, and blue, storing the
 # associated variables in a dictionary for later use.
 colors = {}
 for​ (name, col) ​in​ ((​'red'​, ​'#FF0000'​),
  (​'green'​, ​'#00FF00'​),
  (​'blue'​, ​'#0000FF'​)):
  colors[name] = tkinter.StringVar()
  colors[name].set(​'00'​)
  entry = tkinter.Entry(frame, textvariable=colors[name], bg=col,
  fg=​'white'​)
  entry.pack()
 
 # Display the current color.
 current = tkinter.Label(frame, text=​' '​, bg=​'#FFFFFF'​)
 current.pack()
 
 # Give the user a way to trigger a color update.
 update = tkinter.Button(frame, text=​'Update'​,
  command=​lambda​: change(current, colors))
 update.pack()
 tkinter.mainloop()

This is the most complicated GUI we have seen so far, but it can be understood by breaking it down into a model, some views, and a controller. The model is three StringVars that store the hexadecimal strings representing the current red, green, and blue components of the color to display. These three variables are kept in a dictionary indexed by name for easy access. The controller is function change, which concatenates the strings to create an RGB color and applies that color to the background of a widget. The views are the text-entry boxes for the color components, the label that displays the current color, and the button that tells the GUI to update itself.

This program works, but neither the GUI nor the code is very attractive. It’s annoying to have to click the update button, and if a user ever types anything that isn’t a two-digit hexadecimal value into one of the text boxes, it results in an error. The exercises will ask you to redesign both the appearance and the structure of this program.

Laying Out the Widgets

One of the things that makes the color picker GUI ugly is the fact that everything is arranged top to bottom. tkinter uses this layout by default, but we can usually come up with something better.

To see how, let’s revisit the example from Getting Information from the User with the Entry Type , placing the label and button horizontally. We tell tkinter to do this by providing a side argument to method pack:

 import​ tkinter
 
 window = tkinter.Tk()
 frame = tkinter.Frame(window)
 frame.pack()
 label = tkinter.Label(frame, text=​'Name'​)
 label.pack(side=​'left'​)
 entry = tkinter.Entry(frame)
 entry.pack(side=​'left'​)
 
 window.mainloop()

Here is the resulting GUI:

images/gui/side.png

Setting side to "left" tells tkinter that the leftmost part of the label is to be placed next to the left edge of the frame, and then the leftmost part of the entry field is placed next to the right edge of the label—in short, that widgets are to be packed using their left edges. We could equally well pack to the right, top, or bottom edges, or we could mix packings (though that can quickly become confusing).

For even more control of our window layout, we can use a different layout manager called grid. As its name implies, it treats windows and frames as grids of rows and columns. To add the widget to the window, we call grid instead of pack. Do not call both on the same widget; they conflict with each other. The grid call can take several parameters, as shown in Table 29.


Table 29. grid() Parameters

Parameter

Description

row

The number of the row to insert the widget into—row numbers begin at 0.

column

The number of the column to insert the widget into—column numbers begin at 0.

rowspan

The number of rows the widget occupies—the default number is 1.

columnspan

The number of columns the widget occupies—the default number is 1.


In the following code, we place the label in the upper left (row 0, column 0) and the entry field in the lower right (row 1, column 1).

 import​ tkinter
 
 window = tkinter.Tk()
 frame = tkinter.Frame(window)
 frame.pack()
 label = tkinter.Label(frame, text=​'Name:'​)
 label.grid(row=0, column=0)
 entry = tkinter.Entry(frame)
 entry.grid(row=1, column=1)
 
 window.mainloop()

Here is the resulting GUI; as you can see, this leaves the bottom-left and upper-right corners empty:

images/gui/grid.png
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.249.220