pythonwxpythonhidesizer

wxPython: Hide a widget and remove the leftover space


I want to hide a widget in a sizer and not leave an empty space. I do not want to remove the widget, because I want to show it again later.

Is there a way to hide a widget and have the shown widgets after it move over one space to fill the empty spot?

Here is a simple example of a space being left:

import wx

class MyPanel(wx.Panel):
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)

        sizer = wx.GridSizer(1, 3, 0, 0)

        a = wx.Button(self, -1, 'a')
        b = wx.Button(self, -1, 'b')
        c = wx.Button(self, -1, 'c')

        sizer.Add(a, 0, 0, 0)
        sizer.Add(b, 0, 0, 0)
        sizer.Add(c, 0, 0, 0)

        b.Hide()

        self.SetSizer(sizer)

class MyFrame(wx.Frame):
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="Remove Spaces")
        panel = MyPanel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(panel, 1, wx.EXPAND)
        self.SetSizer(sizer)
        self.Fit()
        self.Show()

if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

Solution

  • Do you have to use wx.GridSizer? Because it will give you a fixed layout, so even you hide a control the grid will still have that space displayed.

    Have you considered using wx.GridBagSizer? Try this one:

    class MyPanel(wx.Panel):
        def __init__(self, parent):
            """Constructor"""
            wx.Panel.__init__(self, parent)
            self.parent = parent
    
            self.sizer = wx.GridBagSizer()
    
            self.a = wx.Button(self, -1, 'a')
            self.b = wx.Button(self, -1, 'b')
            self.c = wx.Button(self, -1, 'c')
            self.a.Bind(wx.EVT_BUTTON, self.button_clicked)
    
            self.sizer.Add(self.a, pos=(0, 0))
            self.sizer.Add(self.b, pos=(0, 1))
            self.sizer.Add(self.c, pos=(0, 2))
    
            self.SetSizer(self.sizer)
    
        def button_clicked(self, event):
            if self.b.IsShown():
                self.b.Hide()
            else:
                self.b.Show()
            self.parent.Fit()
    

    Using FlexGridSizer:

    class MyPanel(wx.Panel):
        def __init__(self, parent):
            """Constructor"""
            wx.Panel.__init__(self, parent)
            self.parent = parent
    
            self.sizer = wx.FlexGridSizer(1, 3, 0, 0)
    
            self.a = wx.Button(self, -1, 'a')
            self.b = wx.Button(self, -1, 'b')
            self.c = wx.Button(self, -1, 'c')
            self.a.Bind(wx.EVT_BUTTON, self.button_clicked)
    
            self.sizer.Add(self.a)
            self.sizer.Add(self.b)
            self.sizer.Add(self.c)
    
            self.SetSizer(self.sizer)
    
        def button_clicked(self, event):
            if self.b.IsShown():
                self.b.Hide()
            else:
                self.b.Show()
            self.parent.Fit()