]>
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
.GetEventHandler(), evt
)
39 sleeptime
= (random
.random() * 2) + 0.5
40 time
.sleep(sleeptime
/4)
42 sleeptime
= sleeptime
* 5
43 if int(random
.random() * 2):
44 self
.val
= self
.val
+ sleeptime
46 self
.val
= self
.val
- sleeptime
48 if self
.val
< 0: self
.val
= 0
49 if self
.val
> 300: self
.val
= 300
53 #----------------------------------------------------------------------
56 class GraphWindow(wx
.Window
):
57 def __init__(self
, parent
, labels
):
58 wx
.Window
.__init
__(self
, parent
, -1)
62 self
.values
.append((label
, 0))
64 font
= wx
.Font(12, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
)
67 self
.colors
= [ wx
.RED
, wx
.GREEN
, wx
.BLUE
, wx
.CYAN
,
70 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
71 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
74 def SetValue(self
, index
, value
):
75 assert index
< len(self
.values
)
76 cur
= self
.values
[index
]
77 self
.values
[index
:index
+1] = [(cur
[0], value
)]
80 def SetFont(self
, font
):
81 wx
.Window
.SetFont(self
, font
)
83 for label
, val
in self
.values
:
84 w
,h
= self
.GetTextExtent(label
)
87 self
.linePos
= wmax
+ 10
91 def GetBestHeight(self
):
92 return 2 * (self
.barHeight
+ 1) * len(self
.values
)
95 def Draw(self
, dc
, size
):
96 dc
.SetFont(self
.GetFont())
97 dc
.SetTextForeground(wx
.BLUE
)
98 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour()))
100 dc
.SetPen(wx
.Pen(wx
.BLACK
, 3, wx
.SOLID
))
101 dc
.DrawLine((self
.linePos
, 0), (self
.linePos
, size
.height
-10))
103 bh
= ypos
= self
.barHeight
104 for x
in range(len(self
.values
)):
105 label
, val
= self
.values
[x
]
106 dc
.DrawText(label
, (5, ypos
))
109 color
= self
.colors
[ x
% len(self
.colors
) ]
110 dc
.SetPen(wx
.Pen(color
))
111 dc
.SetBrush(wx
.Brush(color
))
112 dc
.DrawRectangle((self
.linePos
+3, ypos
), (val
, bh
))
115 if ypos
> size
[1]-10:
119 def OnPaint(self
, evt
):
120 width
, height
= size
=self
.GetSize()
121 bmp
= wx
.EmptyBitmap(width
, height
)
129 wdc
= wx
.PaintDC(self
)
131 wdc
.Blit((0,0), size
, dc
, (0,0))
134 dc
.SelectObject(wx
.NullBitmap
)
137 def OnEraseBackground(self
, evt
):
143 #----------------------------------------------------------------------
145 class TestFrame(wx
.Frame
):
146 def __init__(self
, parent
, log
):
147 wx
.Frame
.__init
__(self
, parent
, -1, "Thread Test", size
=(450,300))
150 #self.CenterOnParent()
152 panel
= wx
.Panel(self
, -1)
153 panel
.SetFont(wx
.Font(10, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
))
154 wx
.StaticText(panel
, -1,
155 "This demo shows multiple threads interacting with this\n"
156 "window by sending events to it, one thread for each bar.",
160 self
.graph
= GraphWindow(self
, ['Zero', 'One', 'Two', 'Three', 'Four',
161 'Five', 'Six', 'Seven'])
162 self
.graph
.SetSize((450, self
.graph
.GetBestHeight()))
164 sizer
= wx
.BoxSizer(wx
.VERTICAL
)
165 sizer
.Add(panel
, 0, wx
.EXPAND
)
166 sizer
.Add(self
.graph
, 1, wx
.EXPAND
)
169 self
.SetAutoLayout(True)
172 self
.Bind(EVT_UPDATE_BARGRAPH
, self
.OnUpdate
)
175 self
.threads
.append(CalcBarThread(self
, 0, 50))
176 self
.threads
.append(CalcBarThread(self
, 1, 75))
177 self
.threads
.append(CalcBarThread(self
, 2, 100))
178 self
.threads
.append(CalcBarThread(self
, 3, 150))
179 self
.threads
.append(CalcBarThread(self
, 4, 225))
180 self
.threads
.append(CalcBarThread(self
, 5, 300))
181 self
.threads
.append(CalcBarThread(self
, 6, 250))
182 self
.threads
.append(CalcBarThread(self
, 7, 175))
184 for t
in self
.threads
:
187 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
190 def OnUpdate(self
, evt
):
191 self
.graph
.SetValue(evt
.barNum
, evt
.value
)
192 self
.graph
.Refresh(False)
195 def OnCloseWindow(self
, evt
):
196 busy
= wx
.BusyInfo("One moment please, waiting for threads to die...")
199 for t
in self
.threads
:
207 for t
in self
.threads
:
208 running
= running
+ t
.IsRunning()
216 #----------------------------------------------------------------------
218 def runTest(frame
, nb
, log
):
219 win
= TestFrame(frame
, log
)
224 #----------------------------------------------------------------------
230 The main issue with multi-threaded GUI programming is the thread safty
231 of the GUI itself. On most platforms the GUI is not thread safe and
232 so any cross platform GUI Toolkit and applications written with it
233 need to take that into account.
235 The solution is to only allow interaction with the GUI from a single
236 thread, but this often severely limits what can be done in an
237 application and makes it difficult to use additional threads at all.
239 Since wxPython already makes extensive use of event handlers, it is a
240 logical extension to allow events to be sent to GUI objects from
241 alternate threads. A function called wx.PostEvent allows you to do
242 this. It accepts an event and an event handler (window) and instead
243 of sending the event immediately in the current context like
244 ProcessEvent does, it processes it later from the context of the GUI
251 if __name__
== '__main__':
254 run
.main(['', os
.path
.basename(sys
.argv
[0])])