]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Threads.py
6d9f5a1d5be8ded3565991aa99f3c9000e0b38df
1 # 11/13/2003 - Jeff Grimmett (grimmtooth@softhome.net)
3 # o Updated for wx namespace
4 # o Replaced deprecated whrandom with random module.
6 # 11/13/2003 - Jeff Grimmett (grimmtooth@softhome.net)
8 # o Currently uses lib.newevent; should probably be updated to use
9 # new-style event binder. OTOH, this is the only place we get
10 # to see that library used that I know of.
18 import wx
.lib
.newevent
20 #----------------------------------------------------------------------
22 # This creates a new Event class and a EVT binder function
23 (UpdateBarEvent
, EVT_UPDATE_BARGRAPH
) = wx
.lib
.newevent
.NewEvent()
26 #----------------------------------------------------------------------
29 def __init__(self
, win
, barNum
, val
):
35 self
.keepGoing
= self
.running
= True
36 thread
.start_new_thread(self
.Run
, ())
39 self
.keepGoing
= False
46 evt
= UpdateBarEvent(barNum
= self
.barNum
, value
= int(self
.val
))
47 wx
.PostEvent(self
.win
.GetEventHandler(), evt
)
50 sleeptime
= (random
.random() * 2) + 0.5
51 time
.sleep(sleeptime
/4)
53 sleeptime
= sleeptime
* 5
54 if int(random
.random() * 2):
55 self
.val
= self
.val
+ sleeptime
57 self
.val
= self
.val
- sleeptime
59 if self
.val
< 0: self
.val
= 0
60 if self
.val
> 300: self
.val
= 300
64 #----------------------------------------------------------------------
67 class GraphWindow(wx
.Window
):
68 def __init__(self
, parent
, labels
):
69 wx
.Window
.__init
__(self
, parent
, -1)
73 self
.values
.append((label
, 0))
75 font
= wx
.Font(12, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
)
78 self
.colors
= [ wx
.RED
, wx
.GREEN
, wx
.BLUE
, wx
.CYAN
,
81 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
82 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
85 def SetValue(self
, index
, value
):
86 assert index
< len(self
.values
)
87 cur
= self
.values
[index
]
88 self
.values
[index
:index
+1] = [(cur
[0], value
)]
91 def SetFont(self
, font
):
92 wx
.Window
.SetFont(self
, font
)
94 for label
, val
in self
.values
:
95 w
,h
= self
.GetTextExtent(label
)
98 self
.linePos
= wmax
+ 10
102 def GetBestHeight(self
):
103 return 2 * (self
.barHeight
+ 1) * len(self
.values
)
106 def Draw(self
, dc
, size
):
107 dc
.SetFont(self
.GetFont())
108 dc
.SetTextForeground(wx
.BLUE
)
109 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour()))
111 dc
.SetPen(wxPen(wxBLACK
, 3, wxSOLID
))
112 dc
.DrawLine((self
.linePos
, 0), (self
.linePos
, size
.height
-10))
114 bh
= ypos
= self
.barHeight
115 for x
in range(len(self
.values
)):
116 label
, val
= self
.values
[x
]
117 dc
.DrawText(label
, (5, ypos
))
120 color
= self
.colors
[ x
% len(self
.colors
) ]
121 dc
.SetPen(wxPen(color
))
122 dc
.SetBrush(wxBrush(color
))
123 dc
.DrawRectangle((self
.linePos
+3, ypos
), (val
, bh
))
126 if ypos
> size
[1]-10:
130 def OnPaint(self
, evt
):
131 width
, height
= self
.GetSize()
132 bmp
= wx
.EmptyBitmap(width
, height
)
137 self
.Draw(dc
, (width
, height
))
139 wdc
= wx
.PaintDC(self
)
141 wdc
.Blit((0,0), size
, dc
, (0,0))
144 dc
.SelectObject(wx
.NullBitmap
)
147 def OnEraseBackground(self
, evt
):
153 #----------------------------------------------------------------------
155 class TestFrame(wx
.Frame
):
156 def __init__(self
, parent
, log
):
157 wx
.Frame
.__init
__(self
, parent
, -1, "Thread Test", size
=(450,300))
160 #self.CenterOnParent()
162 panel
= wx
.Panel(self
, -1)
163 panel
.SetFont(wx
.Font(10, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
164 wx
.StaticText(panel
, -1,
165 "This demo shows multiple threads interacting with this\n"
166 "window by sending events to it, one thread for each bar.",
170 self
.graph
= GraphWindow(self
, ['Zero', 'One', 'Two', 'Three', 'Four',
171 'Five', 'Six', 'Seven'])
172 self
.graph
.SetSize((450, self
.graph
.GetBestHeight()))
174 sizer
= wx
.BoxSizer(wx
.VERTICAL
)
175 sizer
.Add(panel
, 0, wx
.EXPAND
)
176 sizer
.Add(self
.graph
, 1, wx
.EXPAND
)
179 self
.SetAutoLayout(True)
182 self
.Bind(EVT_UPDATE_BARGRAPH
, self
.OnUpdate
)
185 self
.threads
.append(CalcBarThread(self
, 0, 50))
186 self
.threads
.append(CalcBarThread(self
, 1, 75))
187 self
.threads
.append(CalcBarThread(self
, 2, 100))
188 self
.threads
.append(CalcBarThread(self
, 3, 150))
189 self
.threads
.append(CalcBarThread(self
, 4, 225))
190 self
.threads
.append(CalcBarThread(self
, 5, 300))
191 self
.threads
.append(CalcBarThread(self
, 6, 250))
192 self
.threads
.append(CalcBarThread(self
, 7, 175))
194 for t
in self
.threads
:
197 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
200 def OnUpdate(self
, evt
):
201 self
.graph
.SetValue(evt
.barNum
, evt
.value
)
202 self
.graph
.Refresh(False)
205 def OnCloseWindow(self
, evt
):
206 busy
= wx
.BusyInfo("One moment please, waiting for threads to die...")
209 for t
in self
.threads
:
217 for t
in self
.threads
:
218 running
= running
+ t
.IsRunning()
226 #----------------------------------------------------------------------
228 def runTest(frame
, nb
, log
):
229 win
= TestFrame(frame
, log
)
234 #----------------------------------------------------------------------
240 The main issue with multi-threaded GUI programming is the thread safty
241 of the GUI itself. On most platforms the GUI is not thread safe and
242 so any cross platform GUI Toolkit and applications written with it
243 need to take that into account.
245 The solution is to only allow interaction with the GUI from a single
246 thread, but this often severely limits what can be done in an
247 application and makes it difficult to use additional threads at all.
249 Since wxPython already makes extensive use of event handlers, it is a
250 logical extension to allow events to be sent to GUI objects from
251 alternate threads. A function called wx.PostEvent allows you to do
252 this. It accepts an event and an event handler (window) and instead
253 of sending the event immediately in the current context like
254 ProcessEvent does, it processes it later from the context of the GUI
261 if __name__
== '__main__':
264 run
.main(['', os
.path
.basename(sys
.argv
[0])])