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