]>
Commit | Line | Data |
---|---|---|
1e4a197e RD |
1 | #--------------------------------------------------------------------------- |
2 | # Name: EventManager.py | |
3 | # Purpose: A module to demonstrate wxPython.lib.evtmgr.EventManager. | |
4 | # | |
5 | # Author: Robb Shecter (robb@acm.org) | |
6 | # | |
7 | # Created: 16-December-2002 | |
8 | # Copyright: (c) 2002 by Robb Shecter (robb@acm.org) | |
9 | # Licence: wxWindows license | |
10 | #--------------------------------------------------------------------------- | |
8fa876ca RD |
11 | # |
12 | # 11/22/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
13 | # | |
14 | # o Updated for wx namespace | |
15 | # | |
16 | # 11/25/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
17 | # | |
18 | # o What happened to wx.Color()? | |
19 | # | |
20 | ||
1e4a197e | 21 | |
8fa876ca RD |
22 | import wx |
23 | import wx.lib.evtmgr as em | |
1e4a197e RD |
24 | |
25 | #---------------------------------------------------------------------- | |
26 | ||
8fa876ca | 27 | class TestPanel(wx.Panel): |
1e4a197e | 28 | def __init__(self, parent, log): |
8fa876ca | 29 | wx.Panel.__init__(self, parent, -1) |
1e4a197e RD |
30 | self.log = log |
31 | ||
32 | fsize = self.GetFont().GetPointSize() | |
8fa876ca RD |
33 | f1 = wx.Font(fsize+0, wx.SWISS, wx.NORMAL, wx.NORMAL) |
34 | f2 = wx.Font(fsize+2, wx.SWISS, wx.NORMAL, wx.BOLD) | |
35 | f3 = wx.Font(fsize+6, wx.SWISS, wx.NORMAL, wx.BOLD) | |
1e4a197e | 36 | |
8fa876ca | 37 | title1 = wx.StaticText(self, -1, 'EventManager') |
1e4a197e RD |
38 | title1.SetFont(f3) |
39 | txt = """\ | |
40 | This demo shows (1) basic uses and features of the EventManager, as well | |
41 | as (2) how it helps with a real-world task: creating independent, object- | |
42 | oriented components.""" | |
8fa876ca | 43 | message0 = wx.StaticText(self, -1, txt) |
1e4a197e RD |
44 | message0.SetFont(f1) |
45 | ||
8fa876ca | 46 | title2 = wx.StaticText(self, -1, 'Event Listeners') |
1e4a197e RD |
47 | title2.SetFont(f2) |
48 | ||
49 | txt = """\ | |
50 | These objects listen to motion events from the target window, using the ability | |
51 | to register one event with multiple listeners. They also register for mouse events | |
52 | on themselves to implement toggle-button functionality.""" | |
8fa876ca | 53 | message1 = wx.StaticText(self, -1, txt) |
1e4a197e RD |
54 | message1.SetFont(f1) |
55 | ||
8fa876ca | 56 | title3 = wx.StaticText(self, -1, 'Target Window') |
1e4a197e RD |
57 | title3.SetFont(f2) |
58 | ||
59 | txt = """\ | |
60 | A passive window that's used as an event generator. Move the mouse over it to | |
61 | send events to the listeners above.""" | |
8fa876ca | 62 | message2 = wx.StaticText(self, -1, txt) |
1e4a197e RD |
63 | message2.SetFont(f1) |
64 | ||
fd3f2efe | 65 | targetPanel = Tile(self, log, bgColor=wxColour(80,10,10), active=0) |
1e4a197e RD |
66 | buttonPanel = wxPanel(self ,-1) |
67 | sizer = wxBoxSizer(wxHORIZONTAL) | |
68 | target = targetPanel.tile | |
69 | ||
fd3f2efe | 70 | sizer.Add((0,0), 1) |
1e4a197e RD |
71 | for factor in [0.2, 0.3, 0.4, 0.5, 0.6, 0.7]: |
72 | sizer.Add(Tile(buttonPanel, log, factor-0.05, target), 0, wxALIGN_CENTER) | |
fd3f2efe | 73 | sizer.Add((0,0),1) |
1e4a197e | 74 | sizer.Add(Tile(buttonPanel, log, factor, target), 0, wxALIGN_CENTER) |
fd3f2efe | 75 | sizer.Add((0,0),1) |
1e4a197e RD |
76 | |
77 | buttonPanel.SetAutoLayout(1) | |
78 | buttonPanel.SetSizer(sizer) | |
79 | sizer.Fit(buttonPanel) | |
80 | ||
8fa876ca RD |
81 | sizer = wx.BoxSizer(wx.VERTICAL) |
82 | sizer.Add(title1, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 6) | |
83 | sizer.Add(message0, 0, wx.ALIGN_CENTER | wx.ALL, 6) | |
84 | sizer.Add(title2, 0, wx.ALIGN_CENTER | wx.LEFT | wx.TOP | wx.RIGHT, 16) | |
85 | sizer.Add(message1, 0, wx.ALIGN_CENTER | wx.ALL, 6) | |
86 | sizer.Add(buttonPanel, 0, wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, 16) | |
87 | sizer.Add(title3, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 16) | |
88 | sizer.Add(message2, 0, wx.ALIGN_CENTER | wx.ALL, 6) | |
89 | sizer.Add(targetPanel, 2, wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, 16) | |
1e4a197e RD |
90 | self.SetAutoLayout(1) |
91 | self.SetSizer(sizer) | |
92 | ||
93 | ||
94 | ||
8fa876ca | 95 | class Tile(wx.Panel): |
1e4a197e RD |
96 | """ |
97 | This outer class is responsible for changing | |
98 | its border color in response to certain mouse | |
99 | events over its contained 'InnerTile'. | |
100 | """ | |
8fa876ca RD |
101 | normal = wx.Colour(150,150,150) |
102 | active = wx.Colour(250,245,245) | |
103 | hover = wx.Colour(210,220,210) | |
1e4a197e RD |
104 | |
105 | def __init__(self, parent, log, factor=1, thingToWatch=None, bgColor=None, active=1, size=(38,38), borderWidth=3): | |
8fa876ca | 106 | wx.Panel.__init__(self, parent, -1, size=size, style=wx.CLIP_CHILDREN) |
1e4a197e RD |
107 | self.tile = InnerTile(self, log, factor, thingToWatch, bgColor) |
108 | self.log = log | |
8fa876ca RD |
109 | sizer = wx.BoxSizer(wx.HORIZONTAL) |
110 | sizer.Add(self.tile, 1, wx.EXPAND | wx.ALL, borderWidth) | |
1e4a197e RD |
111 | self.SetAutoLayout(1) |
112 | self.SetSizer(sizer) | |
113 | self.Layout() | |
114 | self.SetBackgroundColour(Tile.normal) | |
115 | if active: | |
116 | # Register myself for mouse events over self.tile in order to | |
117 | # create typical button/hyperlink visual effects. | |
8fa876ca RD |
118 | em.eventManager.Register(self.setHover, wx.EVT_ENTER_WINDOW, self.tile) |
119 | em.eventManager.Register(self.setNormal, wx.EVT_LEAVE_WINDOW, self.tile) | |
120 | em.eventManager.Register(self.setActive, wx.EVT_LEFT_DOWN, self.tile) | |
121 | em.eventManager.Register(self.setHover, wx.EVT_LEFT_UP, self.tile) | |
1e4a197e RD |
122 | |
123 | ||
124 | def setHover(self, event): | |
125 | self.SetBackgroundColour(Tile.hover) | |
126 | self.Refresh() | |
127 | ||
128 | ||
129 | def setActive(self, event): | |
130 | self.SetBackgroundColour(Tile.active) | |
131 | self.Refresh() | |
132 | ||
133 | ||
134 | def setNormal(self, event): | |
135 | self.SetBackgroundColour(Tile.normal) | |
136 | self.Refresh() | |
137 | ||
138 | ||
139 | ||
140 | class InnerTile(wxPanel): | |
8fa876ca RD |
141 | IDLE_COLOR = wx.Colour( 80, 10, 10) |
142 | START_COLOR = wx.Colour(200, 70, 50) | |
143 | FINAL_COLOR = wx.Colour( 20, 80,240) | |
144 | OFF_COLOR = wx.Colour(185,190,185) | |
1e4a197e RD |
145 | # Some pre-computation. |
146 | DELTAS = map(lambda a,b: b-a, START_COLOR.Get(), FINAL_COLOR.Get()) | |
147 | START_COLOR_TUPLE = START_COLOR.Get() | |
148 | ||
149 | """ | |
150 | This inner panel changes its color in reaction to mouse | |
151 | events over the 'thingToWatch'. | |
152 | """ | |
153 | def __init__(self, parent, log, factor, thingToWatch=None, bgColor=None): | |
8fa876ca | 154 | wx.Panel.__init__(self, parent, -1) |
1e4a197e RD |
155 | self.log=log |
156 | if bgColor: | |
157 | self.SetBackgroundColour(bgColor) | |
158 | if thingToWatch: | |
159 | self.factor = factor | |
160 | self.thingToWatch = thingToWatch | |
161 | self.state = 0 | |
162 | self.toggleOnOff() | |
163 | # Watch for the mouse click to enable/disable myself. | |
8fa876ca | 164 | em.eventManager.Register(self.toggleOnOff, wx.EVT_LEFT_UP, self) |
1e4a197e RD |
165 | |
166 | ||
167 | def toggleOnOff(self, event=None): | |
168 | # Implement being on or off by registering and | |
169 | # de-registering self.makeColor() from the event manager. | |
170 | if self.state: | |
8fa876ca | 171 | em.eventManager.DeregisterListener(self.makeColor) |
1e4a197e | 172 | else: |
8fa876ca | 173 | em.eventManager.Register(self.makeColor, wx.EVT_MOTION, self.thingToWatch) |
1e4a197e RD |
174 | self.state = 1 - self.state |
175 | self.resetColor() | |
176 | ||
177 | ||
178 | def resetColor(self, event=None): | |
179 | if self.state: | |
180 | self.setColor(InnerTile.IDLE_COLOR) | |
181 | else: | |
182 | self.setColor(InnerTile.OFF_COLOR) | |
183 | ||
184 | ||
185 | def setColor(self, color): | |
186 | self.SetBackgroundColour(color) | |
187 | self.Refresh() | |
188 | ||
189 | ||
190 | def makeColor(self, mouseEvent): | |
191 | self.makeColorFromTuple(mouseEvent.GetPositionTuple()) | |
192 | ||
193 | ||
194 | def makeColorFromTuple(self, (x, y)): | |
195 | MAX = 180.0 | |
196 | scaled = min((x + y) * self.factor, MAX) # In range [0..MAX] | |
197 | percent = scaled / MAX | |
198 | r = InnerTile.START_COLOR_TUPLE[0] + (InnerTile.DELTAS[0] * percent) | |
199 | g = InnerTile.START_COLOR_TUPLE[1] + (InnerTile.DELTAS[1] * percent) | |
200 | b = InnerTile.START_COLOR_TUPLE[2] + (InnerTile.DELTAS[2] * percent) | |
8fa876ca | 201 | self.setColor(wx.Colour(int(r), int(g), int(b))) |
1e4a197e RD |
202 | |
203 | ||
204 | ||
205 | ||
206 | #---------------------------------------------------------------------- | |
207 | ||
208 | def runTest(frame, nb, log): | |
209 | win = TestPanel(nb, log) | |
210 | return win | |
211 | ||
212 | #---------------------------------------------------------------------- | |
213 | ||
214 | ||
215 | ||
216 | overview = """<html><body> | |
217 | <h2>EventManager</h2> | |
218 | ||
219 | <p> The goal of the EventManager is to make wxWindows events more | |
220 | 'Pythonic' (ie. object-oriented) and easier to work with, without | |
221 | impacting performance. It offers these features: | |
222 | ||
223 | <p> | |
224 | <ul> | |
225 | ||
226 | <li> Allows any number of listeners to register for a single | |
227 | event. (In addition to the standard wxPython feature of a single | |
228 | listener being able to respond to many events.) | |
229 | ||
230 | <li> Makes it easy to disconnect and reconnect listeners. This | |
231 | has the effect of reducing the need for case-based branching in | |
232 | application code. | |
233 | ||
234 | <li> Has an object-oriented API. Programmers register to get | |
235 | events directly from the objects that generate them, instead of | |
236 | using ID numbers. | |
237 | ||
238 | </ul> | |
239 | ||
240 | <h3>Usage</h3> | |
241 | ||
242 | <p>The EventManager class has three public methods. First get a | |
243 | reference to it: | |
244 | ||
245 | <PRE> | |
246 | from wxPython.lib.evtmgr import eventManager | |
247 | </PRE> | |
248 | ||
249 | <p>...and then invoke any of the following methods. These methods are | |
250 | 'safe'; duplicate registrations or de-registrations will have no | |
251 | effect. | |
252 | ||
253 | <p><b>Registering a listener:</b> | |
254 | ||
255 | <PRE> | |
256 | eventManager.Register(listener, event, event-source) | |
257 | </PRE> | |
258 | ||
259 | ||
260 | <p><b>De-registering by window:</b> | |
261 | ||
262 | <PRE> | |
263 | eventManager.DeregisterWindow(event-source) | |
264 | </PRE> | |
265 | ||
266 | ||
267 | <p><b>De-registering by listener:</b> | |
268 | ||
269 | <PRE> | |
270 | eventManager.DeregisterListener(listener) | |
271 | </PRE> | |
272 | ||
273 | <p><b>Simple Example:</b> | |
274 | ||
275 | <PRE> | |
276 | from wxPython.lib.evtmgr import eventManager | |
277 | ||
278 | aButton = wxButton(somePanel, -1, 'Click me') | |
279 | eventManager.Register(self.someMethod, EVT_BUTTON, aButton) | |
280 | </PRE> | |
281 | ||
282 | <p> See the demo code as well as the documentation in the source of | |
283 | <tt>wxPython.lib.evtmgr</tt> for more details. | |
284 | ||
285 | ||
286 | <p> | |
287 | by Robb Shecter (robb@acm.org) | |
288 | </body></html> | |
289 | """ | |
290 | ||
291 | ||
292 | ||
293 | if __name__ == '__main__': | |
294 | import sys,os | |
295 | import run | |
296 | run.main(['', os.path.basename(sys.argv[0])]) | |
297 |