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