]>
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         width
, height 
= size 
=self
.GetSize() 
 120         bmp 
= wx
.EmptyBitmap(width
, height
) 
 128         wdc 
= wx
.PaintDC(self
) 
 130         wdc
.Blit((0,0), size
, dc
, (0,0)) 
 133         dc
.SelectObject(wx
.NullBitmap
) 
 136     def OnEraseBackground(self
, evt
): 
 142 #---------------------------------------------------------------------- 
 144 class TestFrame(wx
.Frame
): 
 145     def __init__(self
, parent
, log
): 
 146         wx
.Frame
.__init
__(self
, parent
, -1, "Thread Test", size
=(450,300)) 
 149         #self.CenterOnParent() 
 151         panel 
= wx
.Panel(self
, -1) 
 152         panel
.SetFont(wx
.Font(10, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
)) 
 153         wx
.StaticText(panel
, -1, 
 154                      "This demo shows multiple threads interacting with this\n" 
 155                      "window by sending events to it, one thread for each bar.", 
 159         self
.graph 
= GraphWindow(self
, ['Zero', 'One', 'Two', 'Three', 'Four', 
 160                                         'Five', 'Six', 'Seven']) 
 161         self
.graph
.SetSize((450, self
.graph
.GetBestHeight())) 
 163         sizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 164         sizer
.Add(panel
, 0, wx
.EXPAND
) 
 165         sizer
.Add(self
.graph
, 1, wx
.EXPAND
) 
 168         self
.SetAutoLayout(True) 
 171         self
.Bind(EVT_UPDATE_BARGRAPH
, self
.OnUpdate
) 
 174         self
.threads
.append(CalcBarThread(self
, 0, 50)) 
 175         self
.threads
.append(CalcBarThread(self
, 1, 75)) 
 176         self
.threads
.append(CalcBarThread(self
, 2, 100)) 
 177         self
.threads
.append(CalcBarThread(self
, 3, 150)) 
 178         self
.threads
.append(CalcBarThread(self
, 4, 225)) 
 179         self
.threads
.append(CalcBarThread(self
, 5, 300)) 
 180         self
.threads
.append(CalcBarThread(self
, 6, 250)) 
 181         self
.threads
.append(CalcBarThread(self
, 7, 175)) 
 183         for t 
in self
.threads
: 
 186         self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
) 
 189     def OnUpdate(self
, evt
): 
 190         self
.graph
.SetValue(evt
.barNum
, evt
.value
) 
 191         self
.graph
.Refresh(False) 
 194     def OnCloseWindow(self
, evt
): 
 195         busy 
= wx
.BusyInfo("One moment please, waiting for threads to die...") 
 198         for t 
in self
.threads
: 
 206             for t 
in self
.threads
: 
 207                 running 
= running 
+ t
.IsRunning() 
 215 #---------------------------------------------------------------------- 
 217 def runTest(frame
, nb
, log
): 
 218     win 
= TestFrame(frame
, log
) 
 223 #---------------------------------------------------------------------- 
 229 The main issue with multi-threaded GUI programming is the thread safty 
 230 of the GUI itself.  On most platforms the GUI is not thread safe and 
 231 so any cross platform GUI Toolkit and applications written with it 
 232 need to take that into account. 
 234 The solution is to only allow interaction with the GUI from a single 
 235 thread, but this often severely limits what can be done in an 
 236 application and makes it difficult to use additional threads at all. 
 238 Since wxPython already makes extensive use of event handlers, it is a 
 239 logical extension to allow events to be sent to GUI objects from 
 240 alternate threads.  A function called wx.PostEvent allows you to do 
 241 this.  It accepts an event and an event handler (window) and instead 
 242 of sending the event immediately in the current context like 
 243 ProcessEvent does, it processes it later from the context of the GUI 
 250 if __name__ 
== '__main__': 
 253     run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])