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