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