Search code examples
pythonubuntulayoutwxpython

Replace an Existing layout with new layout with wxPython


I am new to wxPython. I am making a layout with Gridbagsizer. I almost succeeded in making my desired layout. But for some unknown problem it is giving some problem.

My objective: I made 5 layouts. Green, Red, Blue, Yellow and Black. When I double-click on "This is test run", the yellow layout is supposed to be replaced by black layout completely.

What actually happens: Yellow gets replaced by black. No problem on that. But blue layouts position gets shifted to bottom for some reason.

My code goes like this:

import wx

class myframe(wx.Frame):
    def __init__(self):
        "Constructor. No arguments"
        wx.Frame.__init__(self, None, size=(1000,700))
        self.TitlePanel = wx.Panel( self, size=(350, 400) )
        self.newPanel = wx.Panel( self, size=(300, 250) )
        imgPanel = wx.Panel( self, size=(300, 250) )
        modulePanel=wx.Panel( self, size=(350, 250) )
        self.TCPanel=wx.Panel( self, size=(300, 250) )
        ############################################
        self.TitlePanel.SetBackgroundColour("green")
        imgPanel.SetBackgroundColour("red")
        modulePanel.SetBackgroundColour("blue")
        self.TCPanel.SetBackgroundColour("yellow")
        self.newPanel.SetBackgroundColour("black")
        self.newPanel.Hide()
        ############################################        
        self.myGridSizer = wx.GridBagSizer(1,1)
        self.myGridSizer.Add(self.TitlePanel, pos=(0, 0), span=(4,8), flag=wx.EXPAND)
        self.myGridSizer.Add(imgPanel, pos=(0, 10), span=(4,8), flag=wx.ALL)
        self.myGridSizer.Add(modulePanel, pos=(10, 0), span=(1,8), flag=wx.ALL)
        self.myGridSizer.Add(self.TCPanel, pos=(10, 10), span=(4,8), flag=wx.ALL)
        #############################################
        self.text1 = wx.StaticText(self.TitlePanel, label="This is a test run",style=2,size=(350,-1))
        font = wx.Font(18, wx.DECORATIVE, wx.ITALIC,wx.BOLD, wx.NORMAL)
        self.text1.SetFont(font)
        #############################################
        self.SetSizer(self.myGridSizer)
        self.text1.Bind(wx.EVT_LEFT_DCLICK, self.hideMe)
        imgPanel.Bind(wx.EVT_LEFT_DCLICK, self.showMe)
        self.myGridSizer.SetEmptyCellSize((0, 0))
    def hideMe(self, event):
        self.TCPanel.Hide()
        self.myGridSizer.Add(self.newPanel, pos=(5, 10), span=(4,8), flag=wx.ALL)
        self.newPanel.Show()
        self.Layout()
    def showMe(self, event):
        print "show!"
        self.newPanel.Hide()
        self.TCPanel.Show()
        self.Layout()

if __name__ == "__main__":
    app = wx.App()
    region = myframe()
    region.Show()
    app.MainLoop()

So, How can I replace a layout and keep existing layouts intact?


Solution

  • First you should correct how your text1 is being controlled with respect to it's position. If it is a child of TitlePanel, then you should use a new sizer for TitlePanel and put text1 inside. Your sizers should follow the parent-child hierarchy.

    Next, it is not enough to just Hide() and Show(), you have to replace the element in sizer correctly. Easiest way is to use sizer.Replace(old_widget, new_widget).

    import wx
    class myframe(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(self, None, size=(1000,700))
    
            self.TitlePanel = wx.Panel(self, size=(350, 400))
            self.TitlePanel.SetBackgroundColour("green")
    
            self.newPanel = wx.Panel(self, size=(300, 250))
            self.newPanel.SetBackgroundColour("black")
            self.newPanel.Hide()
    
            self.imgPanel = wx.Panel(self, size=(300, 250))
            self.imgPanel.SetBackgroundColour("red")
    
            self.modulePanel=wx.Panel(self, size=(350, 250))
            self.modulePanel.SetBackgroundColour("blue")
    
            self.TCPanel=wx.Panel(self, size=(300, 250))
            self.TCPanel.SetBackgroundColour("yellow")
    
            self.myGridSizer = wx.GridBagSizer(1,1)
            self.myGridSizer.SetEmptyCellSize((0, 0))
            self.myGridSizer.Add(self.TitlePanel, pos=(0, 0), span=(4,8), flag=wx.EXPAND)
            self.myGridSizer.Add(self.imgPanel, pos=(0, 10), span=(4,8), flag=wx.ALL)
            self.myGridSizer.Add(self.modulePanel, pos=(10, 0), span=(1,8), flag=wx.ALL)
            self.myGridSizer.Add(self.TCPanel, pos=(10, 10), span=(4,8), flag=wx.ALL)
    
            self.text1 = wx.StaticText(self.TitlePanel, label="This is a test run",style=2,size=(350,-1))
            font = wx.Font(18, wx.DECORATIVE, wx.ITALIC,wx.BOLD, wx.NORMAL)
            self.text1.SetFont(font)
    
            self.titleSizer = wx.BoxSizer()
            self.titleSizer.Add(self.text1, flag=wx.TOP|wx.LEFT|wx.ALIGN_RIGHT,border=10)
            self.TitlePanel.SetSizer(self.titleSizer)
    
            self.SetSizer(self.myGridSizer)
    
            self.text1.Bind(wx.EVT_LEFT_DCLICK, self.hideMe)
            self.imgPanel.Bind(wx.EVT_LEFT_DCLICK, self.showMe)
    
    
        def hideMe(self, event):
            self.TCPanel.Hide()
            self.myGridSizer.Replace(self.TCPanel, self.newPanel)
            self.newPanel.Show()
            self.Layout()
    
        def showMe(self, event):
            self.newPanel.Hide()
            self.myGridSizer.Replace(self.newPanel, self.TCPanel)
            self.TCPanel.Show()
            self.Layout()
    
    if __name__ == "__main__":
        app = wx.App()
        region = myframe()
        region.Show()
        app.MainLoop()
    

    Also a few notes regarding your code:

    1. Do not surround brackets with spaces. It is ugly and against general Python style.
    2. Do not mix local variables with object attributes for widgets. Use one way and stick to it, preferably use object attributes. This way you will have access to your widgets in all methods.
    3. It is usually more readable to group widget creation with attribute setting etc. It was really hard to find which panel is which color in your code.