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