Tkinter tinkering (Graphical User Interfaces)
July 18, 2011 12 Comments
Man Shut up! (It goes quiet next door) That’s better.
He walks to a side wall and hangs his club on a hook beneath big old-fashioned art-nouveau sign clearly labelled `The Burlington Wall-banger’. He goes across to bed and gets in. In the bed are a party of four Japanese businessmen in suits with lapel badges, two lady American tourists with rain hats and cameras, three other moustached English gentlemen in pyjamas, four Tour De France riders, three Swedish businessmen, and Winston Churchill.
So far we have been dealing with a command line interface for working with our Python programs. While command lines are good for a lot of things, they’re usually pretty bad for interfacing with a general user of the program who doesn’t know how the various pieces work. What we are going to look at now is a different way of presenting the program to a user (and probably a way that you are more familiar with) – GUIs. GUI stands for “Graphical User Interface”.
In order to use a GUI, we need to use an external module to do all the grunt work behind making the interface components and presenting them to the end user. There are a number of different modules which can be used. We are going to use one called “Tkinter“. We are going to use Tkinter because it should come as part of every Python installation, so there’s no additional downloading to do, nor any need to get the Responsible Adult involved – but leave a comment if you have problem with Tkinter.
To start using Tkinter is pretty easy. You do this:
>>> from Tkinter import *
and… absolutely nothing should happen!
DANGER WILL ROBINSON!
A word of warning here: as a general rule using “from X import *” is considered really bad form in Python because it means every object (* is a “wildcard” and means everything) is imported by its own name into your program, rather than part of the X namespace. So, in our previous examples we’ve used import random, then accessed the randint() function via the random namespace: random.randint(). Had we used from random import *, then we could have said randint() and not random.randint(). However, this would be a bad thing to do. If you have two packages X and Y, each of which has its own object called x, then, if you use “import *” the two objects X.x and Y.x will both end up in your program called ‘x’. As you don’t have the X and Y namespaces to distinguish them, they ‘collide’.
So, why am I using “import *” for you? Because Tkinter is an exception. The Tkinter package has been designed so that as few objects as possible are imported into your program, and because their names are specifically GUI related, so there is less risk of a naming collision. If you are feeling uneasy about all this do multiple imports of the specific Tkinter components you need.
Hello World in the GUI
Graphical User Interfaces use a specific, common set of graphical components to display information to a user and to get feedback from them. These components are called “widgets”. As you are using a graphical interface all of the time, you are actually already aware of widgets, but you just don’t realise that they’re there. So, for example, whenever you are presented with an “Ok/Cancel” dialog on the computer, the text of the dialog (“About to delete all your files”) is presented in a “Label” widget, while the “Ok” and “Cancel” are “Button” widgets.
So let’s do a label:
>>> labelWidget = Label(None,text="Hello Python4Kids!") # note: None has a capital
When you hit return you should see something like this (note: if you are running python-idle, this won’t work – at least not yet, run Python from a command line shell. If you don’t know what python-idle is, you can ignore this note):
Python has told Tkinter it’s going to need a window to put a Label widget in. Tkinter has asked the operating system to give it a window and the operating system has given it a default window. Along the top of the window are a number of widgets which have been provided by your operating system (not Python). Your window may look a little different if you’re running an alternative operating system. On my system above, there are 6 widgets – from left to right, a menu widget (X), a button (to pin this window across multiple desktops), a label ‘tk’, and three more buttons (minimise, maximise and close). You might have a different set of operating system widgets.
Where is the label we defined? Well, it exists:
>>> labelWidget <Tkinter.Label instance at 0x7fcf9966e368>
However, it’s not visible yet. It’s not visible yet because we haven’t defined a “geometry” for it. We do this through a function which is part of the widget called .pack() (.pack() is called a ‘method’ of the widget, but we haven’t done that yet).
Debugging tip: If you can’t see your widget, make sure you’ve .pack()ed it.
So let’s .pack() it:
The .pack() method can take a heap of arguments, which define how the widget is to be placed within the window. As we only have a single widget, we just use the default packing, and therefore put no arguments in. You should see the tk window above change to look something like this:
One of the widgets in the title bar is obscured here (only four are visible), but grabbing the bottom right hand corner of the window will resize it allowing you to see the lost widgets:
To close the window click the close button in the top right corner.
That’s it for now, more on GUIs in the coming tutes.
Did you notice that we did a basic GUI interface in only three lines of code (including the import statement)??? Is that amazing?
Hello to visitors from the Podnutz webcast.