Replace an Existing layout with new layout with wx

2019-09-08 14:42发布

问题:

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?

回答1:

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.