]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Threads.py
wxPython metadata xml
[wxWidgets.git] / wxPython / demo / Threads.py
1 # 11/13/2003 - Jeff Grimmett (grimmtooth@softhome.net)
2 #
3 # o Updated for wx namespace
4 # o Replaced deprecated whrandom with random module.
5 #
6 # 11/13/2003 - Jeff Grimmett (grimmtooth@softhome.net)
7 #
8 # o Currently uses lib.newevent; should probably be updated to use
9 # new-style event binder. OTOH, this is the only place we get
10 # to see that library used that I know of.
11 #
12
13 import random
14 import time
15 import thread
16
17 import wx
18 import wx.lib.newevent
19
20 #----------------------------------------------------------------------
21
22 # This creates a new Event class and a EVT binder function
23 (UpdateBarEvent, EVT_UPDATE_BARGRAPH) = wx.lib.newevent.NewEvent()
24
25
26 #----------------------------------------------------------------------
27
28 class CalcBarThread:
29 def __init__(self, win, barNum, val):
30 self.win = win
31 self.barNum = barNum
32 self.val = val
33
34 def Start(self):
35 self.keepGoing = self.running = True
36 thread.start_new_thread(self.Run, ())
37
38 def Stop(self):
39 self.keepGoing = False
40
41 def IsRunning(self):
42 return self.running
43
44 def Run(self):
45 while self.keepGoing:
46 evt = UpdateBarEvent(barNum = self.barNum, value = int(self.val))
47 wx.PostEvent(self.win.GetEventHandler(), evt)
48 #del evt
49
50 sleeptime = (random.random() * 2) + 0.5
51 time.sleep(sleeptime/4)
52
53 sleeptime = sleeptime * 5
54 if int(random.random() * 2):
55 self.val = self.val + sleeptime
56 else:
57 self.val = self.val - sleeptime
58
59 if self.val < 0: self.val = 0
60 if self.val > 300: self.val = 300
61
62 self.running = False
63
64 #----------------------------------------------------------------------
65
66
67 class GraphWindow(wx.Window):
68 def __init__(self, parent, labels):
69 wx.Window.__init__(self, parent, -1)
70
71 self.values = []
72 for label in labels:
73 self.values.append((label, 0))
74
75 font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
76 self.SetFont(font)
77
78 self.colors = [ wx.RED, wx.GREEN, wx.BLUE, wx.CYAN,
79 "Yellow", "Navy" ]
80
81 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
82 self.Bind(wx.EVT_PAINT, self.OnPaint)
83
84
85 def SetValue(self, index, value):
86 assert index < len(self.values)
87 cur = self.values[index]
88 self.values[index:index+1] = [(cur[0], value)]
89
90
91 def SetFont(self, font):
92 wx.Window.SetFont(self, font)
93 wmax = hmax = 0
94 for label, val in self.values:
95 w,h = self.GetTextExtent(label)
96 if w > wmax: wmax = w
97 if h > hmax: hmax = h
98 self.linePos = wmax + 10
99 self.barHeight = hmax
100
101
102 def GetBestHeight(self):
103 return 2 * (self.barHeight + 1) * len(self.values)
104
105
106 def Draw(self, dc, size):
107 dc.SetFont(self.GetFont())
108 dc.SetTextForeground(wx.BLUE)
109 dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
110 dc.Clear()
111 dc.SetPen(wx.Pen(wx.BLACK, 3, wx.SOLID))
112 dc.DrawLine((self.linePos, 0), (self.linePos, size.height-10))
113
114 bh = ypos = self.barHeight
115 for x in range(len(self.values)):
116 label, val = self.values[x]
117 dc.DrawText(label, (5, ypos))
118
119 if val:
120 color = self.colors[ x % len(self.colors) ]
121 dc.SetPen(wx.Pen(color))
122 dc.SetBrush(wx.Brush(color))
123 dc.DrawRectangle((self.linePos+3, ypos), (val, bh))
124
125 ypos = ypos + 2*bh
126 if ypos > size[1]-10:
127 break
128
129
130 def OnPaint(self, evt):
131 width, height = size =self.GetSize()
132 bmp = wx.EmptyBitmap(width, height)
133
134 dc = wx.MemoryDC()
135 dc.SelectObject(bmp)
136
137
138 self.Draw(dc, size)
139
140 wdc = wx.PaintDC(self)
141 wdc.BeginDrawing()
142 wdc.Blit((0,0), size, dc, (0,0))
143 wdc.EndDrawing()
144
145 dc.SelectObject(wx.NullBitmap)
146
147
148 def OnEraseBackground(self, evt):
149 pass
150
151
152
153
154 #----------------------------------------------------------------------
155
156 class TestFrame(wx.Frame):
157 def __init__(self, parent, log):
158 wx.Frame.__init__(self, parent, -1, "Thread Test", size=(450,300))
159 self.log = log
160
161 #self.CenterOnParent()
162
163 panel = wx.Panel(self, -1)
164 panel.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
165 wx.StaticText(panel, -1,
166 "This demo shows multiple threads interacting with this\n"
167 "window by sending events to it, one thread for each bar.",
168 (5,5))
169 panel.Fit()
170
171 self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three', 'Four',
172 'Five', 'Six', 'Seven'])
173 self.graph.SetSize((450, self.graph.GetBestHeight()))
174
175 sizer = wx.BoxSizer(wx.VERTICAL)
176 sizer.Add(panel, 0, wx.EXPAND)
177 sizer.Add(self.graph, 1, wx.EXPAND)
178
179 self.SetSizer(sizer)
180 self.SetAutoLayout(True)
181 sizer.Fit(self)
182
183 self.Bind(EVT_UPDATE_BARGRAPH, self.OnUpdate)
184
185 self.threads = []
186 self.threads.append(CalcBarThread(self, 0, 50))
187 self.threads.append(CalcBarThread(self, 1, 75))
188 self.threads.append(CalcBarThread(self, 2, 100))
189 self.threads.append(CalcBarThread(self, 3, 150))
190 self.threads.append(CalcBarThread(self, 4, 225))
191 self.threads.append(CalcBarThread(self, 5, 300))
192 self.threads.append(CalcBarThread(self, 6, 250))
193 self.threads.append(CalcBarThread(self, 7, 175))
194
195 for t in self.threads:
196 t.Start()
197
198 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
199
200
201 def OnUpdate(self, evt):
202 self.graph.SetValue(evt.barNum, evt.value)
203 self.graph.Refresh(False)
204
205
206 def OnCloseWindow(self, evt):
207 busy = wx.BusyInfo("One moment please, waiting for threads to die...")
208 wx.Yield()
209
210 for t in self.threads:
211 t.Stop()
212
213 running = 1
214
215 while running:
216 running = 0
217
218 for t in self.threads:
219 running = running + t.IsRunning()
220
221 time.sleep(0.1)
222
223 self.Destroy()
224
225
226
227 #----------------------------------------------------------------------
228
229 def runTest(frame, nb, log):
230 win = TestFrame(frame, log)
231 frame.otherWin = win
232 win.Show(True)
233 return None
234
235 #----------------------------------------------------------------------
236
237
238
239
240 overview = """\
241 The main issue with multi-threaded GUI programming is the thread safty
242 of the GUI itself. On most platforms the GUI is not thread safe and
243 so any cross platform GUI Toolkit and applications written with it
244 need to take that into account.
245
246 The solution is to only allow interaction with the GUI from a single
247 thread, but this often severely limits what can be done in an
248 application and makes it difficult to use additional threads at all.
249
250 Since wxPython already makes extensive use of event handlers, it is a
251 logical extension to allow events to be sent to GUI objects from
252 alternate threads. A function called wx.PostEvent allows you to do
253 this. It accepts an event and an event handler (window) and instead
254 of sending the event immediately in the current context like
255 ProcessEvent does, it processes it later from the context of the GUI
256 thread.
257
258 """
259
260
261
262 if __name__ == '__main__':
263 import sys,os
264 import run
265 run.main(['', os.path.basename(sys.argv[0])])
266