]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/Threads.py
non-PCH build fix (according to Tinderbox).
[wxWidgets.git] / wxPython / demo / Threads.py
CommitLineData
8fa876ca
RD
1
2import random
3import time
4import thread
5
6import wx
7import wx.lib.newevent
e19b7164
RD
8
9#----------------------------------------------------------------------
10
8b9a4190 11# This creates a new Event class and a EVT binder function
8fa876ca 12(UpdateBarEvent, EVT_UPDATE_BARGRAPH) = wx.lib.newevent.NewEvent()
e19b7164
RD
13
14
15#----------------------------------------------------------------------
16
17class 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):
1e4a197e 24 self.keepGoing = self.running = True
e19b7164
RD
25 thread.start_new_thread(self.Run, ())
26
27 def Stop(self):
1e4a197e 28 self.keepGoing = False
e19b7164
RD
29
30 def IsRunning(self):
31 return self.running
32
33 def Run(self):
34 while self.keepGoing:
8b9a4190 35 evt = UpdateBarEvent(barNum = self.barNum, value = int(self.val))
d2f9bbfd
RD
36 wx.PostEvent(self.win, evt)
37
8fa876ca 38 sleeptime = (random.random() * 2) + 0.5
4268f798 39 time.sleep(sleeptime/4)
e19b7164
RD
40
41 sleeptime = sleeptime * 5
8fa876ca 42 if int(random.random() * 2):
e19b7164
RD
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
1e4a197e 50 self.running = False
e19b7164
RD
51
52#----------------------------------------------------------------------
53
54
8fa876ca 55class GraphWindow(wx.Window):
e19b7164 56 def __init__(self, parent, labels):
8fa876ca 57 wx.Window.__init__(self, parent, -1)
e19b7164
RD
58
59 self.values = []
60 for label in labels:
61 self.values.append((label, 0))
62
8fa876ca 63 font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
07b2e1cd 64 self.SetFont(font)
e19b7164 65
8fa876ca 66 self.colors = [ wx.RED, wx.GREEN, wx.BLUE, wx.CYAN,
07b2e1cd 67 "Yellow", "Navy" ]
e19b7164 68
8fa876ca
RD
69 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
70 self.Bind(wx.EVT_PAINT, self.OnPaint)
f6bcfd97 71
e19b7164
RD
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):
8fa876ca 80 wx.Window.SetFont(self, font)
e19b7164
RD
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
07b2e1cd
RD
90 def GetBestHeight(self):
91 return 2 * (self.barHeight + 1) * len(self.values)
92
93
6230a84f 94 def Draw(self, dc, size):
07b2e1cd 95 dc.SetFont(self.GetFont())
8fa876ca
RD
96 dc.SetTextForeground(wx.BLUE)
97 dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
6230a84f 98 dc.Clear()
2f4df0ec 99 dc.SetPen(wx.Pen(wx.BLACK, 3, wx.SOLID))
d7403ad2 100 dc.DrawLine(self.linePos, 0, self.linePos, size.height-10)
e19b7164
RD
101
102 bh = ypos = self.barHeight
103 for x in range(len(self.values)):
104 label, val = self.values[x]
d7403ad2 105 dc.DrawText(label, 5, ypos)
e19b7164
RD
106
107 if val:
108 color = self.colors[ x % len(self.colors) ]
2f4df0ec
RD
109 dc.SetPen(wx.Pen(color))
110 dc.SetBrush(wx.Brush(color))
d7403ad2 111 dc.DrawRectangle(self.linePos+3, ypos, val, bh)
e19b7164
RD
112
113 ypos = ypos + 2*bh
8fa876ca 114 if ypos > size[1]-10:
e19b7164
RD
115 break
116
6230a84f
RD
117
118 def OnPaint(self, evt):
cca20a64
RD
119 dc = wx.BufferedPaintDC(self)
120 self.Draw(dc, self.GetSize())
3af4e610 121
6230a84f
RD
122
123 def OnEraseBackground(self, evt):
124 pass
125
126
e19b7164
RD
127
128
129#----------------------------------------------------------------------
130
8fa876ca 131class TestFrame(wx.Frame):
e19b7164 132 def __init__(self, parent, log):
8fa876ca 133 wx.Frame.__init__(self, parent, -1, "Thread Test", size=(450,300))
e19b7164
RD
134 self.log = log
135
136 #self.CenterOnParent()
137
8fa876ca
RD
138 panel = wx.Panel(self, -1)
139 panel.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
140 wx.StaticText(panel, -1,
e19b7164 141 "This demo shows multiple threads interacting with this\n"
4268f798 142 "window by sending events to it, one thread for each bar.",
8fa876ca 143 (5,5))
e19b7164
RD
144 panel.Fit()
145
6230a84f
RD
146 self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three', 'Four',
147 'Five', 'Six', 'Seven'])
0a8c1efb 148 self.graph.SetSize((450, self.graph.GetBestHeight()))
e19b7164 149
8fa876ca
RD
150 sizer = wx.BoxSizer(wx.VERTICAL)
151 sizer.Add(panel, 0, wx.EXPAND)
152 sizer.Add(self.graph, 1, wx.EXPAND)
e19b7164
RD
153
154 self.SetSizer(sizer)
1e4a197e 155 self.SetAutoLayout(True)
07b2e1cd 156 sizer.Fit(self)
e19b7164 157
8fa876ca
RD
158 self.Bind(EVT_UPDATE_BARGRAPH, self.OnUpdate)
159
e19b7164 160 self.threads = []
6230a84f
RD
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))
e19b7164
RD
169
170 for t in self.threads:
171 t.Start()
172
8fa876ca 173 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
e19b7164
RD
174
175
176 def OnUpdate(self, evt):
177 self.graph.SetValue(evt.barNum, evt.value)
1e4a197e 178 self.graph.Refresh(False)
e19b7164
RD
179
180
181 def OnCloseWindow(self, evt):
8fa876ca
RD
182 busy = wx.BusyInfo("One moment please, waiting for threads to die...")
183 wx.Yield()
184
e19b7164
RD
185 for t in self.threads:
186 t.Stop()
8fa876ca 187
e19b7164 188 running = 1
8fa876ca 189
e19b7164
RD
190 while running:
191 running = 0
8fa876ca 192
e19b7164
RD
193 for t in self.threads:
194 running = running + t.IsRunning()
8fa876ca 195
e19b7164 196 time.sleep(0.1)
8fa876ca 197
e19b7164
RD
198 self.Destroy()
199
200
201
34a544a6
RD
202#---------------------------------------------------------------------------
203
204class 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):
5523df9f 214 win = TestFrame(self, self.log)
34a544a6
RD
215 win.Show(True)
216
217
218#---------------------------------------------------------------------------
219
e19b7164
RD
220
221def runTest(frame, nb, log):
34a544a6
RD
222 win = TestPanel(nb, log)
223 return win
e19b7164
RD
224
225#----------------------------------------------------------------------
226
227
228
229
34a544a6 230
e19b7164
RD
231overview = """\
232The main issue with multi-threaded GUI programming is the thread safty
233of the GUI itself. On most platforms the GUI is not thread safe and
234so any cross platform GUI Toolkit and applications written with it
235need to take that into account.
236
237The solution is to only allow interaction with the GUI from a single
8b9a4190 238thread, but this often severely limits what can be done in an
e19b7164
RD
239application and makes it difficult to use additional threads at all.
240
241Since wxPython already makes extensive use of event handlers, it is a
242logical extension to allow events to be sent to GUI objects from
8fa876ca 243alternate threads. A function called wx.PostEvent allows you to do
e19b7164
RD
244this. It accepts an event and an event handler (window) and instead
245of sending the event immediately in the current context like
246ProcessEvent does, it processes it later from the context of the GUI
247thread.
248
249"""
1fded56b
RD
250
251
252
253if __name__ == '__main__':
254 import sys,os
255 import run
8eca4fef 256 run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
1fded56b 257