IT 117: Intermediate Scripting
The final exam will be given on Tuesday, May 15th from 6:30 - 9:30.
The exam will be given in the same room we use for this class.
It will consist of questions like those on the quizzes along with questions
asking you to write short segments of Python code.
60% of the points on this exam will consist of questions from the Ungraded
Class 28, on Thursday May 3rd, will be a review session.
Even though classes do not end until the following week, Class 28 will be the last class.
Instead of having a Class 29, I will have Office Hours all day, from 11 AM to 6 PM.
You will only be responsible for the material in Class Notes 28
and the review for the Mid-term, which you will find
Although the time alloted for the exam is 3 hours, I would
expect that most of you would not need that much time.
You will not be able to leave the room until you turn in your exam paper
so you should visit the restroom before you take the test.
The final is a closed book exam.
- Graphics programs run in widows ...
- which the user can resize in any way they like
- This means that we need a flexible way to determine ...
- where any particular widget should appear on the screen ...
- regardless of how the user resizes the window
- What if you create a label that has a certain number of characters ...
- and the user decides to narrow the screen ...
- so that all characters cannot appear on the same line?
- Tkinter handles this very difficult task ...
- through things called
layout managers ...
- or geometry managers
- These managers are complicated chunks of code ...
- that arrange widgets inside the window
- Tkinter provides three layout managers
- Every time you create a widget ...
- you must call a layout manager ...
- to place the widget in the window ...
- or the widget will not appear
The pack Layout Manager
- pack also has options
- The side option can be given the following values
- If I use want the buttons to align vertically ...
- instead of horizontally ...
- I can write use this code
self.l1 = Label(self.root, text="First label", fg="red")
self.l2 = Label(self.root, text="Second label", fg="green")
self.l3 = Label(self.root, text="Third label", fg="blue")
- The window now looks like this
- A Frame is a container ...
- that can hold other widgets
- Let's create a window with two frames ...
- that hold multiple labels
- First we create the window and two frames
self.top_frame = Frame(self.root)
self.bottom_frame = Frame(self.root)
- Note that the parent ojbect for the frames is the root object
- When we create the label widgets ...
- we don't give them the root object as their parent ...
- instead we give them their respective frames
self.l1 = Label(self.top_frame, text="Red label", fg="red")
self.l2 = Label(self.top_frame, text="Green label", fg="green")
self.l3 = Label(self.top_frame, text="Blue label", fg="blue")
self.l4 = Label(self.bottom_frame, text="Magenta label", fg="magenta")
self.l4 = Label(self.bottom_frame, text="Cyan label", fg="cyan")
- But nothing happens until we run pack ...
- on each frame
- When we run this, we see
The grid Layout Manager
- The grid layout manager allows you to align widgets ...
- both horizontally and vertically ...
- like the cells in a spreadsheet
- To use grid you assign widgets two integers ...
- a column number and a row number ...
- both of which start at 0
- You can skip rows and columns ...
- if you want to save space for future additions
- Here is code with four labels laid out using grid
self.l1 = Label(self.root, text="Red", fg="red")
self.l2 = Label(self.root, text="Green", fg="green")
self.l3 = Label(self.root, text="Blue", fg="blue")
self.l4 = Label(self.root, text="Magenta", fg="magenta")
- And this is what we see when the code is run
- grid adjusts the width of each column ...
- to make it wide enough ...
- for the widest element
- Buttons have some action connected to them
- When a user clicks on a button ...
- the action connected to it takes place
- When we create a Button widget ...
- we have to give it the parent object ...
- which can then be followed by a number of attributes
- The two most important attributes are
- text - the button text
- command - the function run when the button is clicked
- The value given to the command attribute ...
- is the name of a function
- When the button is clicked ...
- this function is run
- Here is a simple program that creates a window ...
- with a single button ...
- that causes the program to quit ...
- when it is clicked
from tkinter import *
self.button = Button(self.root, text="Quit", command=quit)
root = ButtonWindow()
- quit is a function that causes Tkinter to quit
- When the code is run, a small window appears
- When I click the button ...
- the window disappears
The tkinter.messagebox Module
- The tkinter.messagebox module ...
- contains a number of functions ...
- which will display different types of dialog boxes
- The first three functions are similar
- They each display a dialog box with some text ...
- along with a "OK" button ...
- that causes the dialog box to disappear when clicked
- In order to use any of these functions ...
- we have to import the tkinter.messagebox module
- The following script creates a window with a button ...
- that causes a info dialog box to appear ...
- when clicked
self.button = Button(self.root, text="Click for showinfo box", command=self.action)
tkinter.messagebox.showinfo("Show Info", "This is a message box created by showinfo")
- When run a small window appears
- When you click on the button ...
- a dialog box appears
- showerror should display a different icon ...
- but it doesn't on my Mac
- The icon you get depends on the Python interpreter
Making Things Happen in a Window
- We can make a dialog box appear using a button
- We do this by using the command option ...
- to the Button constructor
- The value we give this option is the
- A callback function is code that will be executed ...
- when the widget
to which it is attached ...
- is activated by some user action
- Another name for a callback function is an
- Though we often use Button object to invoke
a callback function ...
- They can be associated with other widgets
- The callback function can be a function provided by Tkinter ...
- like quit ...
- or it can be a
inside the root window object
- When a user clicks a button ...
- an event is created
- Once you call the mainloop method ...
- of the root window ...
- the event loop is started
- The program loops endlessly ...
- processing each event as it occurs ...
- by calling the proper event handler
- The operating system creates events ...
- after the user takes some action
- These events include
- Pressing a button
- Hitting a key
- Moving the mouse
- Resizing a window
- When the users does something ...
- the operating system creates an event to record that action ...
- and passes it to the event loop
- Tkinter can create it's own events ...
- such as when a geometry manager is called ...
- to place a widget on the screen
- The event loop calls the proper event handler
- The program stays in the event loop until the window is closed
The Entry Widget
- Dialog boxes are great for getting a simple answer ...
- to a question
- But what if we wanted to more information ...
- than yes or no?
- Say we wanted to write a program ...
- to convert one unit of measurement ...
- into another
- We need something into which the user can type ...
- and from which the Python interpreter can get the value
- This is the job of the Entry widget
- This widget creates an rectangular area
- When the user clicks inside this area ...
- a text insertion point becomes active ...
- and the user can enter text
- Each Entry widget has a get method ..
- which returns the text entered by the user
- A typical Python graphics program will have a window ...
- with one or more Entry widgets ...
- along with a button that the user clicks to submit the data
- This button will have a callback function ...
- that uses the objects get method ...
- to perform some operation
- The get method returns a string ...
- which the callback function may have to convert to the proper type
Converting Kilometers to Miles
- To illustrate the use of an Entry widget ...
- let's write a program that convert a distance measured in kilometers ...
- into miles
- The conversion formula is
miles = kilometers * 0.6214
- To arrange the needed widgets on the screen ...
- we will use two Frame objects
- The first Frame will have widgets for data entry ...
- and the second will have buttons
- Here is the code
# top frame
self.top_frame = tkinter.Frame(self.root)
self.prompt_label = \
tkinter.Label(self.top_frame, text="Enter a distance in kilometers:')
self.kilo_entry = tkinter.Entry(self.top_frame, width=10)
# bottom frame
self.bottom_frame = tkinter.Frame(self.root)
self.calc_button = \
tkinter.Button(self.bottom_frame, text="Convert', command=self.convert)
self.quit_button = \
tkinter.Button(self.bottom_frame, text="Quit', \
- When you run this script, you get
- Notice that the top frame has an Entry
widget kilo_entry ...
- highlighted in blue ..
- where the user can enter the value to be converted
- Notice also that the calc_button
highlighted in green ...
- calls the convert method whenever it is clicked
- This method will perform the calculation to create the new value
kilo = round(float(self.kilo_entry.get()), 2)
miles = round(kilo * 0.6214, 2)
str(kilo) + ' kilometers is equal to ' + \
str(miles) + ' miles.')
- The code first obtains the value entered in the kilo_entry
- and converts this into a float
- Remember, the get on such a widget ...
- returns a string
- The script then performs the conversion calculation ...
- and rounds the results ...
- before displaying the results in a showinfo messagebox
- When a value is entered in the Entry widget
- and the Convert button is clicked ...
- a messagebox appears with the converted value
- You can see the code for this script here.
Using Labels as Output Fields
- Using a messagebox to display a calculated value as we just did ...
- is not good interface design
- If you wanted to converted another value ...
- you would have to close the messagebox ...
- before entering a new value
- A better option would be to display the converted value ...
- inside the original window
- We don't need a new widget to do this
- We can use a Label widget for this purpose
- You do this using one of the special variable classes ...
- provided by Tkinter
- These variables allow you to pass the value of a Python variable ...
- to a widget
- There are four such classes
- DoubleVar - holds a
- To do this we first create an object ...
- to pass a value to the Label widget
- This will be done in a new middle frame
# mid frame
self.mid_frame = Frame(self.root)
self.descr_label = \
Label(self.mid_frame, text="Converted to miles:')
self.value = StringVar()
self.miles_label = \
- When run, the following appears
- Notice in the code above that the StringVar object value ...
- highlighted in blue ...
- is created before the label object miles_label ...
- marked in green
- We have to do this so we can pass this widget to the label ...
- using the
textvariable attribute to the Label constructor
- Why did we use a StringVar object ...
- to pass a value to the label?
- Because each of these classes of variable objects has a default value
- The default value for a DoubleVar object is 0.0 ...
- while that for a StringVar object is the empty string
- Now that we have the technical details out of the way ...
- let's see a StringVar object in action
- First we enter a value in the input field
- Then we click the Convert button
- Entry objects are not the only widget ...
- that can be used to get values from a user
- Whenever you write code that interacts directly with a user ...
- you have to make sure that the value received is meaningful
- If you asked a user for their age ...
- you would expect an integer
Entry object will accept any value that can be written as a string
- So whenever you use such an object for user input ...
- you need to check whether the value entered ...
- is appropriate
- This effort is called
- and you may need a significant amount of code ...
- to perform this function
- One way to limit the data validation you have to perform ...
- is to use widgets that limit the possible entry values
- One such widget is a RadioBotton
- Radio buttons are GUI elements that allow a user ...
- to chose a single value ...
- from a list of choices
- The user can only chose one value
- If the user clicks a second radio button ...
- the original button is deselected
- A RadioButton object contains a specific value ...
- that can be assigned to a variable inside the Python code
- This value is given to the code through an object ...
- of one the variable classes we used with an Entry object
- So before we create a
RadioButton object ...
- we have to create a variable object of the correct type ...
- to hold the value
- The constructor for a RadioButton object must be given it's parent widget ...
- and is usually given values for the following attributes
- text - The label appearing to the right of the button
- variable - The variable object that will hold the value
- value - The value assigned to that button
- command - A function that is called when the button is selected
A RadioButton Example
- Let's say we need to offer the user a choice ...
- from among the following list of languages
- Since only one language can be selected ...
- we need to create a RadioButton object for each choice
- We create a Frame object to hold all the buttons
self.top_frame = Frame(self.root)
- But first we need create a StringVar object ...
- to associate with each of these objects
self.radio_var = StringVar()
- It is also a good idea to assign a
to this object ...
- which we can do using it's set method
- Now we can create a RadioButton object for each choice
self.rb1 = Radiobutton(self.top_frame, \
text="English', variable=self.radio_var, \
self.rb2 = Radiobutton(self.top_frame, \
text="Spanish', variable=self.radio_var, \
self.rb3 = Radiobutton(self.top_frame, \
text="French', variable=self.radio_var, \
self.rb4 = Radiobutton(self.top_frame, \
text="Arabic', variable=self.radio_var, \
- Although the purpose of a RadioButton object
is to give a value to a variable ...
- it can also be used run a function ...
- that will be run whenever the button is selected
- For this example clicking the button will display the value selected
- When we run this script we get
- When you click on a radio button, the value selected appears
- You can view the code here
- If you want to restrict the values a user can enter ...
- but you want to give them more than one choice ...
- you should use a CheckBox object
- The user can select as many check boxes as they wish
- Just as with a RadioButton object ...
- you need to create a variable object for CheckBox objects
- But while one variable object is shared by all RadioButton objects ...
- each CheckBox object needs it's own variable object
- Another difference is the type of variable object
- A RadioButton object can be associated with any variable type
- A check box can really only have two values ...
- on or off
- So a better choice for the variable class for each CheckBox object ...
- is a BooleanVar
- The constructor for a CheckBox object must have a parent widget
- The constructor will also take a text attribute ...
- which is the label for each selection ...
- and a variable attribute ...
- specific for that choice
- It can also take a command attribute ...
- whose value is the name of the function that is fired ...
- when the check box is clicked
A CheckBox Example
- Let's create a script which will use check boxes ...
- to select from various services offered by a small garage
- Oil change
- Tire rotation
- First we create a BooleanVar object for each service
self.cb_var1 = BooleanVar()
self.cb_var2 = BooleanVar()
self.cb_var3 = BooleanVar()
- and initialize each value to
- Now we can create three CheckBox objects
self.cb1 = Checkbutton(self.top_frame, text="Oil change', \
self.cb2 = Checkbutton(self.top_frame, text="Inspection', \
self.cb3 = Checkbutton(self.top_frame, text="Tire rotation', \
- Notice that I gave each check box a callback function
- Most scripts using check boxes would not set this attribute ...
- but I wanted to show what happens when each box is checked
- So I created the following callback function
choices = 
choice_list = ''
for choice in choices:
choice_list += choice + '\n'
- Here is what I get when I run the script for the first time
- And here is what happens when I select different buttons
Designing User Interfaces
- When we write command line scripts the user interface is simple
- Often we get input from the command line ...
- and then print the results to the screen
- But once you create a script that uses graphics ...
- things get more complicated
- Command line programs are usually run by technical people ...
- who are not frightened by the command line
- But graphical programs are usually created for a more general audience ...
- where you cannot assume much technical experience
- Creating a good user interface design for a program is not easy
- It's almost more art than science
- You need to know quite a bit about the psychology of perception
- That is why most organizations that develop software hire special programmers ...
- to work on the user interface
- It is easy to create a bad user interface ...
- and very hard to create a good one
- I general rule I follow when