]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/throbber.py
   2 A throbber displays an animated image that can be 
   3 started, stopped, reversed, etc.  Useful for showing 
   4 an ongoing process (like most web browsers use) or 
   5 simply for adding eye-candy to an application. 
   7 Throbbers utilize a wxTimer so that normal processing 
   8 can continue unencumbered. 
  12 # throbber.py - Cliff Wells <clifford.wells@comcast.net> 
  14 # Thanks to Harald Massa <harald.massa@suedvers.de> for 
  15 # suggestions and sample code. 
  19 # 12/12/2003 - Jeff Grimmett (grimmtooth@softhome.net) 
  21 # o 2.5 compatability update. 
  28 # ------------------------------------------------------------------------------ 
  30 THROBBER_EVENT 
= wx
.NewEventType() 
  31 EVT_UPDATE_THROBBER 
= wx
.PyEventBinder(THROBBER_EVENT
, 0) 
  33 class UpdateThrobberEvent(wx
.PyEvent
): 
  35         wx
.PyEvent
.__init
__(self
) 
  36         self
.SetEventType(THROBBER_EVENT
) 
  38 # ------------------------------------------------------------------------------ 
  40 class Throbber(wx
.PyPanel
): 
  42     The first argument is either the name of a file that will be split into frames 
  43     (a composite image) or a list of  strings of image names that will be treated 
  44     as individual frames.  If a single (composite) image is given, then additional 
  45     information must be provided: the number of frames in the image and the width 
  46     of each frame.  The first frame is treated as the "at rest" frame (it is not 
  47     shown during animation, but only when Throbber.Rest() is called. 
  48     A second, single image may be optionally specified to overlay on top of the 
  49     animation. A label may also be specified to show on top of the animation. 
  51     def __init__(self
, parent
, id, 
  52                  bitmap
,          # single (composite) bitmap or list of bitmaps 
  53                  pos 
= wx
.DefaultPosition
, 
  54                  size 
= wx
.DefaultSize
, 
  55                  frameDelay 
= 0.1,# time between frames 
  56                  frames 
= 0,      # number of frames (only necessary for composite image) 
  57                  frameWidth 
= 0,  # width of each frame (only necessary for composite image) 
  58                  label 
= None,    # optional text to be displayed 
  59                  overlay 
= None,  # optional image to overlay on animation 
  60                  reverse 
= 0,     # reverse direction at end of animation 
  61                  style 
= 0,       # window style 
  68         wx
.PyPanel
.__init
__(self
, parent
, id, pos
, size
, style
, name
) 
  71         self
.running 
= (1 != 1) 
  72         _seqTypes 
= (type([]), type(())) 
  74         # set size, guessing if necessary 
  77             if type(bitmap
) in _seqTypes
: 
  78                 width 
= bitmap
[0].GetWidth() 
  83             if type(bitmap
) in _seqTypes
: 
  84                 height 
= bitmap
[0].GetHeight() 
  86                 height 
= bitmap
.GetHeight() 
  87         self
.width
, self
.height 
= width
, height
 
  90         assert width 
!= -1 and height 
!= -1, "Unable to guess size" 
  93             extentX
, extentY 
= self
.GetTextExtent(label
) 
  94             self
.labelX 
= (width 
- extentX
)/2 
  95             self
.labelY 
= (height 
- extentY
)/2 
  96         self
.frameDelay 
= frameDelay
 
  98         self
.current 
= current
 
  99         self
.direction 
= direction
 
 100         self
.autoReverse 
= reverse
 
 101         self
.overlay 
= overlay
 
 102         if overlay 
is not None: 
 103             self
.overlay 
= overlay
 
 104             self
.overlayX 
= (width 
- self
.overlay
.GetWidth()) / 2 
 105             self
.overlayY 
= (height 
- self
.overlay
.GetHeight()) / 2 
 106         self
.showOverlay 
= overlay 
is not None 
 107         self
.showLabel 
= label 
is not None 
 109         # do we have a sequence of images? 
 110         if type(bitmap
) in _seqTypes
: 
 111             self
.submaps 
= bitmap
 
 112             self
.frames 
= len(self
.submaps
) 
 113         # or a composite image that needs to be split? 
 117             for chunk 
in range(frames
): 
 118                 rect 
= (chunk 
* frameWidth
, 0, width
, height
) 
 119                 self
.submaps
.append(bitmap
.GetSubBitmap(rect
)) 
 121         # self.sequence can be changed, but it's not recommended doing it 
 122         # while the throbber is running.  self.sequence[0] should always 
 123         # refer to whatever frame is to be shown when 'resting' and be sure 
 124         # that no item in self.sequence >= self.frames or < 0!!! 
 125         self
.SetSequence(sequence
) 
 127         self
.SetClientSize((width
, height
)) 
 130         self
.timer 
= wx
.Timer(self
, timerID
) 
 132         self
.Bind(EVT_UPDATE_THROBBER
, self
.Update
) 
 133         self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
) 
 134         self
.Bind(wx
.EVT_TIMER
, self
.OnTimer
, self
.timer
) 
 135         self
.Bind(wx
.EVT_WINDOW_DESTROY
, self
.OnDestroyWindow
) 
 138     def DoGetBestSize(self
): 
 139         return (self
.width
, self
.height
) 
 142     def OnTimer(self
, event
): 
 143         wx
.PostEvent(self
, UpdateThrobberEvent()) 
 146     def OnDestroyWindow(self
, event
): 
 152         dc
.DrawBitmap(self
.submaps
[self
.sequence
[self
.current
]], 0, 0, True) 
 153         if self
.overlay 
and self
.showOverlay
: 
 154             dc
.DrawBitmap(self
.overlay
, self
.overlayX
, self
.overlayY
, True) 
 155         if self
.label 
and self
.showLabel
: 
 156             dc
.DrawText(self
.label
, self
.labelX
, self
.labelY
) 
 157             dc
.SetTextForeground(wx
.WHITE
) 
 158             dc
.DrawText(self
.label
, self
.labelX
-1, self
.labelY
-1) 
 161     def OnPaint(self
, event
): 
 162         self
.Draw(wx
.PaintDC(self
)) 
 166     def Update(self
, event
): 
 171         if self
.current 
>= len(self
.sequence
): 
 174                 self
.current 
= len(self
.sequence
) - 1 
 182                 self
.current 
= len(self
.sequence
) - 1 
 183         self
.Draw(wx
.ClientDC(self
)) 
 186     # --------- public methods --------- 
 187     def SetFont(self
, font
): 
 188         """Set the font for the label""" 
 189         wx
.Panel
.SetFont(self
, font
) 
 190         self
.SetLabel(self
.label
) 
 191         self
.Draw(wx
.ClientDC(self
)) 
 195         """Stop the animation and return to frame 0""" 
 197         self
.current 
= self
.rest
 
 198         self
.Draw(wx
.ClientDC(self
)) 
 202         """Change the direction of the animation""" 
 203         self
.direction 
= -self
.direction
 
 207         """Returns True if the animation is running""" 
 212         """Start the animation""" 
 214             self
.running 
= not self
.running
 
 215             self
.timer
.Start(int(self
.frameDelay 
* 1000)) 
 219         """Stop the animation""" 
 222             self
.running 
= not self
.running
 
 225     def SetCurrent(self
, current
): 
 226         """Set current image""" 
 227         running 
= self
.Running() 
 229             #FIXME: need to make sure value is within range!!! 
 230             self
.current 
= current
 
 231             self
.Draw(wx
.ClientDC(self
)) 
 234     def SetRest(self
, rest
): 
 239     def SetSequence(self
, sequence 
= None): 
 240         """Order to display images""" 
 242         # self.sequence can be changed, but it's not recommended doing it 
 243         # while the throbber is running.  self.sequence[0] should always 
 244         # refer to whatever frame is to be shown when 'resting' and be sure 
 245         # that no item in self.sequence >= self.frames or < 0!!! 
 247         running 
= self
.Running() 
 250         if sequence 
is not None: 
 251             #FIXME: need to make sure values are within range!!! 
 252             self
.sequence 
= sequence
 
 254             self
.sequence 
= range(self
.frames
) 
 261         """Display next image in sequence""" 
 267         """Display previous image in sequence""" 
 273         """Display next image in sequence according to direction""" 
 274         self
.current 
+= self
.direction
 
 279         """Display previous image in sequence according to direction""" 
 280         self
.current 
-= self
.direction
 
 284     def SetFrameDelay(self
, frameDelay 
= 0.05): 
 285         """Delay between each frame""" 
 286         self
.frameDelay 
= frameDelay
 
 292     def ToggleOverlay(self
, state 
= None): 
 293         """Toggle the overlay image""" 
 295             self
.showOverlay 
= not self
.showOverlay
 
 297             self
.showOverlay 
= state
 
 298         self
.Draw(wx
.ClientDC(self
)) 
 301     def ToggleLabel(self
, state 
= None): 
 302         """Toggle the label""" 
 304             self
.showLabel 
= not self
.showLabel
 
 306             self
.showLabel 
= state
 
 307         self
.Draw(wx
.ClientDC(self
)) 
 310     def SetLabel(self
, label
): 
 311         """Change the text of the label""" 
 314             extentX
, extentY 
= self
.GetTextExtent(label
) 
 315             self
.labelX 
= (self
.width 
- extentX
)/2 
 316             self
.labelY 
= (self
.height 
- extentY
)/2 
 317         self
.Draw(wx
.ClientDC(self
)) 
 321 # ------------------------------------------------------------------------------