]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Threads.py
b1dce085a67c2af993fff54a91ec293fde83f4c6
[wxWidgets.git] / wxPython / demo / Threads.py
1
2 from wxPython.wx import *
3
4 import thread
5 import time
6 from whrandom import random
7
8 #----------------------------------------------------------------------
9
10 wxEVT_UPDATE_BARGRAPH = 25015
11
12 def EVT_UPDATE_BARGRAPH(win, func):
13 win.Connect(-1, -1, wxEVT_UPDATE_BARGRAPH, func)
14
15
16 class UpdateBarEvent(wxPyEvent):
17 def __init__(self, barNum, value):
18 wxPyEvent.__init__(self)
19 self.SetEventType(wxEVT_UPDATE_BARGRAPH)
20 self.barNum = barNum
21 self.value = value
22
23
24 #----------------------------------------------------------------------
25
26 class CalcBarThread:
27 def __init__(self, win, barNum, val):
28 self.win = win
29 self.barNum = barNum
30 self.val = val
31
32 def Start(self):
33 self.keepGoing = self.running = true
34 thread.start_new_thread(self.Run, ())
35
36 def Stop(self):
37 self.keepGoing = false
38
39 def IsRunning(self):
40 return self.running
41
42 def Run(self):
43 while self.keepGoing:
44 evt = UpdateBarEvent(self.barNum, int(self.val))
45 wxPostEvent(self.win, evt)
46 del evt
47
48 sleeptime = (random() * 2) + 0.5
49 #print self.barNum, 'sleeping for', sleeptime
50 time.sleep(sleeptime)
51
52 sleeptime = sleeptime * 5
53 if int(random() * 2):
54 self.val = self.val + sleeptime
55 else:
56 self.val = self.val - sleeptime
57
58 if self.val < 0: self.val = 0
59 if self.val > 300: self.val = 300
60
61 self.running = false
62
63 #----------------------------------------------------------------------
64
65
66 class GraphWindow(wxWindow):
67 def __init__(self, parent, labels):
68 wxWindow.__init__(self, parent, -1)
69
70 self.values = []
71 for label in labels:
72 self.values.append((label, 0))
73
74 font = wxFont(12, wxSWISS, wxNORMAL, wxBOLD)
75 self.SetFont(font)
76
77 self.colors = [ wxRED, wxGREEN, wxBLUE, wxCYAN,
78 "Yellow", "Navy" ]
79
80 EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
81 EVT_PAINT(self, self.OnPaint)
82
83
84 def SetValue(self, index, value):
85 assert index < len(self.values)
86 cur = self.values[index]
87 self.values[index:index+1] = [(cur[0], value)]
88
89
90 def SetFont(self, font):
91 wxWindow.SetFont(self, font)
92 wmax = hmax = 0
93 for label, val in self.values:
94 w,h = self.GetTextExtent(label)
95 if w > wmax: wmax = w
96 if h > hmax: hmax = h
97 self.linePos = wmax + 10
98 self.barHeight = hmax
99
100
101 def GetBestHeight(self):
102 return 2 * (self.barHeight + 1) * len(self.values)
103
104
105 def Draw(self, dc, size):
106 dc.SetFont(self.GetFont())
107 dc.SetTextForeground(wxBLUE)
108 dc.SetBackground(wxBrush(self.GetBackgroundColour()))
109 dc.Clear()
110 dc.SetPen(wxPen(wxBLACK, 3, wxSOLID))
111 dc.DrawLine(self.linePos, 0, self.linePos, size.height-10)
112
113 bh = ypos = self.barHeight
114 for x in range(len(self.values)):
115 label, val = self.values[x]
116 dc.DrawText(label, 5, ypos)
117
118 if val:
119 color = self.colors[ x % len(self.colors) ]
120 dc.SetPen(wxPen(color))
121 dc.SetBrush(wxBrush(color))
122 dc.DrawRectangle(self.linePos+3, ypos, val, bh)
123
124 ypos = ypos + 2*bh
125 if ypos > size.height-10:
126 break
127
128
129 def OnPaint(self, evt):
130 size = self.GetSize()
131 bmp = wxEmptyBitmap(size.width, size.height)
132 dc = wxMemoryDC()
133 dc.SelectObject(bmp)
134 self.Draw(dc, size)
135
136 wdc = wxPaintDC(self)
137 wdc.BeginDrawing()
138 wdc.Blit(0,0, size.width, size.height, dc, 0,0)
139 wdc.EndDrawing()
140
141 dc.SelectObject(wxNullBitmap)
142
143
144 def OnEraseBackground(self, evt):
145 pass
146
147
148
149
150 #----------------------------------------------------------------------
151
152 class TestFrame(wxFrame):
153 def __init__(self, parent, log):
154 wxFrame.__init__(self, parent, -1, "Thread Test", size=(450,300))
155 self.log = log
156
157 #self.CenterOnParent()
158
159 panel = wxPanel(self, -1)
160 panel.SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD))
161 wxStaticText(panel, -1,
162 "This demo shows multiple threads interacting with this\n"
163 "window by sending events to it.", wxPoint(5,5))
164 panel.Fit()
165
166 self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three', 'Four',
167 'Five', 'Six', 'Seven'])
168 self.graph.SetSize((-1, self.graph.GetBestHeight()))
169
170 sizer = wxBoxSizer(wxVERTICAL)
171 sizer.Add(panel, 0, wxEXPAND)
172 sizer.Add(self.graph, 1, wxEXPAND)
173
174 self.SetSizer(sizer)
175 self.SetAutoLayout(true)
176 sizer.Fit(self)
177
178 #self.graph.SetValue(0, 25)
179 #self.graph.SetValue(1, 50)
180 #self.graph.SetValue(2, 75)
181 #self.graph.SetValue(3, 100)
182
183 EVT_UPDATE_BARGRAPH(self, self.OnUpdate)
184 self.threads = []
185 self.threads.append(CalcBarThread(self, 0, 50))
186 self.threads.append(CalcBarThread(self, 1, 75))
187 self.threads.append(CalcBarThread(self, 2, 100))
188 self.threads.append(CalcBarThread(self, 3, 150))
189 self.threads.append(CalcBarThread(self, 4, 225))
190 self.threads.append(CalcBarThread(self, 5, 300))
191 self.threads.append(CalcBarThread(self, 6, 250))
192 self.threads.append(CalcBarThread(self, 7, 175))
193
194 for t in self.threads:
195 t.Start()
196
197 EVT_CLOSE(self, self.OnCloseWindow)
198
199
200 def OnUpdate(self, evt):
201 self.graph.SetValue(evt.barNum, evt.value)
202 self.graph.Refresh(false)
203
204
205 def OnCloseWindow(self, evt):
206 busy = wxBusyInfo("One moment please, waiting for threads to die...")
207 for t in self.threads:
208 t.Stop()
209 running = 1
210 while running:
211 running = 0
212 for t in self.threads:
213 running = running + t.IsRunning()
214 time.sleep(0.1)
215 self.Destroy()
216
217
218
219 #----------------------------------------------------------------------
220
221 def runTest(frame, nb, log):
222 win = TestFrame(frame, log)
223 frame.otherWin = win
224 win.Show(true)
225 return None
226
227 #----------------------------------------------------------------------
228
229
230
231
232 overview = """\
233 The main issue with multi-threaded GUI programming is the thread safty
234 of the GUI itself. On most platforms the GUI is not thread safe and
235 so any cross platform GUI Toolkit and applications written with it
236 need to take that into account.
237
238 The solution is to only allow interaction with the GUI from a single
239 thread, but this often severly limits what can be done in an
240 application and makes it difficult to use additional threads at all.
241
242 Since wxPython already makes extensive use of event handlers, it is a
243 logical extension to allow events to be sent to GUI objects from
244 alternate threads. A function called wxPostEvent allows you to do
245 this. It accepts an event and an event handler (window) and instead
246 of sending the event immediately in the current context like
247 ProcessEvent does, it processes it later from the context of the GUI
248 thread.
249
250 """