home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / tkinter / guido / canvasevents.py < prev    next >
Text File  |  1997-04-02  |  6KB  |  245 lines

  1. #! /usr/bin/env python
  2.  
  3. from Tkinter import *
  4. from Canvas import Oval, Group, CanvasText
  5.  
  6.  
  7. # Fix a bug in Canvas.Group as distributed in Python 1.4.  The
  8. # distributed bind() method is broken.  This is what should be used:
  9.  
  10. class Group(Group):
  11.     def bind(self, sequence=None, command=None):
  12.     return self.canvas.tag_bind(self.id, sequence, command)
  13.  
  14. class Object:
  15.  
  16.     """Base class for composite graphical objects.
  17.  
  18.     Objects belong to a canvas, and can be moved around on the canvas.
  19.     They also belong to at most one ``pile'' of objects, and can be
  20.     transferred between piles (or removed from their pile).
  21.  
  22.     Objects have a canonical ``x, y'' position which is moved when the
  23.     object is moved.  Where the object is relative to this position
  24.     depends on the object; for simple objects, it may be their center.
  25.  
  26.     Objects have mouse sensitivity.  They can be clicked, dragged and
  27.     double-clicked.  The behavior may actually determined by the pile
  28.     they are in.
  29.  
  30.     All instance attributes are public since the derived class may
  31.     need them.
  32.  
  33.     """
  34.  
  35.     def __init__(self, canvas, x=0, y=0, fill='red', text='object'):
  36.     self.canvas = canvas
  37.     self.x = x
  38.     self.y = y
  39.     self.pile = None
  40.     self.group = Group(self.canvas)
  41.     self.createitems(fill, text)
  42.  
  43.     def __str__(self):
  44.     return str(self.group)
  45.  
  46.     def createitems(self, fill, text):
  47.     self.__oval = Oval(self.canvas,
  48.                self.x-20, self.y-10, self.x+20, self.y+10,
  49.                fill=fill, width=3)
  50.     self.group.addtag_withtag(self.__oval)
  51.     self.__text = CanvasText(self.canvas,
  52.                self.x, self.y, text=text)
  53.     self.group.addtag_withtag(self.__text)
  54.  
  55.     def moveby(self, dx, dy):
  56.     if dx == dy == 0:
  57.         return
  58.     self.group.move(dx, dy)
  59.     self.x = self.x + dx
  60.     self.y = self.y + dy
  61.  
  62.     def moveto(self, x, y):
  63.     self.moveby(x - self.x, y - self.y)
  64.  
  65.     def transfer(self, pile):
  66.     if self.pile:
  67.         self.pile.delete(self)
  68.         self.pile = None
  69.     self.pile = pile
  70.     if self.pile:
  71.         self.pile.add(self)
  72.  
  73.     def tkraise(self):
  74.     self.group.tkraise()
  75.  
  76.  
  77. class Bottom(Object):
  78.  
  79.     """An object to serve as the bottom of a pile."""
  80.  
  81.     def createitems(self, *args):
  82.     self.__oval = Oval(self.canvas,
  83.                self.x-20, self.y-10, self.x+20, self.y+10,
  84.                fill='gray', outline='')
  85.     self.group.addtag_withtag(self.__oval)
  86.  
  87.  
  88. class Pile:
  89.  
  90.     """A group of graphical objects."""
  91.  
  92.     def __init__(self, canvas, x, y, tag=None):
  93.     self.canvas = canvas
  94.     self.x = x
  95.     self.y = y
  96.     self.objects = []
  97.     self.bottom = Bottom(self.canvas, self.x, self.y)
  98.     self.group = Group(self.canvas, tag=tag)
  99.     self.group.addtag_withtag(self.bottom.group)
  100.     self.bindhandlers()
  101.  
  102.     def bindhandlers(self):
  103.     self.group.bind('<1>', self.clickhandler)
  104.      self.group.bind('<Double-1>', self.doubleclickhandler)
  105.  
  106.     def add(self, object):
  107.     self.objects.append(object)
  108.     self.group.addtag_withtag(object.group)
  109.     self.position(object)
  110.  
  111.     def delete(self, object):
  112.     object.group.dtag(self.group)
  113.     self.objects.remove(object)
  114.  
  115.     def position(self, object):
  116.     object.tkraise()
  117.     i = self.objects.index(object)
  118.     object.moveto(self.x + i*4, self.y + i*8)
  119.  
  120.     def clickhandler(self, event):
  121.     pass
  122.  
  123.     def doubleclickhandler(self, event):
  124.     pass
  125.  
  126.  
  127. class MovingPile(Pile):
  128.  
  129.     def bindhandlers(self):
  130.     Pile.bindhandlers(self)
  131.     self.group.bind('<B1-Motion>', self.motionhandler)
  132.     self.group.bind('<ButtonRelease-1>', self.releasehandler)
  133.  
  134.     movethis = None
  135.  
  136.     def clickhandler(self, event):
  137.     tags = self.canvas.gettags('current')
  138.     for i in range(len(self.objects)):
  139.         o = self.objects[i]
  140.         if o.group.tag in tags:
  141.         break
  142.     else:
  143.         self.movethis = None
  144.         return
  145.     self.movethis = self.objects[i:]
  146.     for o in self.movethis:
  147.         o.tkraise()
  148.     self.lastx = event.x
  149.     self.lasty = event.y
  150.  
  151.     doubleclickhandler = clickhandler
  152.  
  153.     def motionhandler(self, event):
  154.     if not self.movethis:
  155.         return
  156.     dx = event.x - self.lastx
  157.     dy = event.y - self.lasty
  158.     self.lastx = event.x
  159.     self.lasty = event.y
  160.     for o in self.movethis:
  161.         o.moveby(dx, dy)
  162.  
  163.     def releasehandler(self, event):
  164.     objects = self.movethis
  165.     if not objects:
  166.         return
  167.     self.movethis = None
  168.     self.finishmove(objects)
  169.  
  170.     def finishmove(self, objects):
  171.     for o in objects:
  172.         self.position(o)
  173.  
  174.  
  175. class Pile1(MovingPile):
  176.  
  177.     x = 50
  178.     y = 50
  179.     tag = 'p1'
  180.  
  181.     def __init__(self, demo):
  182.     self.demo = demo
  183.     MovingPile.__init__(self, self.demo.canvas, self.x, self.y, self.tag)
  184.  
  185.     def doubleclickhandler(self, event):
  186.     try:
  187.         o = self.objects[-1]
  188.     except IndexError:
  189.         return
  190.     o.transfer(self.other())
  191.     MovingPile.doubleclickhandler(self, event)
  192.  
  193.     def other(self):
  194.     return self.demo.p2
  195.  
  196.     def finishmove(self, objects):
  197.     o = objects[0]
  198.     p = self.other()
  199.     x, y = o.x, o.y
  200.     if (x-p.x)**2 + (y-p.y)**2 < (x-self.x)**2 + (y-self.y)**2:
  201.         for o in objects:
  202.         o.transfer(p)
  203.     else:
  204.         MovingPile.finishmove(self, objects)
  205.  
  206. class Pile2(Pile1):
  207.  
  208.     x = 150
  209.     y = 50
  210.     tag = 'p2'
  211.  
  212.     def other(self):
  213.     return self.demo.p1
  214.  
  215.  
  216. class Demo:
  217.  
  218.     def __init__(self, master):
  219.     self.master = master
  220.     self.canvas = Canvas(master,
  221.                  width=200, height=200,
  222.                  background='yellow',
  223.                  relief=SUNKEN, borderwidth=2)
  224.     self.canvas.pack(expand=1, fill=BOTH)
  225.     self.p1 = Pile1(self)
  226.     self.p2 = Pile2(self)
  227.     o1 = Object(self.canvas, fill='red', text='o1')
  228.     o2 = Object(self.canvas, fill='green', text='o2')
  229.     o3 = Object(self.canvas, fill='light blue', text='o3')
  230.     o1.transfer(self.p1)
  231.     o2.transfer(self.p1)
  232.     o3.transfer(self.p2)
  233.  
  234.  
  235. # Main function, run when invoked as a stand-alone Python program.
  236.  
  237. def main():
  238.     root = Tk()
  239.     demo = Demo(root)
  240.     root.protocol('WM_DELETE_WINDOW', root.quit)
  241.     root.mainloop()
  242.  
  243. if __name__ == '__main__':
  244.     main()
  245.