]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Threads.py
9 #----------------------------------------------------------------------
11 # This creates a new Event class and a EVT binder function
12 (UpdateBarEvent
, EVT_UPDATE_BARGRAPH
) = wx
.lib
.newevent
.NewEvent()
15 #----------------------------------------------------------------------
18 def __init__(self
, win
, barNum
, val
):
24 self
.keepGoing
= self
.running
= True
25 thread
.start_new_thread(self
.Run
, ())
28 self
.keepGoing
= False
35 evt
= UpdateBarEvent(barNum
= self
.barNum
, value
= int(self
.val
))
36 wx
.PostEvent(self
.win
, evt
)
38 sleeptime
= (random
.random() * 2) + 0.5
39 time
.sleep(sleeptime
/4)
41 sleeptime
= sleeptime
* 5
42 if int(random
.random() * 2):
43 self
.val
= self
.val
+ sleeptime
45 self
.val
= self
.val
- sleeptime
47 if self
.val
< 0: self
.val
= 0
48 if self
.val
> 300: self
.val
= 300
52 #----------------------------------------------------------------------
55 class GraphWindow(wx
.Window
):
56 def __init__(self
, parent
, labels
):
57 wx
.Window
.__init
__(self
, parent
, -1)
61 self
.values
.append((label
, 0))
63 font
= wx
.Font(12, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
)
66 self
.colors
= [ wx
.RED
, wx
.GREEN
, wx
.BLUE
, wx
.CYAN
,
69 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
70 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
73 def SetValue(self
, index
, value
):
74 assert index
< len(self
.values
)
75 cur
= self
.values
[index
]
76 self
.values
[index
:index
+1] = [(cur
[0], value
)]
79 def SetFont(self
, font
):
80 wx
.Window
.SetFont(self
, font
)
82 for label
, val
in self
.values
:
83 w
,h
= self
.GetTextExtent(label
)
86 self
.linePos
= wmax
+ 10
90 def GetBestHeight(self
):
91 return 2 * (self
.barHeight
+ 1) * len(self
.values
)
94 def Draw(self
, dc
, size
):
95 dc
.SetFont(self
.GetFont())
96 dc
.SetTextForeground(wx
.BLUE
)
97 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour()))
99 dc
.SetPen(wx
.Pen(wx
.BLACK
, 3, wx
.SOLID
))
100 dc
.DrawLine(self
.linePos
, 0, self
.linePos
, size
.height
-10)
102 bh
= ypos
= self
.barHeight
103 for x
in range(len(self
.values
)):
104 label
, val
= self
.values
[x
]
105 dc
.DrawText(label
, 5, ypos
)
108 color
= self
.colors
[ x
% len(self
.colors
) ]
109 dc
.SetPen(wx
.Pen(color
))
110 dc
.SetBrush(wx
.Brush(color
))
111 dc
.DrawRectangle(self
.linePos
+3, ypos
, val
, bh
)
114 if ypos
> size
[1]-10:
118 def OnPaint(self
, evt
):
119 dc
= wx
.BufferedPaintDC(self
)
120 self
.Draw(dc
, self
.GetSize())
123 def OnEraseBackground(self
, evt
):
129 #----------------------------------------------------------------------
131 class TestFrame(wx
.Frame
):
132 def __init__(self
, parent
, log
):
133 wx
.Frame
.__init
__(self
, parent
, -1, "Thread Test", size
=(450,300))
136 #self.CenterOnParent()
138 panel
= wx
.Panel(self
, -1)
139 panel
.SetFont(wx
.Font(10, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
140 wx
.StaticText(panel
, -1,
141 "This demo shows multiple threads interacting with this\n"
142 "window by sending events to it, one thread for each bar.",
146 self
.graph
= GraphWindow(self
, ['Zero', 'One', 'Two', 'Three', 'Four',
147 'Five', 'Six', 'Seven'])
148 self
.graph
.SetSize((450, self
.graph
.GetBestHeight()))
150 sizer
= wx
.BoxSizer(wx
.VERTICAL
)
151 sizer
.Add(panel
, 0, wx
.EXPAND
)
152 sizer
.Add(self
.graph
, 1, wx
.EXPAND
)
155 self
.SetAutoLayout(True)
158 self
.Bind(EVT_UPDATE_BARGRAPH
, self
.OnUpdate
)
161 self
.threads
.append(CalcBarThread(self
, 0, 50))
162 self
.threads
.append(CalcBarThread(self
, 1, 75))
163 self
.threads
.append(CalcBarThread(self
, 2, 100))
164 self
.threads
.append(CalcBarThread(self
, 3, 150))
165 self
.threads
.append(CalcBarThread(self
, 4, 225))
166 self
.threads
.append(CalcBarThread(self
, 5, 300))
167 self
.threads
.append(CalcBarThread(self
, 6, 250))
168 self
.threads
.append(CalcBarThread(self
, 7, 175))
170 for t
in self
.threads
:
173 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
176 def OnUpdate(self
, evt
):
177 self
.graph
.SetValue(evt
.barNum
, evt
.value
)
178 self
.graph
.Refresh(False)
181 def OnCloseWindow(self
, evt
):
182 busy
= wx
.BusyInfo("One moment please, waiting for threads to die...")
185 for t
in self
.threads
:
193 for t
in self
.threads
:
194 running
= running
+ t
.IsRunning()
202 #---------------------------------------------------------------------------
204 class TestPanel(wx
.Panel
):
205 def __init__(self
, parent
, log
):
207 wx
.Panel
.__init
__(self
, parent
, -1)
209 b
= wx
.Button(self
, -1, "Show Threads sample", (50,50))
210 self
.Bind(wx
.EVT_BUTTON
, self
.OnButton
, b
)
213 def OnButton(self
, evt
):
214 win
= TestFrame(self
, self
.log
)
218 #---------------------------------------------------------------------------
221 def runTest(frame
, nb
, log
):
222 win
= TestPanel(nb
, log
)
225 #----------------------------------------------------------------------
232 The main issue with multi-threaded GUI programming is the thread safty
233 of the GUI itself. On most platforms the GUI is not thread safe and
234 so any cross platform GUI Toolkit and applications written with it
235 need to take that into account.
237 The solution is to only allow interaction with the GUI from a single
238 thread, but this often severely limits what can be done in an
239 application and makes it difficult to use additional threads at all.
241 Since wxPython already makes extensive use of event handlers, it is a
242 logical extension to allow events to be sent to GUI objects from
243 alternate threads. A function called wx.PostEvent allows you to do
244 this. It accepts an event and an event handler (window) and instead
245 of sending the event immediately in the current context like
246 ProcessEvent does, it processes it later from the context of the GUI
253 if __name__
== '__main__':
256 run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])