]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/Threads.py
Send an extra size event after creation to work around an apparent bug
[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))
fd3f2efe 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]
fd3f2efe 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))
fd3f2efe 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()
fd3f2efe 130 wdc.Blit((0,0), size, 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
215#----------------------------------------------------------------------
216
217def runTest(frame, nb, log):
218 win = TestFrame(frame, log)
219 frame.otherWin = win
1e4a197e 220 win.Show(True)
e19b7164
RD
221 return None
222
223#----------------------------------------------------------------------
224
225
226
227
228overview = """\
229The main issue with multi-threaded GUI programming is the thread safty
230of the GUI itself. On most platforms the GUI is not thread safe and
231so any cross platform GUI Toolkit and applications written with it
232need to take that into account.
233
234The solution is to only allow interaction with the GUI from a single
8b9a4190 235thread, but this often severely limits what can be done in an
e19b7164
RD
236application and makes it difficult to use additional threads at all.
237
238Since wxPython already makes extensive use of event handlers, it is a
239logical extension to allow events to be sent to GUI objects from
8fa876ca 240alternate threads. A function called wx.PostEvent allows you to do
e19b7164
RD
241this. It accepts an event and an event handler (window) and instead
242of sending the event immediately in the current context like
243ProcessEvent does, it processes it later from the context of the GUI
244thread.
245
246"""
1fded56b
RD
247
248
249
250if __name__ == '__main__':
251 import sys,os
252 import run
253 run.main(['', os.path.basename(sys.argv[0])])
254