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:
parent
040e234d84
commit
52fcf3b1bd
@ -4,12 +4,12 @@ started, stopped, reversed, etc. Useful for showing
|
||||
an ongoing process (like most web browsers use) or
|
||||
simply for adding eye-candy to an application.
|
||||
|
||||
Throbbers run in a separate thread so normal application
|
||||
processing can continue unencumbered.
|
||||
Throbbers utilize a wxTimer so that normal processing
|
||||
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
|
||||
# suggestions and sample code.
|
||||
@ -17,23 +17,22 @@ processing can continue unencumbered.
|
||||
# $Id$
|
||||
#
|
||||
|
||||
import threading, os
|
||||
from wxPython.wx import *
|
||||
import os
|
||||
import wx
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
wxEVT_UPDATE_THROBBER = wxNewEventType()
|
||||
THROBBER_EVENT = wx.NewEventType()
|
||||
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):
|
||||
wxPyEvent.__init__(self)
|
||||
self.SetEventType(wxEVT_UPDATE_THROBBER)
|
||||
wx.PyEvent.__init__(self)
|
||||
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
|
||||
(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,
|
||||
bitmap, # single (composite) bitmap or list of bitmaps
|
||||
pos = wxDefaultPosition,
|
||||
size = wxDefaultSize,
|
||||
pos = wx.DefaultPosition,
|
||||
size = wx.DefaultSize,
|
||||
frameDelay = 0.1,# time between frames
|
||||
frames = 0, # number of frames (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
|
||||
style = 0, # window style
|
||||
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.label = label
|
||||
self.running = (1 != 1)
|
||||
_seqTypes = (type([]), type(()))
|
||||
|
||||
# set size, guessing if necessary
|
||||
@ -115,18 +115,20 @@ class Throbber(wxPanel):
|
||||
|
||||
self.SetClientSize((width, height))
|
||||
|
||||
EVT_PAINT(self, self.OnPaint)
|
||||
EVT_UPDATE_THROBBER(self, self.Rotate)
|
||||
EVT_WINDOW_DESTROY(self, self.OnDestroyWindow)
|
||||
timerID = wx.NewId()
|
||||
self.timer = wx.Timer(self, timerID)
|
||||
|
||||
self.event = threading.Event()
|
||||
self.event.set() # we start out in the "resting" state
|
||||
EVT_UPDATE_THROBBER(self, self.Rotate)
|
||||
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):
|
||||
# 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()
|
||||
event.Skip()
|
||||
|
||||
@ -137,27 +139,16 @@ class Throbber(wxPanel):
|
||||
dc.DrawBitmap(self.overlay, self.overlayX, self.overlayY, True)
|
||||
if self.label and self.showLabel:
|
||||
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)
|
||||
|
||||
|
||||
def OnPaint(self, event):
|
||||
self.Draw(wxPaintDC(self))
|
||||
self.Draw(wx.PaintDC(self))
|
||||
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):
|
||||
if self.event.isSet():
|
||||
return
|
||||
self.current += self.direction
|
||||
if self.current >= len(self.sequence):
|
||||
if self.autoReverse:
|
||||
@ -171,22 +162,22 @@ class Throbber(wxPanel):
|
||||
self.current = 1
|
||||
else:
|
||||
self.current = len(self.sequence) - 1
|
||||
self.Draw(wxClientDC(self))
|
||||
self.Draw(wx.ClientDC(self))
|
||||
|
||||
|
||||
# --------- public methods ---------
|
||||
def SetFont(self, font):
|
||||
"""Set the font for the label"""
|
||||
wxPanel.SetFont(self, font)
|
||||
wx.Panel.SetFont(self, font)
|
||||
self.SetLabel(self.label)
|
||||
self.Draw(wxClientDC(self))
|
||||
self.Draw(wx.ClientDC(self))
|
||||
|
||||
|
||||
def Rest(self):
|
||||
"""Stop the animation and return to frame 0"""
|
||||
self.Stop()
|
||||
self.current = 0
|
||||
self.Draw(wxClientDC(self))
|
||||
self.Draw(wx.ClientDC(self))
|
||||
|
||||
|
||||
def Reverse(self):
|
||||
@ -196,28 +187,29 @@ class Throbber(wxPanel):
|
||||
|
||||
def Running(self):
|
||||
"""Returns True if the animation is running"""
|
||||
return not self.event.isSet()
|
||||
return self.running
|
||||
|
||||
|
||||
def Start(self):
|
||||
"""Start the animation"""
|
||||
if not self.Running():
|
||||
self.event.clear()
|
||||
thread = threading.Thread(target = self.UpdateThread,
|
||||
name = "%s-thread" % self.name)
|
||||
thread.start()
|
||||
if not self.running:
|
||||
self.running = not self.running
|
||||
self.timer.Start(self.frameDelay * 1000)
|
||||
|
||||
|
||||
def Stop(self):
|
||||
"""Stop the animation"""
|
||||
if self.event.isSet():
|
||||
return
|
||||
self.event.set()
|
||||
if self.running:
|
||||
self.timer.Stop()
|
||||
self.running = not self.running
|
||||
|
||||
|
||||
def SetFrameDelay(self, frameDelay = 0.05):
|
||||
"""Delay between each frame"""
|
||||
self.frameDelay = frameDelay
|
||||
if self.running:
|
||||
self.Stop()
|
||||
self.Start()
|
||||
|
||||
|
||||
def ToggleOverlay(self, state = None):
|
||||
@ -226,7 +218,7 @@ class Throbber(wxPanel):
|
||||
self.showOverlay = not self.showOverlay
|
||||
else:
|
||||
self.showOverlay = state
|
||||
self.Draw(wxClientDC(self))
|
||||
self.Draw(wx.ClientDC(self))
|
||||
|
||||
|
||||
def ToggleLabel(self, state = None):
|
||||
@ -235,7 +227,7 @@ class Throbber(wxPanel):
|
||||
self.showLabel = not self.showLabel
|
||||
else:
|
||||
self.showLabel = state
|
||||
self.Draw(wxClientDC(self))
|
||||
self.Draw(wx.ClientDC(self))
|
||||
|
||||
|
||||
def SetLabel(self, label):
|
||||
@ -245,7 +237,7 @@ class Throbber(wxPanel):
|
||||
extentX, extentY = self.GetTextExtent(label)
|
||||
self.labelX = (self.width - extentX)/2
|
||||
self.labelY = (self.height - extentY)/2
|
||||
self.Draw(wxClientDC(self))
|
||||
self.Draw(wx.ClientDC(self))
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user