AGW Logo

Source code for pybusyinfo

"""
L{PyBusyInfo} constructs a busy info window and displays a message in it.


Description
===========

L{PyBusyInfo} constructs a busy info window and displays a message in it.

This class makes it easy to tell your user that the program is temporarily busy.
Just create a L{PyBusyInfo} object, and within the current scope, a message window
will be shown.

For example::

    busy = PyBusyInfo("Please wait, working...")

    for i in xrange(10000):
        DoACalculation()

    del busy


It works by creating a window in the constructor, and deleting it in the destructor.
You may also want to call `wx.Yield()` to refresh the window periodically (in case
it had been obscured by other windows, for example).


Usage
=====

Usage example::

    import wx    
    import wx.lib.agw.pybusyinfo as PBI

    class MyFrame(wx.Frame):

        def __init__(self, parent):
        
            wx.Frame.__init__(self, parent, -1, "PyBusyInfo Demo")

            panel = wx.Panel(self)
    
            b = wx.Button(panel, -1, "Test PyBusyInfo ", (50,50))
            self.Bind(wx.EVT_BUTTON, self.OnButton, b)


        def OnButton(self, event):
            
            message = "Please wait 5 seconds, working..."
            busy = PBI.PyBusyInfo(message, parent=self, title="Really Busy")

            wx.Yield()
            
            for indx in xrange(5):
                wx.MilliSleep(1000)

            del busy


    # our normal wxApp-derived class, as usual

    app = wx.PySimpleApp()

    frame = MyFrame(None)
    app.SetTopWindow(frame)
    frame.Show()

    app.MainLoop()



Supported Platforms
===================

L{PyBusyInfo} has been tested on the following platforms:
  * Windows (Windows XP).


Window Styles
=============

`No particular window styles are available for this class.`


Events Processing
=================

`No custom events are available for this class.`


License And Version
===================

L{PyBusyInfo} is distributed under the wxPython license.

Latest Revision: Andrea Gavana @ 17 Aug 2011, 15.00 GMT

Version 0.1

"""


import wx

_ = wx.GetTranslation


[docs]class PyInfoFrame(wx.Frame): """ Base class for L{PyBusyInfo}. """
[docs] def __init__(self, parent, message, title, icon): """ Default class constructor. :param `parent`: the frame parent; :param `message`: the message to display in the L{PyBusyInfo}; :param `title`: the main L{PyBusyInfo} title; :param `icon`: an icon to draw as the frame icon, an instance of `wx.Bitmap`. """ wx.Frame.__init__(self, parent, wx.ID_ANY, title, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER|wx.FRAME_TOOL_WINDOW|wx.FRAME_SHAPED|wx.STAY_ON_TOP) panel = wx.Panel(self) panel.SetCursor(wx.HOURGLASS_CURSOR) self._message = message self._title = title self._icon = icon dc = wx.ClientDC(self) textWidth, textHeight, dummy = dc.GetMultiLineTextExtent(self._message) sizeText = wx.Size(textWidth, textHeight) self.SetClientSize((max(sizeText.x, 340) + 60, max(sizeText.y, 40) + 60)) # need to size the panel correctly first so that text.Centre() works panel.SetSize(self.GetClientSize()) # Bind the events to draw ourselves panel.Bind(wx.EVT_PAINT, self.OnPaint) panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase) self.Centre(wx.BOTH) # Create a non-rectangular region to set the frame shape size = self.GetSize() bmp = wx.EmptyBitmap(size.x, size.y) dc = wx.BufferedDC(None, bmp) dc.SetBackground(wx.Brush(wx.Colour(0, 0, 0), wx.SOLID)) dc.Clear() dc.SetPen(wx.Pen(wx.Colour(0, 0, 0), 1)) dc.DrawRoundedRectangle(0, 0, size.x, size.y, 12) r = wx.RegionFromBitmapColour(bmp, wx.Colour(0, 0, 0)) # Store the non-rectangular region self.reg = r if wx.Platform == "__WXGTK__": self.Bind(wx.EVT_WINDOW_CREATE, self.SetBusyShape) else: self.SetBusyShape() # Add a custom bitmap at the top (if any)
[docs] def SetBusyShape(self, event=None): """ Sets L{PyInfoFrame} shape using the region created from the bitmap. :param `event`: a `wx.WindowCreateEvent` event (GTK only, as GTK supports setting the window shape only during window creation). """ self.SetShape(self.reg) if event: # GTK only event.Skip()
[docs] def OnPaint(self, event): """ Handles the ``wx.EVT_PAINT`` event for L{PyInfoFrame}. :param `event`: a `wx.PaintEvent` to be processed. """ panel = event.GetEventObject() dc = wx.BufferedPaintDC(panel) dc.Clear() # Fill the background with a gradient shading startColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION) endColour = wx.WHITE rect = panel.GetRect() dc.GradientFillLinear(rect, startColour, endColour, wx.SOUTH) # Draw the label font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) dc.SetFont(font) # Draw the message rect2 = wx.Rect(*rect) rect2.height += 20 dc.DrawLabel(self._message, rect2, alignment=wx.ALIGN_CENTER|wx.ALIGN_CENTER) # Draw the top title font.SetWeight(wx.BOLD) dc.SetFont(font) dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_CAPTIONTEXT))) dc.SetTextForeground(wx.SystemSettings_GetColour(wx.SYS_COLOUR_CAPTIONTEXT)) if self._icon.IsOk(): iconWidth, iconHeight = self._icon.GetWidth(), self._icon.GetHeight() dummy, textHeight = dc.GetTextExtent(self._title) textXPos, textYPos = iconWidth + 10, (iconHeight-textHeight)/2 dc.DrawBitmap(self._icon, 5, 5, True) else: textXPos, textYPos = 5, 0 dc.DrawText(self._title, textXPos, textYPos+5) dc.DrawLine(5, 25, rect.width-5, 25) size = self.GetSize() dc.SetPen(wx.Pen(startColour, 1)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawRoundedRectangle(0, 0, size.x, size.y-1, 12)
[docs] def OnErase(self, event): """ Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{PyInfoFrame}. :param `event`: a `wx.EraseEvent` event to be processed. :note: This method is intentionally empty to reduce flicker. """ # This is empty on purpose, to avoid flickering pass # -------------------------------------------------------------------- # # The actual PyBusyInfo implementation # -------------------------------------------------------------------- #
[docs]class PyBusyInfo(object): """ Constructs a busy info window as child of parent and displays a message in it. """
[docs] def __init__(self, message, parent=None, title=_("Busy"), icon=wx.NullBitmap): """ Default class constructor. :param `parent`: the L{PyBusyInfo} parent; :param `message`: the message to display in the L{PyBusyInfo}; :param `title`: the main L{PyBusyInfo} title; :param `icon`: an icon to draw as the frame icon, an instance of `wx.Bitmap`. :note: If `parent` is not ``None`` you must ensure that it is not closed while the busy info is shown. """ self._infoFrame = PyInfoFrame(parent, message, title, icon) if parent and parent.HasFlag(wx.STAY_ON_TOP): # we must have this flag to be in front of our parent if it has it self._infoFrame.SetWindowStyleFlag(wx.STAY_ON_TOP) self._infoFrame.Show(True) self._infoFrame.Refresh() self._infoFrame.Update()
def __del__(self): """ Overloaded method, for compatibility with wxWidgets. """ self._infoFrame.Show(False) self._infoFrame.Destroy()