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