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