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