wxpython : changing background / foreground image dynamically
Question: I am writing a GUI flow using wxPython which has 4 pages (or more). They way I
have approached is creating 4 (or more) classes with each class defining its
own static (background) and dynamic images / content. In my application I
would then programmatically create instances class required and capture events
on that page. Based upon the event triggered the registered handler would
destroy current class and switch to other class(page). So my code actually
creates X classes with each class having its own method to set background /
foreground content/images:

    
    
    def OnEraseBackground(self, evt):
        dc = evt.GetDC()
    
        if not dc:
            dc = wx.ClientDC(self)
            rect = self.GetUpdateRegion().GetBox()
            dc.SetClippingRect(rect)
        dc.Clear()
        bmp = wx.Bitmap(self.image)
        dc.DrawBitmap(bmp, 0, 0)
    
    def buttonClick(self, evt):
        parent = self.frame
        self.Destroy()
        DispatchState(parent, "admin1.png", 1)
    

The issue is that the second page does not comes up at all in screen.

Below is my complete code. Note I have created 2 classes (MainPanel,
SecondPanel)that creates a screen on panel in my application frame. It then
waits for an event. Once I get the desired event I delete the current class
and create an instance of new class:

    
    
    import wx
    
    ########################################################################
    class SecondPanel(wx.Panel):
        def __init__(self,parent, image, state):
            wx.Panel.__init__(self, parent=parent)
        self.state = state
        self.image = image
            self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
            self.frame = parent
            sizer = wx.BoxSizer(wx.VERTICAL)
            hSizer = wx.BoxSizer(wx.HORIZONTAL)
        panel=wx.Panel(self, -1)
    
        self.buttonOne=wx.Image("image1.bmp", wx.BITMAP_TYPE_BMP).ConvertToBitmap()
        self.button=wx.BitmapButton(self, -1, self.buttonOne, pos=(100,50))
        self.button.Bind(wx.EVT_LEFT_DCLICK, self.buttonClick)
            sizer.Add(self.button, 0, wx.ALL, 5)
            hSizer.Add((1,1), 1, wx.EXPAND)
            hSizer.Add(sizer, 0, wx.TOP, 100)
            hSizer.Add((1,1), 0, wx.ALL, 75)
            self.SetSizer(hSizer)
            self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
    
        def buttonClick(self, evt):
        parent = self.frame
        self.Destroy()
        DispatchState(parent, "admin0.png", 0)
    
        def OnEraseBackground(self, evt):
        dc = evt.GetDC()
    
        if not dc:
            dc = wx.ClientDC(self)
            rect = self.GetUpdateRegion().GetBox()
            dc.SetClippingRect(rect)
        dc.Clear()
        bmp = wx.Bitmap(self.image)
        dc.DrawBitmap(bmp, 0, 0)
    
    class MainPanel(wx.Panel):
        def __init__(self,parent, image, state):
            wx.Panel.__init__(self, parent=parent)
        self.state = state
        self.image = image
            self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
            self.frame = parent
            sizer = wx.BoxSizer(wx.VERTICAL)
            hSizer = wx.BoxSizer(wx.HORIZONTAL)
        panel=wx.Panel(self, -1)
        self.buttonOne=wx.Image("image0.bmp", wx.BITMAP_TYPE_BMP).ConvertToBitmap()
        self.button=wx.BitmapButton(self, -1, self.buttonOne, pos=(100,50))
        self.button.Bind(wx.EVT_LEFT_DCLICK, self.buttonClick)
            sizer.Add(self.button, 0, wx.ALL, 5)
            hSizer.Add((1,1), 1, wx.EXPAND)
            hSizer.Add(sizer, 0, wx.TOP, 100)
            hSizer.Add((1,1), 0, wx.ALL, 75)
            self.SetSizer(hSizer)
            self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
    
        def buttonClick(self, evt):
        parent = self.frame
        self.Destroy()
        DispatchState(parent, "admin1.png", 1)
    
        def OnEraseBackground(self, evt):
        dc = evt.GetDC()
    
        if not dc:
            dc = wx.ClientDC(self)
            rect = self.GetUpdateRegion().GetBox()
            dc.SetClippingRect(rect)
        dc.Clear()
        bmp = wx.Bitmap(self.image)
        dc.DrawBitmap(bmp, 0, 0)
    
    
     class Main(wx.App):
        def __init__(self, redirect=False, filename=None):
            wx.App.__init__(self, redirect, filename)
            self.frame = wx.Frame(None, size=(800, 480))
            self.state = 0
            self.image = 'admin0.png'
    
    def DispatchState(frame, image, state):
            if state == 0 :
                print image
                print state
                MainPanel(frame, image, state)
            if state == 1 :
                print image
                print state
                SecondPanel(frame, image, state)
            frame.Show()
    
    
    if __name__ == "__main__":
        app = Main()
        DispatchState(app.frame,app.image, app.state)
        app.MainLoop()
    

The reason I have selected this approach is that I can easily switch from one
state to other such that I can switch to any screen / page. If suppose
tomorrow we need to dynamically add / remove more pages - it can be easily
done. I would need to create the page (class) and add its state in
DispatchState() global method.

But for me currently second screen does not gets rendered at all. Also please
comment on my approach - is there any better way I can achieve this - what are
the things I should take care or what is erroneous in my code?


Answer: Some solution.

I have to create `MyFrame` class to add **sizer** which resize _Panel_ to
_Frame_ size.

I add `DispatchState` as `ChangePanel` to `MyFrame` to make it more Object
oriented. Now _Panel_ call _Frame_ function `ChangePanel` and _Frame_
create/destroy panels.

Because `SecondPanel` and `MainPanel` are very similar I made one `MyPanel`
class - to have less work with removing my errors :) - see **DRY** rule:
[Don't Repeat Yourself](http://en.wikipedia.org/wiki/Don%27t_Repeat_Yourself)

(_I attache my bitmaps so other users can run this code too_)

(_I use ball1.png, ball2.png in place image0.bmp, image1.bmp_)

    
    
    import wx
    
    #######################################################################
    
    class MyPanel(wx.Panel):
    
        def __init__(self, parent, state, button_image, background_image):
            wx.Panel.__init__(self, parent=parent)
    
            print "(debug) MyPanel.__init__: state:", state
    
            self.parent = parent
            self.state  = state
    
            self.button_image = button_image
            self.background_image = background_image
    
    
            self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
    
            vsizer = wx.BoxSizer(wx.VERTICAL)
            hSizer = wx.BoxSizer(wx.HORIZONTAL)
    
            #self.buttonOne=wx.Image("image1.bmp", wx.BITMAP_TYPE_BMP).ConvertToBitmap()
            self.buttonImage = wx.Image(button_image, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
            self.button = wx.BitmapButton(self, -1, self.buttonImage, pos=(100,50))
    
            self.button.Bind(wx.EVT_LEFT_DCLICK, self.buttonClick)
    
            self.backgroundImage = wx.Bitmap(self.background_image)
    
            vsizer.Add(self.button, 0, wx.ALL, 5)
    
            hSizer.Add((1,1), 1, wx.EXPAND)
            hSizer.Add(vsizer, 0, wx.TOP, 100)
            hSizer.Add((1,1), 0, wx.ALL, 75)
    
            self.SetSizer(hSizer)
    
            self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
    
        def buttonClick(self, evt):
            print "(debug) MyPanel.buttonClick"
            self.parent.ChangePanel()
    
        def OnEraseBackground(self, evt):
            dc = evt.GetDC()
    
            if not dc:
                dc = wx.ClientDC(self)
                rect = self.GetUpdateRegion().GetBox()
                dc.SetClippingRect(rect)
            dc.Clear()
            dc.DrawBitmap(self.backgroundImage, 0, 0)
    
    #######################################################################
    
    class MyFrame(wx.Frame):
    
        def __init__(self, size=(800,480)):
            wx.Frame.__init__(self, None, size=size)
    
            self.state = None
            self.panel = None
    
            self.sizer = wx.BoxSizer(wx.VERTICAL)
            self.SetSizer(self.sizer)
    
            self.Show() # Show is used to show/hide window not to update content
    
            self.ChangePanel()
    
        #--------------------------
    
        def ChangePanel(self):
    
            print "(debug) MyFrame.ChangePanel: state:", self.state
    
            if self.state is None or self.state == 1:
                # change state
                self.state = 0 
    
                # destroy old panel
                if self.panel:
                    self.panel.Destroy()
    
                # create new panel
                self.panel = MyPanel(self, self.state, "ball1.png", "admin0.png")
    
                # add to sizer
                self.sizer.Add(self.panel, 1, wx.EXPAND)
            elif self.state == 0 :
                # change state
                self.state = 1 
    
                # destroy old panel
                if self.panel:
                    self.panel.Destroy()
    
                # create new panel
                self.panel = MyPanel(self, self.state, "ball2.png", "admin1.png")
    
                # add to sizer
                self.sizer.Add(self.panel, 1, wx.EXPAND)
            else:
                print "unkown state:", self.state
    
            self.Layout() # refresh window content
    
    #######################################################################
    
    class Application(wx.App):
    
        def __init__(self, redirect=False, filename=None):
            wx.App.__init__(self, redirect, filename)   
            self.frame = MyFrame((800, 480))
    
        def run(self):
            self.MainLoop()
    
    #######################################################################
    
    if __name__ == "__main__":
        Application().run()
    

ball1.png ![ball1.png](http://i.stack.imgur.com/mku2s.png) ball2.png
![ball2.png](http://i.stack.imgur.com/RG2E5.png)

admin0.png ![admin0.png](http://i.stack.imgur.com/6KAjD.png)

admin1.png ![admin1.png](http://i.stack.imgur.com/HGg6e.png)

