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