Example: OOPy Dots Demo
# oopyDotsDemo.py
# starts with betterDotsDemo and adds:
# * a dotCounter that counts all the instances of Dot or its subclasses
# * a MovingDot subclass of Dot that scrolls horizontally
# * a FlashingMovingDot subclass of MovingDot that flashes and moves
import random
from tkinter import *
class Dot(object):
dotCount = 0
def __init__(self, x, y):
Dot.dotCount += 1
self.x = x
self.y = y
self.r = random.randint(20,50)
self.fill = random.choice(["pink","orange","yellow","green",
"cyan","purple"])
self.clickCount = 0
def containsPoint(self, x, y):
d = ((self.x - x)**2 + (self.y - y)**2)**0.5
return (d <= self.r)
def draw(self, canvas):
canvas.create_oval(self.x-self.r, self.y-self.r,
self.x+self.r, self.y+self.r,
fill=self.fill)
canvas.create_text(self.x, self.y, text=str(self.clickCount))
def onTimerFired(self, data):
pass
class MovingDot(Dot):
def __init__(self, x, y):
super().__init__(x, y)
self.speed = 5 # default initial speed
def onTimerFired(self, data):
self.x += self.speed
if (self.x > data.width):
self.x = 0
class FlashingMovingDot(MovingDot):
def __init__(self, x, y):
super().__init__(x, y)
self.flashCounter = 0
self.showFlash = True
def onTimerFired(self, data):
super().onTimerFired(data)
self.flashCounter += 1
if (self.flashCounter == 5):
self.flashCounter = 0
self.showFlash = not self.showFlash
def draw(self, canvas):
if (self.showFlash):
canvas.create_rectangle(self.x-self.r, self.y-self.r,
self.x+self.r, self.y+self.r,
fill="lightGray")
super().draw(canvas)
def init(data):
data.dots = [ ]
def mousePressed(event, data):
for dot in reversed(data.dots):
if (dot.containsPoint(event.x, event.y)):
dot.clickCount += 1
return
dotType = (len(data.dots) % 3)
if (dotType == 0):
data.dots.append(Dot(event.x, event.y))
elif (dotType == 1):
data.dots.append(MovingDot(event.x, event.y))
else:
data.dots.append(FlashingMovingDot(event.x, event.y))
def redrawAll(canvas, data):
for dot in data.dots:
dot.draw(canvas)
canvas.create_text(data.width/2, 10, text="%d Dots" % Dot.dotCount)
def keyPressed(event, data):
pass
def timerFired(data):
for dot in data.dots:
dot.onTimerFired(data)
####################################
# use the run function as-is
####################################
def run(width=300, height=300):
def redrawAllWrapper(canvas, data):
canvas.delete(ALL)
canvas.create_rectangle(0, 0, data.width, data.height,
fill='white', width=0)
redrawAll(canvas, data)
canvas.update()
def mousePressedWrapper(event, canvas, data):
mousePressed(event, data)
redrawAllWrapper(canvas, data)
def keyPressedWrapper(event, canvas, data):
keyPressed(event, data)
redrawAllWrapper(canvas, data)
def timerFiredWrapper(canvas, data):
timerFired(data)
redrawAllWrapper(canvas, data)
# pause, then call timerFired again
canvas.after(data.timerDelay, timerFiredWrapper, canvas, data)
# Set up data and call init
class Struct(object): pass
data = Struct()
data.width = width
data.height = height
data.timerDelay = 100 # milliseconds
init(data)
# create the root and the canvas
root = Tk()
canvas = Canvas(root, width=data.width, height=data.height)
canvas.pack()
# set up events
root.bind("<Button-1>", lambda event:
mousePressedWrapper(event, canvas, data))
root.bind("<Key>", lambda event:
keyPressedWrapper(event, canvas, data))
timerFiredWrapper(canvas, data)
# and launch the app
root.mainloop() # blocks until window is closed
print("bye!")
run(400, 200)