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