import Tkinter as tk from collections import deque from random import random,shuffle from math import sin,cos,pi from itertools import izip class ResizableCanvas(tk.Canvas): def __init__(self,*args,**kwargs): tk.Canvas.__init__(self,*args,**kwargs) self.bind('',self.resize) def resize(self,e): # calculate border width bw = ( int(self['bd']) + int(self['highlightthickness']) ) * 2 # calculate the new width and height newwidth = e.width - bw newheight = e.height - bw # Don't reduce either dimension to 0, it can cause issues. if newwidth < 1: newwidth = 1 if newheight < 1: newheight = 1 # get the old width and height oldwidth = int(self['width']) oldheight = int(self['height']) # if the dimensions have changed... if (newwidth,newheight) != (oldwidth,oldheight): self.configure(width=newwidth,height=newheight) # Animated Polygon class class AnimPoly(object): defpolyopts = {'fill':'','outline':'black'} def __init__(self, canvas=None, pointcnt=4, polycnt=50, speed=5.0, **polyopts): if canvas: self.canvas = canvas else: self.canvas = ResizableCanvas(bg='black') self.canvas.pack(expand=True,fill='both') self.polys = deque() # collection of drawn Poly objects self._polycnt = polycnt # the number of polygons drawn on the screen self.polyopts = dict(self.defpolyopts) self.polyopts.update(polyopts) self.path = [] # set of points that make up a polygon self.vecs = [] # movement vectors for each of the polygons points self._speed = speed self._playing = False # generate starting points and velocities for i in range(pointcnt): self.path.append(int(self.canvas['width'])*random()) # x self.path.append(int(self.canvas['height'])*random()) # y dir = random()*2.0*pi self.vecs.append( sin(dir) * self._speed ) # dx self.vecs.append( cos(dir) * self._speed ) # dy def draw(self): # draw the current permutation p = self.canvas.create_polygon( self.path, **self.polyopts ) self.polys.appendleft(p) # delete the last poly in the stack if there are more than polycnt if len(self.polys) > self._polycnt: self.canvas.delete(self.polys.pop()) def move(self): # move points (corners) for i,point in enumerate(self.path): upperlims = int(self.canvas['width']),int(self.canvas['height']) newval = point + self.vecs[i] if newval > upperlims[i%2] and self.vecs[i] > 0 \ or newval < 0 and self.vecs[i] < 0: self.vecs[i] = -self.vecs[i] newval = point + self.vecs[i] self.path[i] = newval def update(self): self.draw() self.move() # generate animation and drawing properties def _play(self): if self._playing: self.update() self.canvas.after(10,self._play) def _setplaying(self,val): if self._playing != val: self._playing = val if val: self._play() def _getplaying(self): return self._playing playing = property(_getplaying,_setplaying) def _setpolycnt(self,val): while val < len(self.polys): self.canvas.delete(self.polys.pop()) self._polycnt = val def _getpolycnt(self): return self._polycnt polycnt = property(_getpolycnt,_setpolycnt) def _setpointcnt(self,val): # generate starting points and velocities while val < len(self.path) // 2: del self.path[-2:] del self.vecs[-2:] while val > len(self.path) // 2: self.path.append(int(self.canvas['width'])*random()) # x self.path.append(int(self.canvas['height'])*random()) # y dir = random()*2.0*pi self.vecs.append( sin(dir) * self._speed ) # dx self.vecs.append( cos(dir) * self._speed ) # dy def _getpointcnt(self): return len(self.path)//2 pointcnt = property(_getpointcnt,_setpointcnt) def _setspeed(self,val): for i,v in enumerate(self.vecs): self.vecs[i] = val * v / self._speed self._speed = val def _getspeed(self): return self._speed speed = property(_getspeed,_setspeed) # generate polygon properties def _genprop(name): def _get(self): try: return self.polyopts[name] except KeyError: val = self.canvas.itemcget(self.polys[0],name) self.polyopts[name] = val return val def _set(self,val): self.polyopts[name] = val return _get,_set for opt in ['fill','stipple','outline','width','smooth','splinesteps']: get_set = _genprop(name=opt) exec '%s = property(*get_set)'%opt class ColorAnimPoly(AnimPoly): def __init__(self,canvas=None,rate=1.0,**kwargs): AnimPoly.__init__(self,canvas,**kwargs) self.colorrate = rate self.colors = self.gencolor() # get first color self.outline = self.colors.next() def gencolor(self): color = [int(random()*256) for i in range(3)] rate = [0.3*self.colorrate,0.5*self.colorrate,1.1*self.colorrate] shuffle(rate) while 1: yield "#%02x%02x%02x"%tuple(color) for i,(c,r) in enumerate(zip(color,rate)): if c+r > 255 or c+r < 0: rate[i] = -r color[i] += rate[i] def updatecolor(self): self.outline = self.colors.next() def update(self): AnimPoly.update(self) self.updatecolor() class TestApp(object): def __init__(self,master=None): if master: self.master = master else: self.master = tk.Tk() can = ResizableCanvas(self.master,bg='black') can.pack(fill='both',expand=True) self.aps = [ ColorAnimPoly(can, smooth=True, width=10, speed=5, polycnt=30, rate=10), AnimPoly(can, outline='white', fill='black', width=10), ] def run(self): for ap in self.aps: ap.playing = True self.master.mainloop() if "__main__" == __name__: TestApp().run()