]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/Threads.py
wxUniversal fixes:
[wxWidgets.git] / wxPython / demo / Threads.py
CommitLineData
e19b7164
RD
1
2from wxPython.wx import *
3
4import thread
5import time
6from whrandom import random
7
8#----------------------------------------------------------------------
9
4268f798 10wxEVT_UPDATE_BARGRAPH = wxNewEventType()
e19b7164
RD
11
12def EVT_UPDATE_BARGRAPH(win, func):
13 win.Connect(-1, -1, wxEVT_UPDATE_BARGRAPH, func)
14
15
16class 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
26class 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)
4268f798 46 #del evt
e19b7164
RD
47
48 sleeptime = (random() * 2) + 0.5
4268f798 49 time.sleep(sleeptime/4)
e19b7164
RD
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
65class 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
07b2e1cd
RD
73 font = wxFont(12, wxSWISS, wxNORMAL, wxBOLD)
74 self.SetFont(font)
e19b7164 75
6230a84f 76 self.colors = [ wxRED, wxGREEN, wxBLUE, wxCYAN,
07b2e1cd 77 "Yellow", "Navy" ]
e19b7164 78
f6bcfd97
BP
79 EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
80 EVT_PAINT(self, self.OnPaint)
81
e19b7164
RD
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
07b2e1cd
RD
100 def GetBestHeight(self):
101 return 2 * (self.barHeight + 1) * len(self.values)
102
103
6230a84f 104 def Draw(self, dc, size):
07b2e1cd 105 dc.SetFont(self.GetFont())
e19b7164 106 dc.SetTextForeground(wxBLUE)
6230a84f
RD
107 dc.SetBackground(wxBrush(self.GetBackgroundColour()))
108 dc.Clear()
e19b7164
RD
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
6230a84f
RD
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
3af4e610
RD
140 dc.SelectObject(wxNullBitmap)
141
6230a84f
RD
142
143 def OnEraseBackground(self, evt):
144 pass
145
146
e19b7164
RD
147
148
149#----------------------------------------------------------------------
150
151class 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"
4268f798
RD
162 "window by sending events to it, one thread for each bar.",
163 wxPoint(5,5))
e19b7164
RD
164 panel.Fit()
165
6230a84f
RD
166 self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three', 'Four',
167 'Five', 'Six', 'Seven'])
0a8c1efb 168 self.graph.SetSize((450, self.graph.GetBestHeight()))
e19b7164
RD
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)
07b2e1cd 176 sizer.Fit(self)
e19b7164 177
e19b7164
RD
178 EVT_UPDATE_BARGRAPH(self, self.OnUpdate)
179 self.threads = []
6230a84f
RD
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))
e19b7164
RD
188
189 for t in self.threads:
190 t.Start()
191
f6bcfd97 192 EVT_CLOSE(self, self.OnCloseWindow)
e19b7164
RD
193
194
195 def OnUpdate(self, evt):
196 self.graph.SetValue(evt.barNum, evt.value)
6230a84f 197 self.graph.Refresh(false)
e19b7164
RD
198
199
200 def OnCloseWindow(self, evt):
201 busy = wxBusyInfo("One moment please, waiting for threads to die...")
0a8c1efb 202 wxYield()
e19b7164
RD
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
217def 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
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
235thread, but this often severly limits what can be done in an
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
240alternate threads. A function called wxPostEvent allows you to do
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"""