Module 5: Object-Oriented Programming and Graphical User interface
Introduction to OOP using Python
Object-oriented programming (OOP) is a method of structuring a program by
bundling related properties and behaviors into individual objects
Python is an object-oriented language, allowing you to structure your code using classes and
objects for better organization and reusability.
An object contains data, like the raw or preprocessed materials at each step
on an assembly line, and behavior, like the action each assembly line
component performs.
What Is Object-Oriented Programming in Python?
Object-oriented programming is a programming paradigm that provides a means
of structuring programs so that properties and behaviors are bundled into
individual objects.
For instance, an object could represent a person with properties like a name,
age, and address and behaviors such as walking, talking, breathing, and running.
Or it could represent an email with properties like a recipient list, subject, and
body and behaviors like adding attachments and sending.
All class definitions start with the class keyword, which is followed by the name
of the class and a colon. Any code that is indented below the class definition is
considered part of the class’s body.
class Dog:
pass
Object-oriented programming revolves around defining and using new types. A class in
Python represents a type. Object-oriented programming involves at least these phases:
Understanding a Problem Domain
1. Understanding the problem domain. This step is crucial: we need to know what our customer
wants before we can write a program that does what the customer wants.
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.
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.
Data member − A class variable or instance variable that holds data associated with a
class and its objects.
Instance variable − A variable that is defined inside a method and belongs only to the
current instance of a class.
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.
Instantiation − The creation of an instance of a class.
Method − A special kind of function that is defined in a class definition.
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.
Function “Isinstance,” Class Object, and Class Book
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
Creating a class and checking its type
>>> class Book:
... """Information about a book."""
...
>>> type(str)
<class 'type'>
>>> type(Book)
<class 'type'>
Memory representation of Classes and Objects
>>> ruby_book = Book()
>>> ruby_book.title = 'Programming Ruby'
>>> ruby_book.authors = ['Thomas','Fowler','Hunt']
• The first line tells us that we asked for help on class Book. After that is the header
for class Book; the ([Link]) part tells us that Book is a subclass of class
object.
• The next line shows the Book docstring. Last is a section called “data
descriptors,” which are special pieces of information that Python keeps with every
user-defined class that it uses for its own purposes.
General form of defining a class
Writing a Method in Class Book
class Book:
def init (self, title, authors, publisher,
isbn, price):
[Link] = title
[Link] = authors[:]
[Link] = publisher
[Link] = isbn [Link]
= price
def num_authors(self):
return len([Link])
>>> import book
>>> python_book = [Link](
... 'Practical Programming',
... ['Campbell', 'Gries', 'Montojo'],
... 'Pragmatic Bookshelf',
... '978-1-93778-545-1', >>> python_book.title
'Practical Programming'
>>> python_book.authors
['Campbell', 'Gries',
'Montojo']
>>> python_book.publisher
'Pragmatic Bookshelf'
>>>
python_book.ISB
N '978-1-93778-
545-1'
>>>
python_book.price
25.0
Plugging into Python Syntax: More Special Methods
Special Methods in Python
Definition
Special methods are methods with double underscores (__method__) that are automatically called by Python
to perform operations like printing, comparing, or adding objects.
They allow objects to behave like built-in data types.
1. __str__() Method
Definition
__str__() returns a human-readable string of an object. It is called when we use
print().
Example
class Book:
def __init__(self, title):
[Link] = title
def __str__(self):
return f"Book Title: {[Link]}"
b = Book("Python Basics")
print(b)
Output
Book Title: Python Basics
🔹 2. __repr__() Method
Definition
__repr__() returns an official (developer-friendly) representation of an object.
Used for debugging and in Python shell.
Example
class Book:
def __init__(self, title):
[Link] = title
def __repr__(self):
return f"Book('{[Link]}')"
b = Book("Python Basics")
print(b)
Output
Book('Python Basics')
3. __eq__() Method
Definition
__eq__() is used to compare two objects using ==.
Example
class Book:
def __init__(self, title):
[Link] = title
def __eq__(self, other):
return [Link] == [Link]
b1 = Book("Python")
b2 = Book("Python")
print(b1 == b2)
Output
True
Simple Summary
1. __str__() → For printing
2. __repr__() → For debugging
3. __eq__() → For comparison
Creating Graphical User Interfaces
Modern programs interact with users via a graphical user interface, or GUI, which is made up of
windows, menus, buttons, and so on. how to build simple GUIs using a Python module called
tkinter. 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.
5.2 Using Module Tkinter
Every tkinter program consists of these things:
• Windows, buttons, scrollbars, text areas, and other widgets—anything that you can see on the
computer screen (Generally, the term widget means any useful object; in programming, it is short
for “window gadget.”)
• Modules, functions, and classes that manage the data that is being shown in the GUI
• An event manager that listens for events such as mouse clicks and keystrokes and reacts
to these events by calling event handler functions.
tkinter program:
import tkinter
window = [Link]()
[Link]()
Tk is a class that represents the root window of a tkinter GUI. This
root window’s mainloop method handles all the events for the GUI, so
it’s important to create
only one instance of Tk.
Here is the resulting GUI:
TKINTER WIDGETS:
Building a Basic GUI
Labels are widgets that are used to display short pieces of text. Here we create a Label that
belongs to the root window—its parent widget—and we specify the text to be displayed
by assigning it to the Label’s text parameter.
import tkinter window =
[Link]()
label = [Link](window, text='This is our label.') [Link]()
[Link]()
• Method call [Link]() 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
call this method, the child widget (in this case, Label) won’t be displayed or will be displayed
improperly.
• Labels display text. Often, applications will want to update a label’s text as the program
runs to show things like the name of a file or the time of day. One way to do this is simply
to assign a new value to the widget’s text using method config.
import tkinter
window = [Link]()
label = [Link](window, text='First label.')
[Link]() [Link](text='Second label.')
[Link]()
Using Mutable Variables with Widgets
• Suppose you want to display a string, such as the current time or a score in a game,
in several places in a GUI—the application’s status bar, some dialog boxes, and so
on.
import tkinter
window = [Link]()
data = [Link]() [Link]('Data to
display')
label = [Link](window, textvariable=data) [Link]()
[Link]()
Introducing few more Widgets
Grouping Widgets with the Frame Type
• A tkinter Frame is a container, much like the root window is a container. Frames are
not directly visible on the screen; instead, they are used to organize other widgets.
• The following code creates a frame, puts it in the root window, and then adds three
Labels to the frame:
Example-1:
import tkinter
window = [Link]()
frame = [Link](window)
[Link]()
first = [Link](frame, text='First label')
[Link]()
second = [Link](frame, text='Second label')
[Link]()
third = [Link](frame, text='Third label')
[Link]()
[Link]()
Example 2:
import tkinter
window = [Link]()
frame = [Link](window, borderwidth=4, relief=[Link]) [Link]()
first = [Link](frame, text='First label')
[Link]()
second = [Link](frame, text='Second label')
[Link]()
third = [Link](frame, text='Third label')
[Link]()
[Link]()
Note: The other border styles are SUNKEN, RAISED, GROOVE, and RIDGE
Getting Information from the User with the Entry Type
import tkinter
window = [Link]()
frame = [Link](window)
[Link]()
var = [Link]()
label = [Link](frame, textvariable=var) [Link]()
entry = [Link](frame, textvariable=var) [Link]()
[Link]()
Label Widget
import tkinter parent_widget =
[Link]()
label_widget = [Link](parent_widget, text="A Label")
label_widget.pack()
[Link]()
Button Widget
import tkinter parent_widget =
[Link]()
button_widget = [Link](parent_widget, text="A Button")
button_widget.pack()
[Link]()
Entry Widget
import tkinter parent_widget =
[Link]()
entry_widget = [Link](parent_widget) entry_widget.insert(0,
"Type your text here") entry_widget.pack()
[Link]()
Radio button Widget
import tkinter
parent_widget = [Link]() v =
[Link]()
[Link](1) # need to use [Link] and [Link] to
# set and get the value of this variable
radiobutton_widget1 = [Link](parent_widget, text="Radiobutton 1",
variable=v, value=1)
radiobutton_widget2 = [Link](parent_widget, text="Radiobutton 2",
variable=v, value=2)
radiobutton_widget1.pack()
radiobutton_widget2.pack()
[Link]()
Radio button Widget
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 =
[Link]() v = [Link]()
[Link](1)
radiobutton_widget1 = [Link](parent_widget, text="Radiobutton 1",
variable=v, value=1, indicatoron=False)
radiobutton_widget2 = [Link](parent_widget, text="Radiobutton 2",
variable=v, value=2, indicatoron=False)
radiobutton_widget1.pack()
radiobutton_widget2.pack()
[Link]()
Check button Widget
import tkinter parent_widget =
[Link]()
checkbutton_widget = [Link](parent_widget,
text="Checkbutton")
checkbutton_widget.select()
checkbutton_widget.pack()
[Link]()
Scale Widget: Horizontal
import tkinter parent_widget =
[Link]()
scale_widget = [Link](parent_widget, from_=0, to=100,
orient=[Link])
scale_widget.set(25) scale_widget.pack()
[Link]()
Scale Widget: Vertical
import tkinter parent_widget =
[Link]()
scale_widget = [Link](parent_widget, from_=0, to=100,
orient=[Link])
scale_widget.set(25)
scale_widget.pack()
[Link]()
Text Widget
import tkinter parent_widget =
[Link]()
text_widget = [Link](parent_widget,
width=20, height=3)
text_widget.insert([Link],
"Text Widgetn20 characters widen3 lines high") text_widget.pack()
[Link]()
LabelFrame Widget
import tkinter parent_widget =
[Link]()
labelframe_widget = [Link](parent_widget,
text="LabelFrame")
label_widget=[Link](labelframe_widget, text="Child
widget of the LabelFrame")
labelframe_widget.pack(padx=10, pady=10)
label_widget.pack()
[Link]()
Canvas Widget
import tkinter parent_widget =
[Link]()
canvas_widget = [Link](parent_widget, bg="blue", width=10,
height= 50)
canvas_widget.pack()
[Link]()
Listbox Widget
import tkinter
parent_widget =
[Link]()
listbox_entries = ["Entry 1", "Entry 2",
"Entry 3", "Entry 4"]
listbox_widget =
[Link](parent_widget) for entry in
listbox_entries:
listbox_widget.insert([Link], entry)
listbox_widget.pack()
Menu Widget
import tkinter parent_widget =
[Link]() def
menu_callback():
print("I'm in the menu callback!") def
submenu_callback():
print("I'm in the submenu callback!") menu_widget =
[Link](parent_widget)
submenu_widget = [Link](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)
[Link]()
Models, Views, and Controllers
• Using a StringVar to connect a text-entry box and a label is the first step toward separating
models (How do we represent the data?), views (How do we display the data?), and controllers
(How do we modify the data?), which is the key to building larger GUIs (as well as many
other kinds of applications).
• 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():
[Link]([Link]() + 1)
def click_down():
[Link]([Link]() - 1)
# The model.
counter = [Link]() [Link](0)
# The views.
window = [Link]()
frame = [Link](window)
[Link]()
button = [Link](frame, text='Up', command=click_up) [Link]()
label = [Link](frame, textvariable=counter) [Link]()
button = [Link](frame, text='Down', command=click_down) [Link]()
[Link]()
Customizing the Visual Style
Every windowing system has its own look and feel—square or rounded corners, particular colors,
and so on. In this section, we’ll see how to change the appearance of GUI widgets to make
applications look more distinctive. A note of caution before we begin: the default styles of some
windowing systems have been chosen by experts trained in graphic design and human computer
interaction. The odds are that any radical changes on your part will make things worse, not better.
In particular, be careful about color (several percent of the male population has some degree of
color blindness) and font size (many people, particularly the elderly, cannot read small text).
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 = [Link]()
button = [Link](window, text='Hello', font=('Bookman', 14, 'bold
italic'))
[Link]() [Link]()
Changing Colors
Almost all foreground colors can be set using the bg and fg keyword arguments, respectively. As
the following code shows, we can set either of these to a standard color by specifying the color’s
name, such as white, black, red, green, blue, cyan, yellow, or magenta:
import tkinter window =
[Link]()
button = [Link](window, text='Hello', bg='green', fg='white') [Link]()
[Link]()
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:
# Set up text entry widgets for red, green, and blue, storing
the
# associated variables in a dictionary for later use.
colors = {}
for (name, col) in (('red', '#FF0000'),
('green', '#00FF00'),
('blue', '#0000FF')):
colors[name] = [Link]()
colors[name].set('00')
entry = [Link](frame, textvariable=colors[name],
bg=col,
fg='white')
[Link]()
current = [Link](frame, ',
text=' bg='#FFFFFF')
[Link](
)
# Give the user a way to trigger a color update.
update = [Link](frame, text='Update',
command=lambda: change(current,
colors))
[Link]()
[Link]()
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
[Link], and its controllers are the methods upClick and quitClick.
import tkinter
class Counter:
"""A simple counter GUI using object-oriented programming.""" def init
(self, parent):
"""Create the GUI."""
# Framework. [Link] =
parent
[Link] = [Link](parent) [Link]()
# Model.
[Link] = [Link]() [Link](1)
# Label displaying current state.
[Link] = [Link]([Link], textvariable=[Link]) [Link]()
# Buttons to control application. [Link] =
[Link]([Link],
text='up', command=self.up_click) [Link](side='left')
[Link] = [Link]([Link],
text='down', command=self.down_click)
[Link](side='left')
[Link] = [Link]([Link], text='quit',
command=self.quit_click)
[Link](side='left')
def up_click(self):
"""Handle click on 'up' button.""" [Link]([Link]() + 1)
def down_click(self):
"""Handle click on 'down' button."""
[Link]([Link]() - 1)
def quit_click(self):
"""Handle click on 'quit' button.""" [Link]()
if name == ' main ':
window = [Link]() myapp =
Counter(window)
[Link]()
Keeping the Concepts from Being a GUI Mess
• Most modern programs provide a graphical user interface (GUI) for displaying
information and interacting with users. GUIs are built out of widgets, such as buttons,
sliders, and text panels; all modern programming languages provide at least one GUI
toolkit.
• Unlike command-line programs, GUI applications are usually event-driven. In other
words, they react to events such as keystrokes and mouse clicks when and as they occur.
• Experience shows that GUIs should be built using the model-view-controller pattern. The
model is the data being manipulated; the view displays the current state of the data and
gathers input from the user, while the controller decides what to do next.
• Lambda expressions create functions that have no names. These are often used to define
the actions that widgets should take when users provide input, without requiring global
variables.
• Designing usable GUIs is as challenging a craft as designing software. Being good at the
latter doesn’t guarantee that you can do the former, but dozens of good books can help
you get started.
--- 000 ---