Search code examples
pythongridwxpythonpanelsizer

wxpython Gridsizer not fitting to panel


I am working on a wxpython GUI. I have three panels (two on the left split horizontally and one on the right split vertically from the other two -- think two squares on left half and tall rectangle on right half). I am trying to fit a Gridsizer in Panel 3 (P3 in image). I cannot seem to get the grid panels to "fill" the overall Panel 3. Instead they snap to the top and bottom. Ideally, i would like the 10 small panels (2 rows, 5 cols) to resize and fill the Panel 3 nicely (all the same size and big enough to see each). What am I doing wrong? Thanks!

**** EDIT **** I have changed my code to look like the following:

        sizer_31 = wx.BoxSizer(wx.VERTICAL)
        gs = wx.GridSizer(0,4,7,7)

        for i in self.Panel_Others.keys():
            gs.Add(self.Panel_Others[i],0,wx.ALIGN_CENTER|wx.ALL,5)

        sizer_31.Add(gs,0,wx.ALIGN_CENTER|wx.ALL,5)
        self.OtherTeams.SetSizer(sizer_31)
        sizer_31.SetSizeHints(self.OtherTeams)

And my New Panel 3 looks like the picture below. This is some improvement. However, I want the individual panels (10 in all) to expand the same amount so that the entire notebook page is covered in equal size smaller panels (Imagine what a Calendar looks like and each day is a panel).

enter image description here

**** END EDIT ****

Below is my original code:

Note: self.OtherTeams is the wx.Notebook Page under self.Panel3. self.Panel_Others is a dictionary containing the wx.Panels I'm displaying (this changes dynamically so this is why i have a dictionary of them rather than specifying them).

        sizer_31 = wx.BoxSizer(wx.HORIZONTAL)
        gs = wx.GridSizer(2,5,5,5)

        for i in self.Panel_Others.keys():
            sizer_temp = wx.BoxSizer(wx.VERTICAL)
            sizer_temp.Add(self.Panel_Others[i],1,wx.EXPAND)
            gs.Add(sizer_temp,1,wx.EXPAND,0)

        sizer_31.Add(gs,0,wx.EXPAND)
        self.OtherTeams.SetSizer(sizer_31)

enter image description here


Solution

  • In wxPython 2.8 this would result in a single blur at the top left corner of the page. wxPython 2.9 is a bit smarter when it comes to sizers which is why it appears to work somewhat.

    Firstly, you create a GridSizer within a BoxSizer but you do not allow it to expand dynamically (wx.EXPAND). And secondly, you're setting the sizer to the wx.Notebook instead of the page (panel) which would shift the entire layout down and crop the bottom row of controls/panels in the grid sizer, or would be ignored entirely in 2.8 thus moving everything to the top left corner.

    This should do the trick:

    sizer_31 = wx.BoxSizer(wx.VERTICAL) # page (panel) sizer for outer border
    gs = wx.GridSizer(0,4,7,7) # content sizer
    
    for i in self.Panel_Others.keys():
        gs.Add(self.Panel_Others[i],0,wx.EXPAND|wx.ALL,5) 
        # + wx.EXPAND: allow the content to fill the 'cells'
        #              (proportion is ignored here so it can be 0)
    sizer_31.Add(gs,1,wx.EXPAND|wx.ALL,5) 
    # + 1, wx.EXPAND: allow the grid to expand to the main sizer
    #                 which in turn fits to the page
    self.Panel3.SetSizer(sizer_31) # set the sizer to page, not the notebook
    

    EDIT: The following example demonstrates how to dynamically update the contents of a wx.GridSizer in a wx.Notebook page:

    import wx
    
    class MyFrame(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(self, None, title='wx.Notebook')
            # create a wx.Notebook
            book = wx.Notebook(self)
            # create a new page; wx.Notebook owns the page
            # therefore the notebook must be the parent window
            page = MyPage(parent=book)
            # add the page to the notebook:
            book.AddPage(page, 'Page 1')
            book.AddPage(MyPage(book),'Page 2')
            book.AddPage(MyPage(book),'Page 3')
    
    class MyPage(wx.Panel):
        "a page for wx.Notebook"
        def __init__(self, parent):
            # NOTE: wxPython 2.9.4/winXP may create graphic 
            # artifacts when more than one page is added. This can
            # be avoided by creating the page with a size of (0,0).
            # the reason for this is: the page (here a panel) is
            # created with the default size and position (upper
            # left corner). Once the layout is applied, the page
            # is moved to the proper coordinates. However, the
            # wx.Notebook is not redrawn so it will leave a black
            # spot where the page was moved away from. Alternatively,
            # the frame or notebook can be Refresh()ed after the
            # frame is shown.
            wx.Panel.__init__(self, parent, size=(0,0))
            # create sizer to add a border
            pageSizer = wx.BoxSizer(wx.VERTICAL)
            # create a grid sizer for the content
            self.grid = wx.GridSizer(0, 4, 5, 5)
            # add the grid sizer to the page sizer:
            # to allow the grid to fill the entire page,
            # set proportion>0 and add the wx.EXPAND flag.
            # the border of 10 is the spacing between the
            # page and the cells of the grid
            pageSizer.Add(self.grid, 1, wx.EXPAND|wx.ALL, 10)
            # set the main sizer:
            self.SetSizer(pageSizer)
            # add content to the grid
            self.GenerateContent()
            # DEMO: click any white space on the page to 
            # generate new content
            self.Bind(wx.EVT_LEFT_DOWN, self.GenerateContent)
    
        def GenerateContent(self, event=None):
            "dynamically create page content"
            # remove all items from the grid and destroy them
            # NOTE: if you don't actually create new controls here,
            # but use a list of controls created elsewhere (like in
            # in your code), do not delete the items! Use:
            # deleteWindows=False instead.
            self.grid.Clear(deleteWindows=True)
            # generate new grid content
            for i in range(10):
                # the contents are owned by the page,
                # therefore the page must be the parent window:
                # NOTE: size=(0,0) here is not required but
                # eliminates a briefly shown graphic artifact
                cell = wx.Panel(self, size=(0,0))
                cell.SetBackgroundColour(self.NewColor())
                # add the content (cells) to the grid:
                # specify the wx.EXPAND flag to fit the
                # content to the grid cell
                self.grid.Add(cell, flag=wx.EXPAND)
            # DEMO: hint text
            self.grid.Add(wx.StaticText(self, label=
                'Click empty cell to update content ->'),
                          flag=wx.EXPAND)
            # recalculate the layout to move the new contents
            # of the grid sizer into place
            self.Layout()
    
        col = 0 # DEMO: coloring
        def NewColor(self):
            self.col = (self.col + 3) % 241
            return wx.Colour(0, self.col * 10 % 255, self.col % 255)
    
    app = wx.App(False)
    MyFrame().Show()
    app.MainLoop()