Virgil Stokes | 8 Feb 23:37
Picon
Picon
Favicon
Gravatar

Some code that could be helpful in using wx.Overlay

With the help of Tim Roberts I have prepared some code that I hope will 
be useful for those of you who would like to know more about wx.Overlay. 
The code contains many comments which IMHO can be helpful when working 
with wx.Overlay.

--V

-- 
To unsubscribe, send email to wxPython-users+unsubscribe <at> googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en
'''
Purpose: to show how wx.Overlay() can be used to draw an object then erase it 
         (recover the bitmap before the object was drawn on it).

  This code snippet can be quite useful for the development of a more complex
  interactive drawing package.

 Notes:
  1. wx.ClientDC --- draws to window (frame) object, the interior (client part)
  2. wx.PaintDC  --- similiar to wx.ClientDC, but only used when processing a 
                     wx.PaintEvent
  3. Code is heavily commented for my own purposes.                   
  4. Code has been tested with Python 2.6.6, wxPython 2.8.12.1 on both a Windows
     Vista and 7 platform. No anomalies have been observed.
  5. TESTMODE = True, will "print" additional information for test purposes.   
  
  Creator: V. Stokes (vs <at> it.uu.se)
  Version: 2012.02.08.02
'''

import wx
import sys
print 'Python version: %s\n' %sys.version
print 'wxPython version: %s\n' %wx.version()

TESTMODE = False
TESTMODE = True

class TestPanel(wx.Panel):
    # # Define my own subclass for wx.Panel
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)        
        
        # wx.EVT_PAINT will occur when the window (panel) being used for
        #  drawing must be redrawn (see comments in self.OnPaint for details)
        self.Bind(wx.EVT_PAINT, self.onPaint)
        # wx.EVT_MOTION will occur when the mouse is moved
        self.Bind(wx.EVT_MOTION, self.onMouseMove)       
        # To save previous cell (rectangle) that mouse was over        
        self.oldCell = None  
        # Define the location of two rectangles
        self.rect1 = wx.Rect(50,60,200,250) 
        self.rect2 = wx.Rect(250,60,200,250)
        # Create an instance of wx.Overlay (to handle Overlay processing)
        self.overlay = wx.Overlay()
       
        if TESTMODE:
            self.OnPaintCounter = 0 
            self.recoverCounter = 0

    def onPaint(self, evt):
        
        if TESTMODE:
            self.OnPaintCounter += 1
            print 'Enter OnPaint -- %3d' %self.OnPaintCounter        
        ## Draw/redraw static objects when wx.EVT_PAINT event fires 
        # Put some polygons on a sky blue background
        dc = wx.PaintDC(self)        # create a context for drawing        
        dc.SetBackground(wx.Brush("sky blue")) # set BG
        dc.Clear()                   # blits BG to screen 
         
        dc.SetPen(wx.Pen("red", 1))
        dc.SetBrush(wx.CYAN_BRUSH)
        coords = ((40,40),(200,220),(210,120),(120,300))
        dc.DrawPolygon(coords)
      
        dc.SetPen(wx.Pen("white", 2))
        dc.SetBrush(wx.RED_BRUSH)
        coords = ((10,50),(100,200),(210,30),(120,280))
        dc.DrawPolygon(coords)

        # Draw two adjacent cells -- rectangles (only their edges)
        dc.SetPen(wx.Pen("black", 2))
        dc.SetBrush(wx.TRANSPARENT_BRUSH)        
        dc.DrawRectangleRect(self.rect1) 
        dc.SetPen(wx.Pen("green", 2))
        dc.DrawRectangleRect(self.rect2)
        
        # The first time wx.DCOverlay is called or after a self.Overlay.Reset(),
        #  the current screen is mapped to the Overlay. After this 
        #  initialization call it will map the Overlay to the screen. 
        dc = wx.ClientDC(self)
        # Map dc to odc and Overlay  -- first execution 
        odc = wx.DCOverlay(self.overlay, dc)
        # Blit bitmap in odc to the screen and clear it in odc
        odc.Clear()         
              
    def onMouseMove(self, evt): 
        '''
          Purpose: track the movement of the mouse
        '''
        def recoverBitMap(dc):
            '''
              Purpose: recover what was placed in the Overlay bitmap
                       since its last initialization. 
                       [note it's paired with wx.DCOverlay(self.overlay, dc]                       
            '''
            if TESTMODE:
                self.recoverCounter += 1
                print 'Forced recovery of screen -- %3d' %self.recoverCounter            
            # Map Overlay to odc ---  when not the first call
            odc = wx.DCOverlay(self.overlay, dc)
            # Blit bitmap in odc to the screen and clear it in odc
            odc.Clear()            
            # Note, self.overlay.Reset() clears whatever is in Overlay 
            #  and reinitializes so that the next call to wx.DCOverlay 
            #  will be treated as the first call. See comments in OnPaint.
            #self.overlay.Reset()
        
        ## Process the position of the mouse wrt cells
        cell = None  
        # Get mouse coordinates (referenced to this frame (panel))          
        pt = evt.GetPosition()                   
        if self.rect1.Inside(pt): 
            cell = self.rect1
        if self.rect2.Inside(pt): 
            cell = self.rect2              
        # Either have not entered a cell yet --- cell = None
        #  or, in the same cell              --- cell = oldCell,
        #  or, in a new cell 
        if cell == self.oldCell: return# same cell or have not entered a cell
                
        # New cell has been entered        
        dc = wx.ClientDC(self)        
        if self.oldCell:    
            # Moved from inside another cell
            recoverBitMap(dc)  # recover orginal (as defined in onPaint)
            
        # Highlight the new cell (edges only) just entered       
        dc.SetPen(wx.Pen("red", 4))
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
        dc.DrawRectangleRect(cell) 
        self.oldCell = cell      
        
class MyApp(wx.App):
    # Define my own subclass for wx.App
    def OnInit(self):       
        # The frame (container for the panel) is extremely simple 
        #  and thus a subclass of wx.Frame is not defined
        frame = wx.Frame(None, title="wx.Overlay Test", size=(600,450))
        # Create my own panel (subclass of frame)
        panel = TestPanel(frame)
        # Display what is in the frame -- when app.MainLoop() executes
        frame.Show(True)
        #self.SetTopWindow(frame)
        return True
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Every wxPython program must have one application object and one or more 
#  frame objects!
if __name__ == '__main__':
    # Initialize 
    app = MyApp(False) # the False is important!
    # Display frame and start looking for "events" (e.g wx.EVT_PAINT, 
    # wx.EVT_MOTION) 
    app.MainLoop() 

Gmane