Learning Python Programming - Part 5 - Classes and Tkinter

in #programming8 years ago

Welcome to the 5th part of an ongoing series, Learning Python!

Today we will be learning about the power of classes and get a basic understanding of Tkinter, then write a program using what we've learned so far.


source

Classes

Classes are probably the most powerful tool in programming. Classes are used to make class objects that contain a blueprint of an object. As with a blueprint you can use it over and over to make similar objects.
How do we define a class?

class Name:
    def __init__(self):
        pass

In this class definition, Name can be any variable name, but it is common practice to capitalize the first letter and use only letters. Parenthesis after Name are optional, and inside of them are where you would put another class object to inherit another class. The __init__ method is required for all classes and is used to set class specific variables with its arguments.
NOTE: the pass statement can be used anywhere to tell Python to end the statement.

Class Variables

Classes can have two types of variables, if you are familiar with Java, you might know a similar concept with static and non-static. The two types of variables only have three differences: where you define them, if they have the prefix self, and what is changed when you change them.
Self variables:
The variables in a class need the prefix self to tell Python where this variable is. These variables are class specific and can be different between classes. This type of class variable acts just like a normal variable, but it has the scope of inside that class.
Shared variables:
In my programming experience, I haven't seen static class variables used very often, but they can be helpful in some situations. These "shared" variables are used by the class, and don't need to be defined with the prefix self. We define these variables above the __init__ method. When you change the value held by this type of variable per object, the object's definition of it will change, but if you change the class's definition of this type of variable, every class object with that class will have that variable changed.

Class Methods

Class methods are shared by every object extended from the class and are used to allow the class to do something from within. When we define a class method, it is just like a normal method, except the first argument must be self, and we define it inside the class definition. The __init__ method is a special method for classes that gets run when you define the class.
With any method you can tell Python to substitute default values if none are given using:

def method(a=1):
    pass

Class Example

When I learned about classes, the easiest way for me was to watch how they worked. This is how classes work:
Let's say we want to write a program to keep the information on two dogs. Each dog has their own name and breed, but at the same time they are both dogs and they both "bark," whether it sounds like a bark or not. We could write some code with separate variables that explain that Fido and Jimmy are dogs, but we can do it a whole lot simpler with classes.


source

First, we can define a class that shows the similarities between the two dogs.

class Dog:
    def __init__(self):
        pass

Pretty simple to conclude they are both dogs.

Second, we tell the class what all dogs share above the __init__ method.

class Dog:
    bark_sound = "bark"
    def __init__(self):
        pass

Third, we tell the class what is different between dogs, like their name, their breed, and their age.

class Dog:
    bark_sound = "Bark!"
    def __init__(self, name, breed, age):
        self.name = name
        self.breed = breed
        self.age = age

Now Python knows that there is a thing called a Dog, every Dog has a bard_sound equal to "Bark!", and each dog has its own name, breed, and age.

Fourth, we can tell Python a couple of things that a dog can do using methods.
Let's tell Python a dog can bark.

class Dog:
    bark_sound = "Bark!"
    def __init__(self, name, breed, age):
        self.name = name
        self.breed = breed
        self.age = age
    def bark(self):
        print(self.bark_sound)

With this class definition we can call the method and it will print out "Bark!"

Now Python knows what we defined a dog as, so we can tell Python to create a class object from the class Dog. You can think of this as Python "making" a dog. The code for this is fairly simple and can be compared to a method call.

fido_the_dog = Dog("Fido", "Terrier", 2)

When you create a class object, you need a way to access it or it will do absolutely nothing. A way to access it can be as simple as assigning the class object to a valid variable name to a more complex dictionary or list approach that can hold many class objects. In this case fido_the_dog is the valid variable name I used to store the class object. Similar to a method call, we call the class Dog with the arguments "Fido", "Terrier", and 2. If we recall from our class definition, we can see that these arguments go to the __init__ method where they are assigned to self.name, self.breed, and self.age.

After all that we can make "Fido" bark by calling her method bark.

fido_the_dog.bark()

This may not seem like much, but now we can make all the dogs bark!
Let's change the class method bark a little bit to give some more information and then make a whole bunch of dogs and have them all bark!

class Dog:
    bark_sound = "Bark!"
    def __init__(self, name, breed="dog", age=0):
        self.name = name
        self.breed = breed
        self.age = age
    def bark(self):
        print(self.name+" says "+self.bark_sound)

dog_names = ["Fido", "Pupper", "Jimmy", "Max", "Squirt"]
dogs = []

for name in dog_names:
    dogs.append(Dog(name))

for dog in dogs:
    dog.bark()

Running this code, there are 5 dogs added to the list and then all five dogs bark!

Fido says Bark!
Pupper says Bark!
Jimmy says Bark!
Max says Bark!
Squirt says Bark!

Tkinter


source

Tkinter is a module for visual displays. If isn't the prettiest, but it has function and is a breeze to learn.
First, we need to import tkinter. Depending on what version of Python you have, tkinter will be capitalized or lowercase. For 3.5 the tkinter module is tkinter. To use tkinter, we need to set up a root access and a canvas to display.

root = tkinter.Tk()
canvas = tkinter.Canvas(root)

These generally go at the very top of your program.
At the very bottom of our program, we need to tell tkinter to compile what to draw and then draw it. To do this, we use these commands:

canvas.pack()
root.mainloop()

NOTE: anything below these commands will not be run until after the screen closes.
Adding these parts to your code will open a window. YAY!
To make a custom size for this window, you can add additional arguments to your Canvas class call.

canvas = tkinter.Canvas(root, width=500, height=500)

Now we can draw things on our window. Drawing things with tkinter creates class objects with everything you draw, so we need to keep track of the class object with a variable or a list unless you want it gone forever.

line = canvas.create_line(0,0,100,100, fill="Black")
circle = canvas.create_oval(100-5,100-5,100+5,100+5, fill="Red")
rect = canvas.create_rectangle(300,300,400,400)

Very simple. You can view the tkinter docs here for a more accurate and indepth description of how this works.

Tkinter also has a method in the Tk class called after. The after method will call the second argument of its method call after the first argument's time in milliseconds has passed. This is very useful to create a game update loop.

def update():
    #code to update
    root.after(16, update)
update()

1000/60 = 16.6667 Therefore updating after 16 milliseconds will achieve a game loop that runs about 60 times per second.

Paint ball target program!


source

Now that we know how to make classes and draw circles on the screen, we can make a program to populate the screen with a whole bunch of circles. In this case we will just keep drawing over the circles with more circles, so we won't need to keep track of our drawn objects.
To make this program, we need to use the random module to chose where our circles will be, and how big they will be. For that we only need the randrange method. The randrange method is used just like the range method except it only returns one random number from within that range.
First, we import the tkinter module and the random module.

import tkinter
import random

Second, we need to define some variables.

WIDTH, HEIGHT = 500,500
MAX_RAD = 6

We'll use the width and height to define how big the screen is and the max rad to give a maximum radius for each circle.

Third, we need to initialize tkinter, just as we learned above.

root = tkinter.Tk()
canvas = tkinter.Canvas(root, width=WIDTH, height=HEIGHT)

Fourth, we need to add a helper method to help the random color into something that tkinter can read.

def rgb(rgb):
    return "#%02x%02x%02x" % rgb

Fifth, we can write the paintball class that creates a paintball on the screen.

class PaintBall:
    def __init__(self):
        self.pos = [random.randrange(WIDTH), random.randrange(HEIGHT)]
        self.rad = random.randrange(MAX_RAD)
        self.color = (random.randrange(256),random.randrange(256),random.randrange(256))
    def draw(self, canvas):
        canvas.create_oval(self.pos[0]-self.rad, self.pos[1]-self.rad, 
                           self.pos[0]+self.rad, self.pos[1]+self.rad,
                           fill=rgb(self.color))

That is a good example of a class that creates its own variables.

Sixth, we can write a loop with tkinter that keeps creating and drawing circles on the screen.

def update():
    PaintBall().draw(canvas)
    root.after(16, update)
update()

Finally, we can write the ending of the program to start tkinter.

canvas.pack()
root.mainloop()