Applied patch that converts the throbber to using timers instead of threads
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@22070 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user