]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/demo/Threads.py
Added a demo showing how to use wxPostEvent
[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] #, wxNamedColour("Yellow") ]
78
79
80 def SetValue(self, index, value):
81 assert index < len(self.values)
82 cur = self.values[index]
83 self.values[index:index+1] = [(cur[0], value)]
84
85
86 def SetFont(self, font):
87 wxWindow.SetFont(self, font)
88 wmax = hmax = 0
89 for label, val in self.values:
90 w,h = self.GetTextExtent(label)
91 if w > wmax: wmax = w
92 if h > hmax: hmax = h
93 self.linePos = wmax + 10
94 self.barHeight = hmax
95
96
97 def OnPaint(self, evt):
98 size = self.GetSize()
99 dc = wxPaintDC(self)
100 dc.BeginDrawing()
101 dc.SetFont(self.font)
102 dc.SetTextForeground(wxBLUE)
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 dc.EndDrawing()
122
123
124 #----------------------------------------------------------------------
125
126 class TestFrame(wxFrame):
127 def __init__(self, parent, log):
128 wxFrame.__init__(self, parent, -1, "Thread Test", size=(450,300))
129 self.log = log
130
131 #self.CenterOnParent()
132
133 panel = wxPanel(self, -1)
134 panel.SetFont(wxFont(10, wxSWISS, wxNORMAL, wxBOLD))
135 wxStaticText(panel, -1,
136 "This demo shows multiple threads interacting with this\n"
137 "window by sending events to it.", wxPoint(5,5))
138 panel.Fit()
139
140 self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three'])
141
142 sizer = wxBoxSizer(wxVERTICAL)
143 sizer.Add(panel, 0, wxEXPAND)
144 sizer.Add(self.graph, 1, wxEXPAND)
145
146 self.SetSizer(sizer)
147 self.SetAutoLayout(true)
148
149 #self.graph.SetValue(0, 25)
150 #self.graph.SetValue(1, 50)
151 #self.graph.SetValue(2, 75)
152 #self.graph.SetValue(3, 100)
153
154 EVT_UPDATE_BARGRAPH(self, self.OnUpdate)
155 self.threads = []
156 self.threads.append(CalcBarThread(self, 0, 25))
157 self.threads.append(CalcBarThread(self, 1, 50))
158 self.threads.append(CalcBarThread(self, 2, 75))
159 self.threads.append(CalcBarThread(self, 3, 100))
160
161 for t in self.threads:
162 t.Start()
163
164
165
166 def OnUpdate(self, evt):
167 self.graph.SetValue(evt.barNum, evt.value)
168 self.graph.Refresh()
169
170
171 def OnCloseWindow(self, evt):
172 busy = wxBusyInfo("One moment please, waiting for threads to die...")
173 for t in self.threads:
174 t.Stop()
175 running = 1
176 while running:
177 running = 0
178 for t in self.threads:
179 running = running + t.IsRunning()
180 time.sleep(0.1)
181 self.Destroy()
182
183
184
185 #----------------------------------------------------------------------
186
187 def runTest(frame, nb, log):
188 win = TestFrame(frame, log)
189 frame.otherWin = win
190 win.Show(true)
191 return None
192
193 #----------------------------------------------------------------------
194
195
196
197
198 overview = """\
199 The main issue with multi-threaded GUI programming is the thread safty
200 of the GUI itself. On most platforms the GUI is not thread safe and
201 so any cross platform GUI Toolkit and applications written with it
202 need to take that into account.
203
204 The solution is to only allow interaction with the GUI from a single
205 thread, but this often severly limits what can be done in an
206 application and makes it difficult to use additional threads at all.
207
208 Since wxPython already makes extensive use of event handlers, it is a
209 logical extension to allow events to be sent to GUI objects from
210 alternate threads. A function called wxPostEvent allows you to do
211 this. It accepts an event and an event handler (window) and instead
212 of sending the event immediately in the current context like
213 ProcessEvent does, it processes it later from the context of the GUI
214 thread.
215
216 """