Applied patch that converts the throbber to using timers instead of threads

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@22070 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2003-07-18 01:53:08 +00:00
parent 040e234d84
commit 52fcf3b1bd

View File

@@ -4,12 +4,12 @@ started, stopped, reversed, etc. Useful for showing
an ongoing process (like most web browsers use) or an ongoing process (like most web browsers use) or
simply for adding eye-candy to an application. simply for adding eye-candy to an application.
Throbbers run in a separate thread so normal application Throbbers utilize a wxTimer so that normal processing
processing can continue unencumbered. can continue unencumbered.
""" """
# #
# throbber.py - Cliff Wells <clifford.wells@attbi.com> # throbber.py - Cliff Wells <clifford.wells@comcast.net>
# #
# Thanks to Harald Massa <harald.massa@suedvers.de> for # Thanks to Harald Massa <harald.massa@suedvers.de> for
# suggestions and sample code. # suggestions and sample code.
@@ -17,23 +17,22 @@ processing can continue unencumbered.
# $Id$ # $Id$
# #
import threading, os import os
from wxPython.wx import * import wx
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
THROBBER_EVENT = wx.NewEventType()
wxEVT_UPDATE_THROBBER = wxNewEventType()
def EVT_UPDATE_THROBBER(win, func): def EVT_UPDATE_THROBBER(win, func):
win.Connect(-1, -1, wxEVT_UPDATE_THROBBER, func) win.Connect(-1, -1, THROBBER_EVENT, func)
class UpdateThrobberEvent(wxPyEvent): class UpdateThrobberEvent(wx.PyEvent):
def __init__(self): def __init__(self):
wxPyEvent.__init__(self) wx.PyEvent.__init__(self)
self.SetEventType(wxEVT_UPDATE_THROBBER) self.SetEventType(THROBBER_EVENT)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Throbber(wxPanel): class Throbber(wx.Panel):
""" """
The first argument is either the name of a file that will be split into frames The first argument is either the name of a file that will be split into frames
(a composite image) or a list of strings of image names that will be treated (a composite image) or a list of strings of image names that will be treated
@@ -46,8 +45,8 @@ class Throbber(wxPanel):
""" """
def __init__(self, parent, id, def __init__(self, parent, id,
bitmap, # single (composite) bitmap or list of bitmaps bitmap, # single (composite) bitmap or list of bitmaps
pos = wxDefaultPosition, pos = wx.DefaultPosition,
size = wxDefaultSize, size = wx.DefaultSize,
frameDelay = 0.1,# time between frames frameDelay = 0.1,# time between frames
frames = 0, # number of frames (only necessary for composite image) frames = 0, # number of frames (only necessary for composite image)
frameWidth = 0, # width of each frame (only necessary for composite image) frameWidth = 0, # width of each frame (only necessary for composite image)
@@ -56,9 +55,10 @@ class Throbber(wxPanel):
reverse = 0, # reverse direction at end of animation reverse = 0, # reverse direction at end of animation
style = 0, # window style style = 0, # window style
name = "throbber"): name = "throbber"):
wxPanel.__init__(self, parent, id, pos, size, style, name) wx.Panel.__init__(self, parent, id, pos, size, style, name)
self.name = name self.name = name
self.label = label self.label = label
self.running = (1 != 1)
_seqTypes = (type([]), type(())) _seqTypes = (type([]), type(()))
# set size, guessing if necessary # set size, guessing if necessary
@@ -115,18 +115,20 @@ class Throbber(wxPanel):
self.SetClientSize((width, height)) self.SetClientSize((width, height))
EVT_PAINT(self, self.OnPaint) timerID = wx.NewId()
EVT_UPDATE_THROBBER(self, self.Rotate) self.timer = wx.Timer(self, timerID)
EVT_WINDOW_DESTROY(self, self.OnDestroyWindow)
self.event = threading.Event() EVT_UPDATE_THROBBER(self, self.Rotate)
self.event.set() # we start out in the "resting" state wx.EVT_PAINT(self, self.OnPaint)
wx.EVT_TIMER(self, timerID, self.OnTimer)
wx.EVT_WINDOW_DESTROY(self, self.OnDestroyWindow)
def OnTimer(self, event):
wx.PostEvent(self, UpdateThrobberEvent())
def OnDestroyWindow(self, event): def OnDestroyWindow(self, event):
# this is currently broken due to a bug in wxWindows... hopefully
# it'll be fixed soon. Meanwhile be sure to explicitly call Stop()
# before the throbber is destroyed.
self.Stop() self.Stop()
event.Skip() event.Skip()
@@ -137,27 +139,16 @@ class Throbber(wxPanel):
dc.DrawBitmap(self.overlay, self.overlayX, self.overlayY, True) dc.DrawBitmap(self.overlay, self.overlayX, self.overlayY, True)
if self.label and self.showLabel: if self.label and self.showLabel:
dc.DrawText(self.label, self.labelX, self.labelY) dc.DrawText(self.label, self.labelX, self.labelY)
dc.SetTextForeground(wxWHITE) dc.SetTextForeground(wx.WHITE)
dc.DrawText(self.label, self.labelX-1, self.labelY-1) dc.DrawText(self.label, self.labelX-1, self.labelY-1)
def OnPaint(self, event): def OnPaint(self, event):
self.Draw(wxPaintDC(self)) self.Draw(wx.PaintDC(self))
event.Skip() event.Skip()
def UpdateThread(self):
try:
while hasattr(self, 'event') and not self.event.isSet():
wxPostEvent(self, UpdateThrobberEvent())
self.event.wait(self.frameDelay)
except wxPyDeadObjectError: # BUG: we were destroyed
return
def Rotate(self, event): def Rotate(self, event):
if self.event.isSet():
return
self.current += self.direction self.current += self.direction
if self.current >= len(self.sequence): if self.current >= len(self.sequence):
if self.autoReverse: if self.autoReverse:
@@ -171,22 +162,22 @@ class Throbber(wxPanel):
self.current = 1 self.current = 1
else: else:
self.current = len(self.sequence) - 1 self.current = len(self.sequence) - 1
self.Draw(wxClientDC(self)) self.Draw(wx.ClientDC(self))
# --------- public methods --------- # --------- public methods ---------
def SetFont(self, font): def SetFont(self, font):
"""Set the font for the label""" """Set the font for the label"""
wxPanel.SetFont(self, font) wx.Panel.SetFont(self, font)
self.SetLabel(self.label) self.SetLabel(self.label)
self.Draw(wxClientDC(self)) self.Draw(wx.ClientDC(self))
def Rest(self): def Rest(self):
"""Stop the animation and return to frame 0""" """Stop the animation and return to frame 0"""
self.Stop() self.Stop()
self.current = 0 self.current = 0
self.Draw(wxClientDC(self)) self.Draw(wx.ClientDC(self))
def Reverse(self): def Reverse(self):
@@ -196,28 +187,29 @@ class Throbber(wxPanel):
def Running(self): def Running(self):
"""Returns True if the animation is running""" """Returns True if the animation is running"""
return not self.event.isSet() return self.running
def Start(self): def Start(self):
"""Start the animation""" """Start the animation"""
if not self.Running(): if not self.running:
self.event.clear() self.running = not self.running
thread = threading.Thread(target = self.UpdateThread, self.timer.Start(self.frameDelay * 1000)
name = "%s-thread" % self.name)
thread.start()
def Stop(self): def Stop(self):
"""Stop the animation""" """Stop the animation"""
if self.event.isSet(): if self.running:
return self.timer.Stop()
self.event.set() self.running = not self.running
def SetFrameDelay(self, frameDelay = 0.05): def SetFrameDelay(self, frameDelay = 0.05):
"""Delay between each frame""" """Delay between each frame"""
self.frameDelay = frameDelay self.frameDelay = frameDelay
if self.running:
self.Stop()
self.Start()
def ToggleOverlay(self, state = None): def ToggleOverlay(self, state = None):
@@ -226,7 +218,7 @@ class Throbber(wxPanel):
self.showOverlay = not self.showOverlay self.showOverlay = not self.showOverlay
else: else:
self.showOverlay = state self.showOverlay = state
self.Draw(wxClientDC(self)) self.Draw(wx.ClientDC(self))
def ToggleLabel(self, state = None): def ToggleLabel(self, state = None):
@@ -235,7 +227,7 @@ class Throbber(wxPanel):
self.showLabel = not self.showLabel self.showLabel = not self.showLabel
else: else:
self.showLabel = state self.showLabel = state
self.Draw(wxClientDC(self)) self.Draw(wx.ClientDC(self))
def SetLabel(self, label): def SetLabel(self, label):
@@ -245,7 +237,7 @@ class Throbber(wxPanel):
extentX, extentY = self.GetTextExtent(label) extentX, extentY = self.GetTextExtent(label)
self.labelX = (self.width - extentX)/2 self.labelX = (self.width - extentX)/2
self.labelY = (self.height - extentY)/2 self.labelY = (self.height - extentY)/2
self.Draw(wxClientDC(self)) self.Draw(wx.ClientDC(self))