]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/Threads.py
Changes to ensure that GDI objects returned from Python methods are
[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
10wxEVT_UPDATE_BARGRAPH = 25015
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)
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
66class 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
07b2e1cd
RD
74 font = wxFont(12, wxSWISS, wxNORMAL, wxBOLD)
75 self.SetFont(font)
e19b7164 76
6230a84f 77 self.colors = [ wxRED, wxGREEN, wxBLUE, wxCYAN,
07b2e1cd 78 "Yellow", "Navy" ]
e19b7164 79
f6bcfd97
BP
80 EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
81 EVT_PAINT(self, self.OnPaint)
82
e19b7164
RD
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
07b2e1cd
RD
101 def GetBestHeight(self):
102 return 2 * (self.barHeight + 1) * len(self.values)
103
104
6230a84f 105 def Draw(self, dc, size):
07b2e1cd 106 dc.SetFont(self.GetFont())
e19b7164 107 dc.SetTextForeground(wxBLUE)
6230a84f
RD
108 dc.SetBackground(wxBrush(self.GetBackgroundColour()))
109 dc.Clear()
e19b7164
RD
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
6230a84f
RD
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
3af4e610
RD
141 dc.SelectObject(wxNullBitmap)
142
6230a84f
RD
143
144 def OnEraseBackground(self, evt):
145 pass
146
147
e19b7164
RD
148
149
150#----------------------------------------------------------------------
151
152class 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
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"""