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