4 from Canvas
import Oval
, Group
, CanvasText
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:
11 def bind(self
, sequence
=None, command
=None):
12 return self
.canvas
.tag_bind(self
.id, sequence
, command
)
16 """Base class for composite graphical objects.
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).
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.
26 Objects have mouse sensitivity. They can be clicked, dragged and
27 double-clicked. The behavior may actually determined by the pile
30 All instance attributes are public since the derived class may
35 def __init__(self
, canvas
, x
=0, y
=0, fill
='red', text
='object'):
40 self
.group
= Group(self
.canvas
)
41 self
.createitems(fill
, text
)
44 return str(self
.group
)
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,
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
)
55 def moveby(self
, dx
, dy
):
58 self
.group
.move(dx
, dy
)
62 def moveto(self
, x
, y
):
63 self
.moveby(x
- self
.x
, y
- self
.y
)
65 def transfer(self
, pile
):
67 self
.pile
.delete(self
)
79 """An object to serve as the bottom of a pile."""
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
)
90 """A group of graphical objects."""
92 def __init__(self
, canvas
, x
, y
, tag
=None):
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
)
102 def bindhandlers(self
):
103 self
.group
.bind('<1>', self
.clickhandler
)
104 self
.group
.bind('<Double-1>', self
.doubleclickhandler
)
106 def add(self
, object):
107 self
.objects
.append(object)
108 self
.group
.addtag_withtag(object.group
)
109 self
.position(object)
111 def delete(self
, object):
112 object.group
.dtag(self
.group
)
113 self
.objects
.remove(object)
115 def position(self
, object):
117 i
= self
.objects
.index(object)
118 object.moveto(self
.x
+ i
*4, self
.y
+ i
*8)
120 def clickhandler(self
, event
):
123 def doubleclickhandler(self
, event
):
127 class MovingPile(Pile
):
129 def bindhandlers(self
):
130 Pile
.bindhandlers(self
)
131 self
.group
.bind('<B1-Motion>', self
.motionhandler
)
132 self
.group
.bind('<ButtonRelease-1>', self
.releasehandler
)
136 def clickhandler(self
, event
):
137 tags
= self
.canvas
.gettags('current')
138 for i
in range(len(self
.objects
)):
140 if o
.group
.tag
in tags
:
145 self
.movethis
= self
.objects
[i
:]
146 for o
in self
.movethis
:
151 doubleclickhandler
= clickhandler
153 def motionhandler(self
, event
):
154 if not self
.movethis
:
156 dx
= event
.x
- self
.lastx
157 dy
= event
.y
- self
.lasty
160 for o
in self
.movethis
:
163 def releasehandler(self
, event
):
164 objects
= self
.movethis
168 self
.finishmove(objects
)
170 def finishmove(self
, objects
):
175 class Pile1(MovingPile
):
181 def __init__(self
, demo
):
183 MovingPile
.__init
__(self
, self
.demo
.canvas
, self
.x
, self
.y
, self
.tag
)
185 def doubleclickhandler(self
, event
):
190 o
.transfer(self
.other())
191 MovingPile
.doubleclickhandler(self
, event
)
196 def finishmove(self
, objects
):
200 if (x
-p
.x
)**2 + (y
-p
.y
)**2 < (x
-self
.x
)**2 + (y
-self
.y
)**2:
204 MovingPile
.finishmove(self
, objects
)
218 def __init__(self
, master
):
220 self
.canvas
= Canvas(master
,
221 width
=200, height
=200,
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')
235 # Main function, run when invoked as a stand-alone Python program.
240 root
.protocol('WM_DELETE_WINDOW', root
.quit
)
243 if __name__
== '__main__':