]>
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:])