]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Threads.py
6d9f5a1d5be8ded3565991aa99f3c9000e0b38df
[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(wxPen(wxBLACK, 3, wxSOLID))
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(wxPen(color))
122 dc.SetBrush(wxBrush(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 = self.GetSize()
132 bmp = wx.EmptyBitmap(width, height)
133
134 dc = wx.MemoryDC()
135 dc.SelectObject(bmp)
136
137 self.Draw(dc, (width, height))
138
139 wdc = wx.PaintDC(self)
140 wdc.BeginDrawing()
141 wdc.Blit((0,0), size, dc, (0,0))
142 wdc.EndDrawing()
143
144 dc.SelectObject(wx.NullBitmap)
145
146
147 def OnEraseBackground(self, evt):
148 pass
149
150
151
152
153 #----------------------------------------------------------------------
154
155 class TestFrame(wx.Frame):
156 def __init__(self, parent, log):
157 wx.Frame.__init__(self, parent, -1, "Thread Test", size=(450,300))
158 self.log = log
159
160 #self.CenterOnParent()
161
162 panel = wx.Panel(self, -1)
163 panel.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
164 wx.StaticText(panel, -1,
165 "This demo shows multiple threads interacting with this\n"
166 "window by sending events to it, one thread for each bar.",
167 (5,5))
168 panel.Fit()
169
170 self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three', 'Four',
171 'Five', 'Six', 'Seven'])
172 self.graph.SetSize((450, self.graph.GetBestHeight()))
173
174 sizer = wx.BoxSizer(wx.VERTICAL)
175 sizer.Add(panel, 0, wx.EXPAND)
176 sizer.Add(self.graph, 1, wx.EXPAND)
177
178 self.SetSizer(sizer)
179 self.SetAutoLayout(True)
180 sizer.Fit(self)
181
182 self.Bind(EVT_UPDATE_BARGRAPH, self.OnUpdate)
183
184 self.threads = []
185 self.threads.append(CalcBarThread(self, 0, 50))
186 self.threads.append(CalcBarThread(self, 1, 75))
187 self.threads.append(CalcBarThread(self, 2, 100))
188 self.threads.append(CalcBarThread(self, 3, 150))
189 self.threads.append(CalcBarThread(self, 4, 225))
190 self.threads.append(CalcBarThread(self, 5, 300))
191 self.threads.append(CalcBarThread(self, 6, 250))
192 self.threads.append(CalcBarThread(self, 7, 175))
193
194 for t in self.threads:
195 t.Start()
196
197 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
198
199
200 def OnUpdate(self, evt):
201 self.graph.SetValue(evt.barNum, evt.value)
202 self.graph.Refresh(False)
203
204
205 def OnCloseWindow(self, evt):
206 busy = wx.BusyInfo("One moment please, waiting for threads to die...")
207 wx.Yield()
208
209 for t in self.threads:
210 t.Stop()
211
212 running = 1
213
214 while running:
215 running = 0
216
217 for t in self.threads:
218 running = running + t.IsRunning()
219
220 time.sleep(0.1)
221
222 self.Destroy()
223
224
225
226 #----------------------------------------------------------------------
227
228 def runTest(frame, nb, log):
229 win = TestFrame(frame, log)
230 frame.otherWin = win
231 win.Show(True)
232 return None
233
234 #----------------------------------------------------------------------
235
236
237
238
239 overview = """\
240 The main issue with multi-threaded GUI programming is the thread safty
241 of the GUI itself. On most platforms the GUI is not thread safe and
242 so any cross platform GUI Toolkit and applications written with it
243 need to take that into account.
244
245 The solution is to only allow interaction with the GUI from a single
246 thread, but this often severely limits what can be done in an
247 application and makes it difficult to use additional threads at all.
248
249 Since wxPython already makes extensive use of event handlers, it is a
250 logical extension to allow events to be sent to GUI objects from
251 alternate threads. A function called wx.PostEvent allows you to do
252 this. It accepts an event and an event handler (window) and instead
253 of sending the event immediately in the current context like
254 ProcessEvent does, it processes it later from the context of the GUI
255 thread.
256
257 """
258
259
260
261 if __name__ == '__main__':
262 import sys,os
263 import run
264 run.main(['', os.path.basename(sys.argv[0])])
265