© Magnus Lie Hetland 2017

Magnus Lie Hetland, Beginning Python, 10.1007/978-1-4842-0028-5_12

12. Graphical User Interfaces

Magnus Lie Hetland

(1)Trondheim, Norway

In this rather short chapter, you’ll learn the basics of how to make graphical user interfaces (GUIs) for your Python programs—you know, windows with buttons and text fields and stuff like that. The de facto standard GUI toolkit for Python is Tkinter, which ships as part of the standard Python distribution. Several other toolkits are available, however. This has its advantages (greater freedom of choice) and drawbacks (others can’t use your programs unless they have the same GUI toolkit installed). Fortunately, there is no conflict between the various GUI toolkits available for Python, so you can install as many different GUI toolkits as you want.

This chapter gives a brief introduction to using Tkinter, and we’ll build on this in Chapter 28. Tkinter is easy to use, but there’s a lot to learn if you want to use all of its features. I’ll only scratch the surface here to get you going; for further details, you should consult the section on graphical user interfaces in the standard library reference. There you’ll find documentation for Tkinter, as well as links to sites with more in-depth information and suggestions for other GUI packages to use.

Building a Sample GUI Application

To demonstrate using Tkinter , I will show you how to build a simple GUI application. Your task is to write a basic program that enables you to edit text files. We aren’t going to write a full-fledged text editor but instead stick to the essentials. After all, the goal is to demonstrate the basic mechanisms of GUI programming in Python.

The requirements for this minimal text editor are as follows:

  • It must allow you to open text files, given their file names.

  • It must allow you to edit the text files.

  • It must allow you to save the text files.

  • It must allow you to quit.

When writing a GUI program, it’s often useful to draw a sketch of how you want it to look. Figure 12-1 shows a simple layout that satisfies the requirements for our text editor .

A326949_3_En_12_Fig1_HTML.gif
Figure 12-1. A sketch of the text editor

The elements of the interface can be used as follows:

  • Type a file name in the text field to the left of the buttons and click Open to open a file.

The text contained in the file is put in the text field at the bottom.

  • You can edit the text to your heart’s content in the large text field.

  • If and when you want to save your changes, click the Save button, which again uses the text field containing the file name and writes the contents of the large text field to the file.

  • There is no Quit button—we’ll just use the Quit command from the default Tkinter menus.

This might seem like a slightly daunting task, but it’s really a piece of cake.

Initial Exploration

To begin with, you must import tkinter. To keep its namespace separate but save some typing, you might want to rename it.

import tkinter as tk

There’s not much harm in just importing all of its contents, though, if you prefer. For some initial exploration, let’s just use the interactive interpreter.

>>> from tkinter import *

To start up the GUI, we can create a top-level component, or widget, which will act as our main window. We do this by instantiating a Tk object.

>>> top = Tk()

At this point, a window should appear. In an ordinary program, we would insert a call to the function mainloop here to enter into the Tkinter main event loop, rather than simply exiting the program. There’s no need for that in the interactive interpreter, but feel free to try.

>>> mainloop()

The interpreter will seem to hang while the GUI is still working. To keep going, quit the GUI and restart the interpreter.

Various widgets are available under rather obvious names. For example, to create a button, you instantiate the Button class. If there is no Tk instance, creating a widget will also instantiate Tk, so you can just jump right in.

>>> from tkinter import *
>>> btn = Button()

The button won’t be visible at this point—you need to use a layout manager (also known as a geometry manager) to tell Tkinter where to place it. We’ll be using the pack manager , which in its simplest form simply involves calling the pack method.

>>> btn.pack()

Widgets have various properties we can use to modify their appearance and behavior. The properties are available like dictionary fields, so if we want to give our button some text, all it takes is an assignment.

>>> btn['text'] = 'Click me!'

By now, you should have a window looking somewhat like this:

A326949_3_En_12_Figa_HTML.jpg

Adding some behavior to the button is also quite straightforward.

>>> def clicked():
...     print('I was clicked!')
...
>>> btn['command'] = clicked

If you click the button now, you should see the message printed out.

Rather than individual assignments, you can use the config method to set several properties at once.

>>> btn.config(text='Click me!', command=clicked)

You can also configure the widget using its constructor.

>>> Button(text='Click me too!', command=clicked).pack()

Layout

When we call pack on a widget, it is laid out within its parent widget, or master. The master widget may be supplied as an optional first argument to the constructor; if we don’t supply one, the main top-level window is used, as in the following snippet:

Label(text="I'm in the first window!").pack()
second = Toplevel()
Label(second, text="I'm in the second window!").pack()

The Toplevel class represents a top-level window beyond the main one, and Label is simply a text label.

Without any parameters, pack will simply stack widgets in a single, centered column, starting at the top of the window. For example, the following will result in a tall, thin window with a single column of buttons:

for i in range(10):
    Button(text=i).pack()

Luckily, you can adjust the positioning and stretching of your widgets. The side you pack a widget on is given by the side parameter, to which you supply LEFT, RIGHT, TOP, or BOTTOM. If you want the widget to fill out the space assigned to it in the x- or y-direction, you specify a fill value of X, Y, or BOTH. If you want it to grow as the parent (in this case, the window) grows, you can set expand to true. There are other options as well, for specifying anchoring and padding, though I won’t be using them here. To get a quick overview, you can use the following:

>>> help(Pack.config)

There are other layout manager options, which might suit your taste better, namely, grid and place. You call these methods on the widgets you’re laying out, just like with pack. To avoid trouble, you should stick to a single layout manager for one container, such as a window.

The grid method lets you lay out objects by placing them in the cells of an invisible table; you do this by specifying a row and column and possibly a rowspan or columnspan, if the widgets span multiple rows or columns. The place method lets you place widgets manually, by specifying the coordinates x and y, and the widgets’ height and weight. This is rarely a good idea but might be needed on occasion. Both of these geometry managers have additional parameters as well, which you can find by using the following:

>>> help(Grid.configure)
>>> help(Place.config)

Event Handling

As you’ve seen, we can supply an action for a button to take by setting the command property. This is a specialized form of event handling, for which Tkinter also has a more general mechanism: the bind method. You call this on the widget you want to handle a given kind of event, specifying the name of the event and a function to use. Here’s an example:

>>> from tkinter import *
>>> top = Tk()
>>> def callback(event):
...     print(event.x, event.y)
...
>>> top.bind('<Button-1>', callback)
'4322424456callback'

Here, <Button-1> is the name for a mouse click (or equivalent) using the left button (button 1). We bind it to the callback function, which is called whenever we click inside the top window. An event object is passed along to the callback, and it has various properties depending on the kind of event. For a mouse click, for example, it provides the x and y coordinates, which are printed in this example. Many other kinds of events are available. You can find a list by using

>>> help(Tk.bind)

and can find further information by consulting the sources described earlier .

The Final Program

At this point, we have roughly what we need to write the program. We just need to figure out the names of the widgets used for small text fields and larger text areas. A quick look at the documentation tells us that Entry is what we want for the single-line text fields. A multi-line, scrolled text area can be constructed by combining Text and Scrollbar, but there’s already an implementation available in the tkinter.scrolledtext module. The contents of an Entry can be extracted using its get method, while for the ScrolledText object, we will use the delete and insert methods, with appropriate arguments to indicate locations in the text. In our case, we’ll use '1.0' to specify the first line and the zeroth character (i.e., before the first character), END for the end of the text, and INSERT for the current insertion point. The resulting program is shown in Listing 12-1 and Figure 12-2.

A326949_3_En_12_Fig2_HTML.jpg
Figure 12-2. The final text editor

Listing 12-1. Simple GUI Text Editor
from tkinter import *
from tkinter.scrolledtext import ScrolledText


def load():
    with open(filename.get()) as file:
        contents.delete('1.0', END)
        contents.insert(INSERT, file.read())


def save():
    with open(filename.get(), 'w') as file:
        file.write(contents.get('1.0', END))


top = Tk()
top.title("Simple Editor")


contents = ScrolledText()
contents.pack(side=BOTTOM, expand=True, fill=BOTH)


filename = Entry()
filename.pack(side=LEFT, expand=True, fill=X)


Button(text='Open', command=load).pack(side=LEFT)
Button(text='Save', command=save).pack(side=LEFT)


mainloop()

You can try the editor using the following steps:

  1. Run the program. You should get a window like the one in the previous runs.

  2. Type something in the large text area (for example, Hello, world!).

  3. Type a file name in the small text field (for example, hello.txt). Make sure that this file does not already exist or it will be overwritten.

  4. Click the Save button.

  5. Quit the program.

  6. Restart the program.

  7. Type the same file name in the little text field.

  8. Click the Open button. The text of the file should reappear in the large text area.

  9. Edit the file to your heart’s content, and save it again .

Now you can keep opening, editing, and saving until you grow tired of that. Then you can start thinking of improvements. How about allowing your program to download files with the urllib module , for example?

You might also consider using more object-oriented design in your programs, of course. For example, you may want to manage the main application as an instance of a custom application class with methods for setting up the various widgets and bindings. See Chapter 28 for some examples. And as with any GUI package, Tkinter has a great selection of widgets and other classes for you to use. You should use help(tkinter) or consult the documentation for information on any graphical element you would like to use.

Using Something Else

The basics of most GUI toolkits are roughly the same. Unfortunately, however, when learning how to use a new package, it takes time to find your way through all the details that enable you to do exactly what you want. So you should take your time before deciding which package you want to work with (see, for example, the section on other GUI packages in the Python standard library reference) and then immerse yourself in its documentation and start writing code. I hope this chapter has provided the basic concepts you need to make sense of that documentation.

A Quick Summary

Once again, let’s review what we’ve covered in this chapter:

  • Graphical user interfaces (GUIs): GUIs are useful in making your programs more user friendly. Not all programs need them, but whenever your program interacts with a user, a GUI is probably helpful.

  • Tkinter: Tkinter is a mature and widely available cross-platform GUI toolkit for Python.

  • Layout: You can position components quite simply by specifying their geometry directly. However, to make them behave properly when their containing window is resized, you will need to use some sort of layout manager.

  • Event handling: Actions performed by the user trigger events in the GUI toolkit. To be of any use, your program will probably be set up to react to some of these events; otherwise, the user won’t be able to interact with it. In Tkinter, event handlers are added to components with the bind method.

What Now?

That’s it. You now know how to write programs that can interact with the outside world through files and GUIs. In the next chapter, you learn about another important component of many program systems: databases.

..................Content has been hidden....................

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