Tuesday, January 19, 2010

Ch18



















   







Page
297






















     
 
  Hour 18

Tk Widgets I
 
 






















 
 
  Life is much
too short to spend time programming in lousy languages.

Robert Meegan
 
 






















   
 
  In this hour, we
start learning about windows and widgets in Tkinter. At the end of the
hour, you will be able to
 
 






















   
 
  � Discriminate
between windows and widgets
 
 






















   
 
  � Identify
different several kinds of widgets
 
 






















   
 
  � Use callbacks
in Tkinter applications
 
 






















   
 
  Windows and
Widgets
 
 






















   
 
  The distinction
between windows and widgets is clear: a window is simply an area of your
screen that is marked off in some way, usually by visible borders added
by either your window manager (in X Windows) or by the Windows OS. A
widget is the same as a window, but it has added behavior�sound
familiar? It should. A widget is usually a smaller part of a window.
Figure 18.1 should make the distinction visible:
 
 


 




 


 
















   







Page
298






















   
 
 
 
 






















   
 
 
Figure 18.1

Windows and widgets.
 
 






















   
 
  The object on
the left is a simple window; it does nothing but occupy screen real
estate because there aren't any buttons or menus. The code�what there is
of it�is
 
 






















   
 
 
from Tkinter import *

root = Tk()

root.mainloop()
 
 






















   
 
  The only way to
exit this program is to push the X button at the upper right-hand
corner. On the other hand, the object on the right is a window that
contains a widget�a button that says ''I am a widget." It actually does
something; if you push the button, it exits the program (you should
remember this from the last chapter). Listing 18.1 shows the code.
 
 






















   
 
  Listing 18.1


tkt3.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import sys

 5

 6  root = Tk()

 7  button = Button(root)

 8  button["text"] = "I am a widget"

 9  button.pack()

10  root.mainloop()

11
 
 






















   
 
  Again, this
listing should look familiar because it's very close to


ave.py
from
Chapter 17, "Introducing the Python GUI."
 
 






















   
 
  As I pointed out
before, widgets have behavior and state; they have methods that you can
call and properties that you can set. The root window that appears on
the left in Figure 18.1 is not really a true window; it is instead a
Tkinter encapsulation of a window: because all widgets in Tkinter are
children of this root, or top level, window, it has some properties and
some behavior, which all children inherit. Remember our earlier
discussion of Python's object inheritance? All widgets in Tkinter are
objects, and thus, all have state (properties) and behavior (methods);
you can subclass them and modify the behavior to suit your needs.
 
 


 




 


 
















   







Page
299






















   
 
  Reference pages
for the Tkinter widgets can be found at



http://www.pythonware.com/library/tkinter/tkclass/index.htm
.
These pages list the various kinds of widgets, their properties, and
their methods. All the different widgets are described and pictured
next, alphabetically. Simple test scripts are given, along with some
comments; in the section on scrollbars and text widgets, in Chapter 19,
Tk Widgets II, I'll present a complete application that actually does
something useful. The Button widget, shown in Figure 18.2, is fairly
simple to use. Listing 18.2 shows how:
 
 






















   
 
  The Button
Widget
 
 






















   
 
 
 
 






















   
 
 
Figure 18.2

A Button widget.
 
 






















   
 
  Listing 18.2


tkbutton.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import sys

 5

 6  def die(event):

 7      sys.exit(0)

 8

 9  root = Tk()

10  button = Button(root)

11  button[''text"] = "Button"

12  button.bind("<Button>",die)

13  button.pack()

14

15  root.mainloop()
 
 






















   
 
  As you can see,
it's essentially the same as


tkt3.py
,
shown in Listing 18.1. However, we could create the button another way:
We could use Tkinter's


option

syntax, which works like this:
 
 






















   
 
 
button = Button(root,text="Button",command=die)
 
 






















   
 
  This single line
would replace lines 10 through 12 in Listing 18.2. When any widget is
created, you can set as many options as you want by using the "
keyword=value"
syntax shown previously. The only glitch for


tkbutton.py

is that the


command

option expects to be given a callback function that takes no arguments,
so


die()
must be
modified to eliminate the


event

parameter. For creating this Button widget, then, this alternate method
doesn't really get us much, but it doesn't cost much either. The


option
method
can,
 
 


 




 


 
















   







Page
300






















   
 
  however, be both
easier and more readable in many situations; some widgets have a great
many options. You should get into the habit of using actual event
bindings instead of the


command=callback

style; callbacks that can be installed as options this way are limited
to just one event and one specific argument list. Using event bindings
lets you have callbacks for exactly what you need. The Canvas widget,
shown in Figure 18.3, is simple (and boring) to look at in its natural
state. Drawing things in it, which is what it's good for, is a subject
for in-depth treatment in a later chapter.
 
 






















   
 
  The Canvas
Widget
 
 






















   
 
 
 
 






















   
 
 
Figure 18.3

A Canvas

widget.
 
 






















   
 
  The simplest
possible program showing how to display one is shown in Listing 18.3.
 
 






















   
 
  Listing 18.3


tkcanvas.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import sys

 5

 6  def die(event):

 7      sys.exit(0)

 8

 9  root = Tk()

10  button = Button(root)

11  button[''text"] = "Button"

12  button.bind("<Button>",die)

13  button.pack()

14  canvas = Canvas(root)

15  canvas["height"]=64

16  canvas["width"]=64

17  canvas["borderwidth"]=2

18  canvas["relief"]=RAISED

19  canvas.pack()

20

21  root.mainloop()
 
 






















   
 
  The height,
width, and so on could be set using the option method we used in the
alternate method for Button widgets, but again, it doesn't make much
difference in such a small demo program anyway. Many of the options are
covered in a later chapter.
 
 


 




 


 
















   







Page
301






















   
 
  The
Checkbutton Widget
 
 






















   
 
  The Checkbutton
widget, as shown in Figure 18.4, is used for yes-no conditions, or
toggle
variables (from toggle switches) that have only two states:
on and off.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.4

A Checkbutton

widget.
 
 






















   
 
  Listing 18.4
shows how to use it.
 
 






















   
 
  Listing 18.4


tkcheckbutton.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import sys

 5

 6  def die(event):

 7      sys.exit(0)

 8

 9  root = Tk()

10  button = Button(root)

11  button[''text"] = "Button"

12  button.bind("<Button>",die)

13  button.pack()

14  checkbutton = Checkbutton(root)

15  checkbutton["text"] = "Checkbutton"

16  checkbutton.pack()

17

18  root.mainloop()
 
 






















   
 
  Many, if not
most, of the widgets I'm showing you will look different on different
platforms. For example, Figure 18.5 shows how the Checkbutton would look
on UNIX, and it would appear differently on a Mac, too.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.5

A Checkbutton

widget on UNIX.
 
 






















   
 
  The Entry
Widget
 
 






















   
 
  The Entry widget
shown in Figure 18.6 obtains text input from a user. It's limited to a
single line, whereas the Text widget that you will see later can have
multiple lines. Listing 18.5 shows a simple way to use it.
 
 


 




 


 
















   







Page
302






















   
 
 
 
 






















   
 
 
Figure 18.6

An Entry widget.
 
 






















   
 
  Listing 18.5


tkentry.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import sys

 5

 6  def die(event):

 7      print entry.get()

 8      sys.exit(0)

 9

10  root = Tk()

11  button = Button(root)

12  button[''text"] = "Button"

13  button.bind("<Button>",die)

14  button.pack()

15

16  entry = Entry(root)

17  entry.insert(0,"Entry")

18  entry.pack()

19

20  root.mainloop()

21
 
 






















   
 
  When you exit
the program by pressing the button, the program prints the text that you
typed into the Entry widget; line 7 shows how to read the value�with the


get()
method.
The


get()
method
is common to many widgets, as is the


set()
method.
 
 






















   
 
  The Frame
Widget
 
 






















   
 
  The Frame
widget, shown in Figure 18.7, holds things. It is also used to occupy
space; that is, it can be used either as a placeholder or as a separator
for aesthetic reasons.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.7

A Frame

widget.
 
 






















   
 
  Listing 18.6
shows a simple program that displays a Frame widget; notice that height
and width must be set.
 
 


 




 


 
















   







Page
303






















   
 
  Listing 18.6


tkframe.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import sys

 5

 6  def die(event):

 7      sys.exit(0)

 8

 9  root = Tk()

10  button = Button(root)

11  button[''text"] = "Button"

12  button.bind("<Button>",die)

13  button.pack()

14  frame = Frame(root)

15  frame["height"]=64

16  frame["width"]=64

17  frame["background"] = "white"

18  frame["borderwidth"]=2

19  frame["relief"]=RAISED

20  frame.pack()

21

22  root.mainloop()
 
 






















   
 
  The Label
Widget
 
 






















   
 
  The Label
widget, shown in Figure 18.8, is one of the most useful widgets.
 
 






















   
 
 
 
 






















   
 
 
Figure

18.8

A Label

widget.
 
 






















   
 
  It holds
noneditable text and is extremely easy to use, as Listing 18.7 shows.
 
 






















   
 
  Listing 18.7


tklabel.py
TABLE
17.1
Tkinter Events
 
 























 
 
 
1  #!/usr/local/bin/python

2

3  from Tkinter import *

4  import sys

5

6  def die(event):

7      sys.exit(0)
 
 






















   
 
  continues  
 


 




 


 
















   







Page
304






















   
 
  Listing 18.7
continued
 
 























 
 
 
 8

 9  root = Tk()

10  button = Button(root)

11  button[''text"] = "Button"

12  button.bind("<Button>",die)

13  button.pack()

14  labelx = Label(root)

15  labelx["height"] = 1

16  labelx.pack()

17  label = Label(root)

18  label["text"] = "Label"

19  label["borderwidth"] = 1

20  label["relief"] = SOLID

21

22  label.pack()

23

24  root.mainloop()
 
 






















   
 
  This program
uses an extra label (
labelx),
with no text, as a separator; the Frame widget could have been used just
as easily.
 
 






















   
 
  The Listbox
Widget
 
 






















   
 
  A listbox
widget, shown in Figure 18.9, is used to provide users with multiple
choices. When building the widget, it's easier to use the regular method
of construction instead of the option way.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.9

A Listbox widget.
 
 






















   
 
  Listing 18.8
shows how.
 
 






















   
 
  Listing 18.8


tklistbox.py
TABLE
17.1
Tkinter Events
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import sys

 5

 6  elements = [ "item5", "item4", "item3", "item2", "item1" ]

 7
 
 






















   
 
  continues  
 


 




 


 
















   







Page
305























 
 
 
 8  def die(event):

 9      sys.exit(0)

10

11  root = Tk()

12  button = Button(root)

13  button[''text"] = "Button"

14  button.bind("<Button>",die)

15  button.pack()

16  labelx = Label(root)

17  labelx["height"] = 1

18  labelx.pack()

19

20  listbox = Listbox(root)

21  for i in elements :

22      listbox.insert(0, i)

23  listbox.pack()

24

25  root.mainloop()
 
 






















   
 
  The
for
loop in line 21 inserts the text for each item into the list. You could
add elements or items to the listbox in many ways; this is just one way.
 
 






















   
 
  Tkinter
Variables
 
 






















   
 
  To use variables
with the Tkinter widgets, you must first understand that all Tk/TCL
variables are strings. Therefore, any time a widget requires a variable
that it can modify (we'll see a use for this in the description of menu
widgets, next), you have to use a set of special variables designed
especially for interfacing between Python and Tkinter. What you need to
know about them is that they are objects, not simple strings; all of
them inherit from a class called


Variable
,
which has certain basic methods and states that are common to all the
different kinds. Each particular kind knows how to get and set its own
value, taking into account its own special needs. Table 18.1 lists the
Tkinter variables, along with a description and a short example of how
to create one.
 
 








































TABLE  18.1
Tkinter Variables

Name

Description

Example


StringVar()

Holds string
values


x = StringVar("Text")


IntVar()

Holds integer
values


x = IntVar(42)


DoubleVar()

Holds
floating-point values


x = DoubleVar(3.14159)


BooleanVar()

Holds

true
and


false

values


x = BooleanVar("true")




 


 




 


 
















   







Page
306






















   
 
  To retrieve the
value of any of these variables, you would simply use the


get()

method:


print x.get()
,
for example. To set the value, use the


set()
method:


x.set(2*pi)
.
Any time you need to send a variable value into or get a value out of a
widget, you will need to use a Tk variable, as we'll see next.
 
 






















   
 
  The Menu and
Menubutton Widgets
 
 






















   
 
  The Menu widget
is not displayable on its own; it must contain Menubutton widgets. You
can think of the Menu widget as something like a Frame widget that holds
things. There are two major kinds of menus: menu bars and option menus.
A menu bar looks like the one shown in Figure 18.10.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.10

A menu bar.
 
 






















   
 
  You've seen
these in all kinds of Windows applications. Listing 18.9 shows the code
for a standard menu bar.
 
 






















   
 
  Listing 18.9


tkmenu.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox

 5  import sys

 6

 7  def die():

 8      sys.exit(0)

 9

10  def callee():

11      print ''I was called; few are chosen"

12

13  def about():

14      tkMessageBox.showinfo("tkmenu","This is tkmenu.py Version 0")

15

16  root = Tk()

17  bar = Menu(root)

18

19  filem = Menu(bar)

20  filem.add_command(label="Open...", command=callee)

21  filem.add_command(label="New...", command=callee)

22  filem.add_command(label="Save", command=callee)

23  filem.add_command(label="Save as...", command=callee)

24  filem.add_separator()
 
 






















   
 
  continues  
 


 




 


 
















   







Page
307























 
 
 
25  filem.add_command(label="Exit", command=die)

26

27  helpm = Menu(bar)

28  helpm.add_command(label=''Index...", command=callee)

29  helpm.add_separator()

30  helpm.add_command(label="About", command=about)

31

32  bar.add_cascade(label="File", menu=filem)

33  bar.add_cascade(label="Help", menu=helpm)

34

35  root.config(menu=bar)

36  root.mainloop()

37
 
 






















   
 
  Lines 13 and 14
show a special callback for the


About
menu
entry; the MessageBox widget is discussed later in this chapter. Line 19
creates a Menu widget, which is the container for several Menubutton
widgets, which are added to it in lines 20 through 25. In line 24, we
add a separator�which is just a line, giving some kind of visual
separation between the other menu entries and the Exit selection. As you
can see, we don't ever call


Menubutton()

directly, but instead, use methods built into the Menu widget;


add_command()

has easier-to-use syntax than


Menubutton()
.
 
 






















   
 
  Lines 27 through
30 create and fill another Menu, and in lines 32 and 33, we add the two
created menus to the menu bar, which we created in line 17 as a child of
the root window. The


add_cascade()

method puts a label into the menu bar and then attaches the specified
menu to that label; clicking the label pops up the appropriate "cascade"
menu. Figure 18.11 shows what the cascade looks like popped up.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.11

A cascade menu.
 
 






















   
 
  It's also
possible for such a cascade menu to have other cascading menus hanging
off individual Menubuttons, but I'm not particularly fond of designs
like that. Menus are usually touchy things, so the more dependent menus
you have, the more opportunity the user has to get annoyed because the
menu decides to evaporate underneath the pointer. By the way, the
ellipses in the menus (the "
..."
in "
New...")
means, by convention, that if you choose such an item, a dialog will pop
up. An arrow, or some similar indicator, means that another menu will
appear if you choose that selection. Menus can include submenus, check
boxes, regular selections, and separators.
 
 


 




 


 
















   







Page
308






















   
 
 
 
 






















   
 
 
Figure 18.12

An option menu.
 
 






















   
 
  An option menu,
however, is a little more complicated (see Figure 18.12). Although it's
not mandatory, it is generally necessary to provide a Tkinter variable
to set the label of the option menu. Option menus can appear anywhere
within a Tk container widget, not just within a menu bar at the top of
the application's main (or a dialog) window. Listing 18.10 shows the
code for the option menu shown in Figure 18.12.
 
 






















   
 
  Listing 18.10


tkoptionmenu.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox

 5  import sys

 6

 7  def die():

 8      global xx

 9      print xx.get()

10      sys.exit(0)

11

12  def callee():

13      print ''I was called; few are chosen"

14

15  def about():

16      tkMessageBox.showinfo("tkmenu","This is tkmenu.py Version 0")

17

18  root = Tk()

19  bar = Menu(root)

20

21  filem = Menu(bar)

22  filem.add_command(label="Open...", command=callee)

23  filem.add_command(label="New...", command=callee)

24  filem.add_command(label="Save", command=callee)

25  filem.add_command(label="Save as...", command=callee)

26  filem.add_separator()

27  filem.add_command(label="Exit", command=die)

28

29  helpm = Menu(bar)

30  helpm.add_command(label="Index...", command=callee)

31  helpm.add_separator()

32  helpm.add_command(label="About", command=about)

33
 
 






















   
 
  continues  
 


 




 


 
















   







Page
309























 
 
 
34  bar.add_cascade(label="File", menu=filem)

35  bar.add_cascade(label=''Help", menu=helpm)

36

37  root.config(menu=bar)

38  frame = Frame(root)

39  frame.pack()

40  xx = StringVar(frame)

41  xx.set("slow")

42

43  fm = OptionMenu(frame,xx,"slow","slower","slowest","even slower")

44  fm.pack()

45  root.mainloop()

46
 
 






















   
 
  As you can see,
it contains the same menu bar code as Listing 18.9 does, in addition to
new code for the option menu. Line 40 sets up a Tkinter string variable,
and in line 43 it is used; the second argument to


OptionMenu()

must be a Tkinter variable, and here it is set to

slow.
This provides the default setting for the menu, and thus, the initial
label for the option menu. When another choice is selected from the
menu, the value of the


xx

variable is also changed. Lines 8 and 9 show how to retrieve that value
and print it out.
 
 






















   
 
  The
MessageBox Widgets
 
 






















   
 
  MessageBox
widgets are known as "dialogs" because they are windows that pop up from
your main application and stay in front of them until the user pushes a
default button. This default button, for most dialogs and message boxes,
is usually labeled "OK," but it does not have to be. For instance, the
"yesno" message box has buttons labeled only "Yes" and "No," but of
course, that's logical. The easiest way to use most message boxes, as
you can see in Listing 18.10 in line 16, is to use convenience
functions. We will see how to use the actual


Messagebox()

call later, so that question boxes can be customized. Note that all the
pictures here are of Windows message boxes; the UNIX versions differ
quite a bit, notably in using monochrome icons instead of color ones,
but their function and usage remains the same.
 
 






















   
 
  The Info
MessageBox
 
 






















   
 
  Listing 18.11


tkmessage.info.py
 
 























 
 
 
1  #!/usr/local/bin/python

2

3  from Tkinter import *
 
 






















   
 
  continues  
 


 




 


 
















   







Page
310






















   
 
  Listing 18.11
continued
 
 























 
 
 
 4  import tkMessageBox

 5  import sys

 6

 7  def die(event):

 8      tkMessageBox.showinfo(''tkMessageBox","tkMessageBox.showinfo")

 9      sys.exit(0)

10

11  root = Tk()

12  button = Button(root)

13  button["text"] = "Button"

14  button.bind("<Button>",die)

15  button.pack()

16

17  root.mainloop()
 
 






















   
 
  The first
parameter in the convenience function


showinfo()

(line 8) is the title of the box, and the second parameter is the text
to be displayed in the box itself. Figure 18.13 shows what it looks like
in action.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.13

An Info MessageBox

widget.
 
 






















   
 
  Most of the
remaining message boxes are just as simple to use.
 
 






















   
 
  The
Warning MessageBox
 
 






















   
 
  The warning box
shown in Figure 18.14, for example, is used almost identically.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.14

A Warning MessageBox

widget.
 
 






















   
 
  Listing 18.12
shows the code.
 
 






















   
 
  Listing 18.12


tkmessage.warning.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox
 
 






















   
 
  continues  
 


 




 


 
















   







Page
311























 
 
 
 5  import sys

 6

 7  def die(event):

 8      tkMessageBox.showwarning(''tkMessageBox","tkMessageBox.showwarning")

 9      sys.exit(0)

10

11  root = Tk()

12  button = Button(root)

13  button["text"] = "Button"

14  button.bind("<Button>",die)

15  button.pack()

16

17  root.mainloop()
 
 






















   
 
  Only line 8
differs at all.
 
 






















   
 
  The Error
MessageBox
 
 






















   
 
 
 
 






















   
 
 
Figure 18.15

An Error MessageBox

widget.
 
 






















   
 
  The same
situation holds in the case of the error box (see Figure 18.15), which
again has a single button. Listing 18.13 shows how simple it is to use.
 
 






















   
 
  Listing 18.13


tkmessage.error.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox

 5  import sys

 6

 7  def die(event):

 8      tkMessageBox.showerror("tkMessageBox","tkMessageBox.showerror")

 9      sys.exit(0)

10

11  root = Tk()

12  button = Button(root)

13  button["text"] = "Button"

14  button.bind("<Button>",die)

15  button.pack()

16

17  root.mainloop()
 
 


 




 


 
















   







Page
312






















   
 
  Again, only line
8 differs. The three boxes we've been talking about have much in common
because they have only one button; the user isn't really expected to do
anything except acknowledge that they've seen the box. In the case of an
error box, it's usually a good idea to exit the application unless you
are certain (you the programmer) that there will be no ill effects; that
is, the user will not lose any data. In most cases, it's better to exit
and annoy the user a little bit than to keep running and run the risk of
either destroying or distorting data. The next set of message boxes,
however, uses more than one button because the user is expected to make
a decision, and the program is expected to respond properly to the
user's decision.
 
 






















   
 
  The Yesno
MessageBox
 
 






















   
 
  The message box
shown in Figure 18.16, naturally enough, asks a yes-or-no question.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.16

A Yesno MessageBox

widget.
 
 






















   
 
  The code is
shown below in Listing 18.14.
 
 






















   
 
  Listing 18.14


tkmessage.askyesno.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox

 5  import sys

 6

 7  def die(event):

 8      response = tkMessageBox.askyesno(''tkMessageBox",

 9          "tkMessageBox.askyesno")

10      print response

11      sys.exit(0)

12

13  root = Tk()

14  button = Button(root)

15  button["text"] = "Button"

16  button.bind("<Button>",die)

17  button.pack()

18

19  root.mainloop()
 
 


 




 


 
















   







Page
313






















   
 
  If you run this
code, you will see that pushing the Yes button results in a 1 being
printed out; when the No button is pushed, the result is a 0. The


askyesno()

function returns a value indicating which button the user pushed, and
that value is collected in line 8. By adding an

if
statement to check the response, you could decide whether to exit the
program, based on the user's choice.
 
 






















   
 
  The
Okcancel MessageBox
 
 






















   
 
  In this message
box, shown in Figure 18.17, you can see that we also have only two
buttons, although they're labeled differently.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.17

An Okcancel MessageBox

widget.
 
 






















   
 
  Listing 18.15
shows the code (and its similarity to the other two-button message box).
 
 






















   
 
  Listing 18.15


tkmessage.askokcancel.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox

 5  import sys

 6

 7  def die(event):

 8      r = tkMessageBox.askokcancel(''tkMessageBox", \

 9          "tkMessageBox.askokcancel")

10      print r

11      sys.exit(0)

12

13  root = Tk()

14  button = Button(root)

15  button["text"] = "Button"

16  button.bind("<Button>,"die)

17  button.pack()

18

19  root.mainloop()
 
 






















   
 
  When you run
this code, you'll see that the response is the same as the previous box:
either 1 or 0.
 
 


 




 


 
















   







Page
314






















   
 
  The
Retrycancel MessageBox
 
 






















   
 
  This box, shown
in Figure 18.18, is another two-button message box and also behaves the
same way.
 
 






















   
 
 
 
 






















   
 
 
Figure 18.18

A Retrycancel MessageBox

widget.
 
 






















   
 
  Listing 18.16
shows the code.
 
 






















   
 
  Listing 18.16


tkmessage.askretrycancel.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox

 5  import sys

 6

 7  def die(event):

 8      r = tkMessageBox.askretrycancel(''tkMessageBox", \

 9          "tkMessageBox.askretrycancel")

10      print r

11      sys.exit(0)

12

13  root = Tk()

14  button = Button(root)

15  button["text"] = "Button"

16  button.bind("<Button>",die)

17  button.pack()

18

19  root.mainloop()
 
 






















   
 
  The usage for
all three two-button convenience functions is the same: Put up a
standard question dialog so that the user can answer a simple question
one of two (limited) ways. These dialogs all return 0 or 1, which means
that you should remember which button returns which value: 0 means no,
cancel, or ignore, and 1 indicates yes, OK, or retry.
 
 






















   
 
  The
Question MessageBox
 
 






















   
 
  For a
three-button message box, as shown in Figure 18.19, we must resort to
calling the


Message()

method directly; there are no convenience functions for message boxes
with more than two buttons. Notice that here we use the keyword style of
setting options.
 
 


 




 


 
















   







Page
315






















   
 
 
 
 






















   
 
 
Figure 18.19

A Question MessageBox

widget.
 
 






















   
 
  Listing 18.17
shows the code.
 
 






















   
 
  Listing 18.17


tkmessage.askquestion.py
 
 























 
 
 
 1  #!/usr/local/bin/python

 2

 3  from Tkinter import *

 4  import tkMessageBox

 5  import sys

 6

 7  def die(event):

 8      x = tkMessageBox.Message(root, type=tkMessageBox.ABORTRETRYIGNORE,

 9          icon=tkMessageBox.QUESTION,

10          title=''tkMessageBox",

11          message="tkMessageBox.askquestion")

12      r = x.show()

13      tkMessageBox.showinfo("Reply", r )

14      sys.exit(0)

15

16  root = Tk()

17  button = Button(root)

18  button["text"] = "Button"

19  button.bind("<Button>",die)

20  button.pack()

21

22  root.mainloop()
 
 






















   
 
  Lines 8 through
11 show the keyword arguments; we specify the type (three buttons) and
the icon (the


QUESTION

icon) using special constants defined in the


tkMessageBox

module. The title and the message, although passed as keyword options,
are ordinary strings, the same as we would have used if there were a
convenience function. Because no convenience function is available, what
we have to do is create the message box (
x = tkMessageBox.Message())
and then call the


x.show()

method. We retrieve the value returned by


show()
in
line 12 and then use the


showinfo()

convenience function to display the button pressed by the user. When you
run this program, notice that

r
is a string; this is a consequence of not using a convenience function.
 
 






















   
 
  You can use this
same style for all the message boxes; convenience functions are just
that�merely convenient, not necessary.
 
 


 




 


 
















   







Page
316






















   
 
  Summary  
 






















   
 
  We've talked
about various kinds of basic


Tkinter

widgets, from the Button widget to the different kinds of message boxes.
In the next hour, we'll discuss more Tkinter widgets (from Radiobuttons
to Text), put together a complete application, and demonstrate Toplevel
widgets.
 
 






















   
 
  Workshop  
 






















   
 
  Q&A  
 






















   
 
  Q Why do
Windows, X Windows, and Mac widgets all look so different?
 
 






















   
 
  A
Originally, Windows and X Windows widgets looked fairly similar because
they evolved from a common ancestor developed by HP. On X Windows, the
HP widgets transformed in a relatively straightforward way into Motif
widgets. Windows widgets, influenced by Mac widgets (which grew out of
similar objects developed at Xerox's Palo Alto Research labs), mutated
into Windows classes, which changed appearance yet again in the
transition from Windows 3.1 to Windows 95. The developers of Tk/TCL
originally used widgets that looked the same on all three platforms, but
recently they have changed to using the native widget sets for the three
differing platforms. The reason for the change, I suspect, is that the
portable widgets looked so clunky.
 
 






















   
 
  Q One kind of
widget I see a lot of on Windows is a list combined with a scrollbar.
What are these, and are they available in Tkinter?
 
 






















   
 
  A These
are usually called combo boxes, and they are not available in Tkinter
itself. However, Greg McFarlane, in Australia, has put together an
extremely nice package called ''Python Megawidgets," which does include
combo boxes; it can be found at



http://www.dscpl.com.au/pmw/
.
Greg says, "It consists of a set of base classes and a library of
flexible and extensible megawidgets built on this foundation. These
megawidgets include notebooks, comboboxes, selection widgets, paned
widgets, scrolled widgets, dialog windows, etc." They're also written in
pure Python, with no C extensions needed (this is important if you don't
have a C compiler on your machine).
 
 






















   
 
  Quiz  
 






















   
 
  1. What kind of
widget operates like a toggle switch?
 
 























 
 
  a. Button  
 























 
 
  b. List  
 


 




 


 
















   







Page
317























 
 
  c. Check box  
 























 
 
  d. Entry  
 






















   
 
  2. What's the
difference between menu bars and option menus?
 
 























 
 
  a. Menu bars run
across the whole top of the application's main window; option menus are
in a bar at the bottom of the window.
 
 























 
 
  b. Menu bar
menus pull down; option menus pull sideways.
 
 























 
 
  c. Option menus
can appear anywhere in a window, whereas menu bars have to be at the
top.
 
 























 
 
  d. Only the
names are different; they are otherwise the same.
 
 






















   
 
  Answers  
 






















   
 
  1. c, check box
widgets operate like toggle switches; they only have two states: checked
and unchecked.
 
 






















   
 
  2. c, option
menus can be used anywhere in a window; menu bars run across the top.
 
 






















   
 
  Exercises  
 






















   
 
  Take out Alien
Abduction Life Insurance, in case you get kidnapped by the Heechee. Make
Scott Meyers the beneficiary. Get abducted. Try to file a claim.
 
 






















   
 
  Research the
history of GUI programming; an excellent starting point is Michael S.
Hoffman's interesting Web page, ''The Unix GUI Manifesto," to be found
at



http://www.cybtrans.com/infostrc/unixgui.htm
.
 
 


 




No comments: