Python Notes Module5
Python Notes Module5
Creating Graphical User interface: Building a Basic GUI, Models, Views, and Controllers,
Customizing the Visual Style Introducing few more Widgets, Object-Oriented GUIs, Keeping the
Concepts from Being a GUI Mess.
In all the programs we wrote till now, we have designed our program around functions i.e.
blocks of statements which manipulate data. This is called the procedure-oriented way of
programming.
There is another way of organizing your program which is to combine data and
functionality and wrap it inside something called an object. This is called the object
oriented programming paradigm.
Phase 3 Figuring out what features you want your type to have.
2. Figuring out what type(s) we might want. A good starting point is to read the description of the
problem domain and look for the main nouns and noun phrases.
3. Figuring out what features we want our type to have. Here we should write some code that uses
the type we’re thinking about, much like we did with the Book code at the beginning of this chapter.
This is a lot like the Examples step in the function design recipe, where we decide what the code
that we’re about to write should do.
4. Writing a class that represents this type. We now need to tell Python about your type. To do this,
we will write a class, including a set of methods inside that class.
5. Testing our code. Our methods will have been tested separately as we followed the function
design recipe, but it’s important to think about how the various methods will interact.
class Dog:
pass
The body of the Dog class consists of a single statement: the pass keyword. pass is
often used as a placeholder indicating where code will eventually go. It allows
you to run this code without Python throwing an error.
Creating a new object from a class is called instantiating an object. You can
instantiate a new Dog object by typing the name of the class, followed by opening
and closing parentheses:
We now have a new Dog object at 0x106702d30. This funny-looking string of letters and
numbers is a memory address that indicates where the Dog object is stored in your computer’s
memory. Note that the address you see on your screen will be different.
• Fields are of two types - they can belong to each instance/object of the class or they can
belong to the class itself. They are called instance variables and class
variables respectively.
• A class is created using the class keyword. The fields and methods of the class are listed in
an indented block.
OOP Terminology
Class − A user-defined prototype for an object that defines a set of attributes that
characterize any object of the class. The attributes are data members (class variables and
instance variables) and methods, accessed via dot notation.
Class variable − A variable that is shared by all instances of a class. Class variables are
defined within a class but outside any of the class's methods. Class variables are not used
as frequently as instance variables are.
Function overloading − The assignment of more than one behavior to a particular function.
The operation performed varies by the types of objects or arguments involved.
Instance variable − A variable that is defined inside a method and belongs only to the
current instance of a class.
Inheritance − The transfer of the characteristics of a class to other classes that are derived
from it.
Instance − An individual object of a certain class. An object obj that belongs to a class
Circle, for example, is an instance of the class Circle.
Object − A unique instance of a data structure that's defined by its class. An object
comprises both data members (class variables and instance variables) and methods.
Operator overloading −The assignment of more than one function to a particular operator.
The class has a documentation string, which can be accessed via ClassName.__doc__.
The class_suite consists of all the component statements defining class members, data
attributes and functions.
class Employee:
'Common base class for all employees'
empCount = 0
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
The first method __init__() is a special method, which is called class constructor or
initialization method that Python calls when you create a new instance of this class.
You declare other class methods like normal functions with the exception that the first
argument to each method is self. Python adds the self argument to the list for you;
you do not need to include it when you call the methods.
• when you call the method, Python will provide it. This particular variable refers to the
object itself, and by convention, it is given the name self.
• This also means that if you have a method which takes no arguments, then you still have
to have one argument - the self.
• There are many method names which have special significance in Python classes. We will
see the significance of the __init__ method now.
• The __init__ method is run as soon as an object of a class is instantiated. The method is
useful to do any initialization you want to do with your object. Notice the double
underscores both at the beginning and at the end of the name.
Accessing Attributes
• You access the object's attributes using the dot operator with object. Class variable would
be accessed using class name as follows −
Example:
class Employee:
'Common base class for all employees'
empCount = 0
def displayCount(self):
print("Total Employee %d" % Employee.empCount)
def displayEmployee(self):
print("Name : ", self.name, ", Salary: ", self.salary)
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)
Function “Isinstance,”
• Function isinstance reports whether an object is an instance of a class—that is, whether
an object has a particular type:
>>> isinstance('abc', str)
True
>>> isinstance(55.2, str)
False
• 'abc' is an instance of str, but 55.2 is not.
Note: Python has a class called object. Every other class is based on it.
>>> isinstance(55.2, object)
True
>>> isinstance('abc', object)
True
Special Methods
• Consider
>>> print(python_book)
<book.Book object at 0x59f410>
• This is the default behavior for converting objects to strings: it just shows us where the object is
in memory. This is the behavior defined in class object’s method __str__, which our Book class
has inherited.
• If we want to present a more useful string, we need to explore two more special methods,
__str__ and __repr__.
• __str__ is called when an informal, human-readable version of an object is needed, and is called
when unambiguous, but possibly less-readable, outp__repr__ ut is desired.
• In particular, __str__ is called when print is used, and it is also called by function str and
by string method format.
• Let’s define method Book.__str__ to provide useful output; this method goes inside class
Book,
def __str__(self):
return """Title: {0} Authors: {1} Publisher: {2} ISBN: {3} Price:
Rs{4}""".format(self.title, ', '.join(self.authors),
self.publisher, self.ISBN, self.price)
Complete Example:
class Book:
def __init__(self, title, authors, publisher,
isbn, price):
self.title = title
self.authors = authors[:]
self.publisher = publisher
self.ISBN = isbn
self.price = price
def num_authors(self):
return len(self.authors)
def __str__(self):
return """Title: {0} Authors: {1} Publisher: {2}
ISBN: {3} Price: Rs{4}""".format(self.title,
','.join(self.authors), self.publisher, self.ISBN,
self.price)
Printing a Book now gives more useful information:
>>> python_book = Book(
... 'Practical Programming',
... ['Campbell', 'Gries', 'Montojo'],
... 'Pragmatic Bookshelf',
... '978-1-93778-545-1',
... 25.0)
Example:
class Book:
def __init__(self, title, authors, publisher, isbn, price):
self.title = title
self.authors = authors[:]
self.publisher = publisher
self.ISBN = isbn
self.price = price
def num_authors(self):
return len(self.authors)
def __repr__(self):
return '''Title=%s
Authors = %s
Publisher = %s
ISbN = %s
Price=%f''' % (self.title,self.authors, self.publisher,
self.ISBN, self.price)
python_book1 = Book("Programming with Python",
['Satish', 'Suma', 'Roopa', 'Rajani'],
'GaneshXerox',
'1-244-211',
500.00)
print(python_book1)
Python Inheritance
Inheritance allows us to define a class that inherits all the methods and properties from another
class.
Parent class is the class being inherited from, also called base class.
Child class is the class that inherits from another class, also called derived class.
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
def printname(self):
print(self.firstname, self.lastname)
#Use the Person class to create an object, and then execute the
printname method:
x = Person("Rama", "Satish")
x.printname()
Example Create a class named Student, which will inherit the properties and methods from the
Person class:
def display(self):
print(self.firstname, self.lastname)
class Student(Person):
pass
x = Student("Sairam", "Srivatsa")
x.display()
Note: The __init__() function is called automatically every time the class is being used to
create a new object.
# parent class
class Person( object ):
# child class
class Employee( Person ):
def __init__(self, name, idnumber, salary, post):
self.salary = salary
self.post = post
def display(self):
print(self.name, self.idnumber, self.salary, self.post)
1. Single inheritance: When a child class inherits from only one parent class, it is called
single inheritance. We saw an example above.
2. Multiple inheritance: When a child class inherits from multiple parent classes, it is called
multiple inheritance. Unlike Java and like C++, Python supports multiple inheritance. We
specify all parent classes as a comma-separated list in the bracket.
class Base2(object):
def __init__(self):
self.str2 = "MCA"
print("Base2")
def printStrs(self):
print(self.str1, self.str2)
ob = Derived()
ob.printStrs()
# Constructor
def __init__(self, name):
self.name = name
# Constructor
def __init__(self, name, age):
Base.__init__(self, name)
self.age = age
# Constructor
def __init__(self, name, age, address):
Child.__init__(self, name, age)
self.address = address
# To get address
def display(self):
return self.name, self.age, self.address
# Driver code
g = GrandChild("RNSIT", 20, "Bengaluru")
print(g.display())
Magic Methods
Magic methods in Python are the special methods which add "magic" to your class. Magic
methods are not meant to be invoked directly by you, but the invocation happens internally from
the class on a certain action. For example, when you add two numbers using the + operator,
internally, the __add__() method will be called.
__pow__(self, other[, modulo]) To get called on calculating the power using ** operator.
__add__() method
In following example, a class named distance is defined with two instance attributes - ft and
inch. The addition of these two distance objects is desired to be performed using the overloading
+ operator. To achieve this, the magic method __add__() is overridden, which performs the
addition of the ft and inch attributes of the two objects. The __str__() method returns the object's
string representation.
Example:
class distance:
def __init__(self, x=None,y=None):
self.ft=x
self.inch=y
def __add__(self,x):
temp=distance()
temp.ft=self.ft+x.ft
temp.inch=self.inch+x.inch
if temp.inch>=12:
temp.ft+=1
temp.inch-=12
return temp
def __str__(self):
return 'ft:'+str(self.ft)+' in: '+str(self.inch)
Run the above Python script to verify the overloaded operation of the + operator.
As you already know, most modern programs interact with users via a graphical user interface,
or GUI, which is made up of windows, menus, buttons, and so on. In this chapter, we will show
you how to build simple GUIs using a Python module called tkinter. Along the way, we will
introduce a different way of structuring programs called event-driven programming. A
traditionally structured program usually has control over what happens when, but an event-
driven program must be able to respond to input at unpredictable moments. tkinter is one of
several toolkits you can use to build GUIs in Python. It is the only one that comes with a standard
Python installation.
import tkinter
window = tkinter.Tk()
label = tkinter.Label(window, text='This is our label.')
label.pack()
window.mainloop()
• Method call label.pack() is crucial. Each widget has a method called pack that places
it in its parent widget and then tells the parent to resize itself as necessary. If we forget to
import tkinter
window = tkinter.Tk()
label = tkinter.Label(window, text='First label.')
label.pack()
label.config(text='Second label.')
window.mainloop()
import tkinter
window = tkinter.Tk()
data = tkinter.StringVar()
data.set('Data to display')
label = tkinter.Label(window, textvariable=data)
label.pack()
window.mainloop()
Example 2:
import tkinter
window = tkinter.Tk()
frame = tkinter.Frame(window, borderwidth=4, relief=tkinter.GROOVE)
frame.pack()
first = tkinter.Label(frame, text='First label')
first.pack()
second = tkinter.Label(frame, text='Second label')
second.pack()
third = tkinter.Label(frame, text='Third label')
third.pack()
window.mainloop()
Note: The other border styles are SUNKEN, RAISED, GROOVE, and RIDGE
Label Widget
import tkinter
parent_widget = tkinter.Tk()
label_widget = tkinter.Label(parent_widget, text="A Label")
Button Widget
import tkinter
parent_widget = tkinter.Tk()
button_widget = tkinter.Button(parent_widget, text="A Button")
button_widget.pack()
tkinter.mainloop()
Entry Widget
import tkinter
parent_widget = tkinter.Tk()
entry_widget = tkinter.Entry(parent_widget)
entry_widget.insert(0, "Type your text here")
entry_widget.pack()
tkinter.mainloop()
import tkinter
parent_widget = tkinter.Tk()
v = tkinter.IntVar()
v.set(1) # need to use v.set and v.get to
# set and get the value of this variable
radiobutton_widget1 = tkinter.Radiobutton(parent_widget, text="Radiobutton 1",
variable=v, value=1)
radiobutton_widget2 = tkinter.Radiobutton(parent_widget, text="Radiobutton 2",
variable=v, value=2)
radiobutton_widget1.pack()
radiobutton_widget2.pack()
tkinter.mainloop()
We can display a Radiobutton without the dot indicator. In that case it displays its
state by being sunken or raised.
import tkinter
parent_widget = tkinter.Tk()
checkbutton_widget = tkinter.Checkbutton(parent_widget,
text="Checkbutton")
checkbutton_widget.select()
checkbutton_widget.pack()
tkinter.mainloop()
import tkinter
parent_widget = tkinter.Tk()
scale_widget = tkinter.Scale(parent_widget, from_=0, to=100,
orient=tkinter.HORIZONTAL)
scale_widget.set(25)
scale_widget.pack()
tkinter.mainloop()
Text Widget
import tkinter
parent_widget = tkinter.Tk()
text_widget = tkinter.Text(parent_widget,
width=20, height=3)
text_widget.insert(tkinter.END,
"Text Widgetn20 characters widen3 lines high")
text_widget.pack()
tkinter.mainloop()
LabelFrame Widget
import tkinter
parent_widget = tkinter.Tk()
labelframe_widget = tkinter.LabelFrame(parent_widget,
text="LabelFrame")
label_widget=tkinter.Label(labelframe_widget,
text="Child widget of the LabelFrame")
labelframe_widget.pack(padx=10, pady=10)
label_widget.pack()
tkinter.mainloop()
Canvas Widget
import tkinter
parent_widget = tkinter.Tk()
canvas_widget = tkinter.Canvas(parent_widget, bg="blue", width=10,
height= 50)
canvas_widget.pack()
Listbox Widget
import tkinter
parent_widget = tkinter.Tk()
listbox_entries = ["Entry 1", "Entry 2",
"Entry 3", "Entry 4"]
listbox_widget = tkinter.Listbox(parent_widget)
for entry in listbox_entries:
listbox_widget.insert(tkinter.END, entry)
listbox_widget.pack()
tkinter.mainloop()
Menu Widget
import tkinter
parent_widget = tkinter.Tk()
def menu_callback():
print("I'm in the menu callback!")
def submenu_callback():
print("I'm in the submenu callback!")
menu_widget = tkinter.Menu(parent_widget)
submenu_widget = tkinter.Menu(menu_widget, tearoff=False)
submenu_widget.add_command(label="Submenu Item1",
command=submenu_callback)
submenu_widget.add_command(label="Submenu Item2",
command=submenu_callback)
menu_widget.add_cascade(label="Item1", menu=submenu_widget)
menu_widget.add_command(label="Item2", command=menu_callback)
menu_widget.add_command(label="Item3", command=menu_callback)
parent_widget.config(menu=menu_widget)
tkinter.mainloop()
• This MVC design helps separate the parts of an application, which will make the application
easier to understand and modify.
• The main goal of this design is to keep the representation of the data separate from the parts of
the program that the user interacts with; that way, it is easier to make changes to the GUI code
without affecting the code that manipulates the data.
• As its name suggests, a view is something that displays information to the user, like Label.
Many views, like Entry, also accept input, which they display immediately. The key is that they
don’t do anything else: they don’t calculate average temperatures, move robot arms, or do any
other calculations.
• Models, on the other hand, store data, like a piece of text or the current inclination of a
telescope. They also don’t do calculations; their job is simply to keep track of the application’s
current state (and, in some cases, to save that state to a file or database and reload it later).
• Controllers are the pieces that convert user input into calls on functions in the model that
manipulate the data. The controller is what decides whether two gene sequences match well
enough to be colored green or whether someone is allowed to overwrite an old results file.
Controllers may update an application’s models, which in turn can trigger changes to its views.
Example :
import tkinter
# The controller.
def click_up():
counter.set(counter.get() + 1)
def click_down():
counter.set(counter.get() - 1)
# The model.
counter = tkinter.IntVar()
counter.set(0)
window.mainloop()
Lambda Functions
• The name lambda function comes from lambda calculus, a mathematical system for
investigating function definition and application that was developed in the 1930s by
Alonzo Church and Stephen Kleene.
• The lambda form does not create a new variable or change an existing one. Finally,
lambda functions can take arguments, just like other functions:
• The simple counter GUI shown earlier does what it’s supposed to, but there is room for
improvement.
• For example, suppose we want to be able to lower the counter’s value as well as raise it.
• So how does this help us with GUIs? The answer is that it lets us write one controller
function to handle different buttons in a general way and then wrap up calls to that
function when and as needed. Here’s the two-button GUI once again using lambda
functions:
import tkinter
# The controller.
def click(var, value):
var.set(var.get() + value)
# The model.
counter = tkinter.IntVar()
counter.set(0)
# The views.
window = tkinter.Tk()
frame = tkinter.Frame(window)
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=('Bookman', 14, 'bold italic'))
button.pack()
window.mainloop()
import tkinter
window = tkinter.Tk()
button = tkinter.Label(window, text='Hello', bg='green', fg='white')
button.pack()
window.mainloop()
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
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()
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, grid()
Parameters.
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()
Object-Oriented GUIs
• The GUIs we have built so far have not been particularly well structured. Most of the code
to construct them has not been modularized in functions, and they have relied on global
variables. We can get away with this for very small examples, but if we try to build larger
applications this way, they will be difficult to understand and debug.
• For this reason, almost all real GUIs are built using classes and objects that tie models,
views, and controllers together in one tidy package. In the counter shown next, for example,
the application’s model is a member variable of class Counter, accessed using self.state,
and its controllers are the methods upClick and quitClick.
class Counter:
"""A simple counter GUI using object-oriented programming."""
def __init__(self, parent):
# Framework.
self.parent = parent
self.frame = tkinter.Frame(parent)
self.frame.pack()
# Model.
self.state = tkinter.IntVar()
self.state.set(1)
def up_click(self):
"""Handle click on 'up' button."""
self.state.set(self.state.get() + 1)
def down_click(self):
"""Handle click on 'down' button."""
self.state.set(self.state.get() - 1)
def quit_click(self):
"""Handle click on 'quit' button."""
self.parent.destroy()
if __name__ == '__main__':
window = tkinter.Tk()
myapp = Counter(window)
window.mainloop()