I have been wrestling with this for two days now and getting nowhere. Something is broken, either the GridSizer control or me. I'm hoping it's me and someone can show me the problem. I've stripped my app of non-essentials. What I am building is a Sudoku app which consists of several nested controls, as can be seen in the atached image. The outer frame contains the puzzle which contains a 3x3 grid of panes. Each pane contains a 3x3 grid of tiles and each tile contains a 3x3 grid of digits.

So far so good. Except for the layout. I use RPAD and CPAD to determine on which edge of a control to apply a border. As you can see in the image, for some unknown reason the layout logic insists on adding the PANEBORDER between the 2nd and 3rd columns, and the 2nd and 3rd rows. Similarly, it screws up the TILEBORDER in the tile placements.

I've included wx.lib.inspection.InspectionTool().Show() so that you can see (if you try this locally) that the border values wx.TOP, etc. are assigned correctly, just not laid out correctly.

Is there anyone out there proficient enough in wxPython to offer a suggestion?

import wx
import wx.lib.mixins.inspection

RPAD = (wx.TOP , 0, wx.BOTTOM)
CPAD = (wx.LEFT, 0, wx.RIGHT)

PANEBORDER = 20
TILEBORDER =  5      

class App(wx.App):

    def OnInit(self):
        self.frame = Frame()
        self.frame.Position = (10,10)
        self.frame.Show()
        return True

class Frame(wx.Frame):

    def __init__(self):

        wx.Frame.__init__(self, None, title="Sudoku", style=wx.CLOSE_BOX | wx.CAPTION)

        self.SetBackgroundColour('white')    
        self.puzzle = Puzzle(self)

        bsizer = wx.BoxSizer(wx.HORIZONTAL)
        bsizer.Add(self.puzzle,0,wx.ALL,10)

        self.SetSizerAndFit(bsizer)

class Puzzle(wx.Panel):

    def __init__(self, parent):

        wx.Panel.__init__(self, parent, -1, style=wx.BORDER_DOUBLE)

        self.SetBackgroundColour('white')  

        gsizer = wx.GridSizer(cols=3, vgap=5, hgap=5)

        for row in (0,1,2):
            for col in (0,1,2):
                pane = Pane(self,'(%d,%d)' % (row,col))
                gsizer.Add(pane,0,RPAD[row] | CPAD[col], border=PANEBORDER)

        self.SetSizerAndFit(gsizer)

class Pane(wx.Panel):

    def __init__(self, parent, name):

        wx.Panel.__init__(self, parent, -1, name=name, style=wx.BORDER_DOUBLE)

        self.SetBackgroundColour('yellow')  

        gsizer = wx.GridSizer(cols=3, vgap=5, hgap=5)

        for row in (0,1,2):
            for col in (0,1,2):
                tile = Tile(self,'(%d,%d)' % (row,col))
                gsizer.Add(tile,0,RPAD[row] | CPAD[col], border=TILEBORDER)

        self.SetSizerAndFit(gsizer)

class Tile(wx.Panel):

    def __init__(self, parent, name):

        wx.Panel.__init__(self, parent, -1, name=name, style=wx.BORDER_DOUBLE)

        gsizer = wx.GridSizer(cols=3, vgap=0, hgap=0) 

        for i in range(1,10): 
            button = wx.Button(self,label = str(i), size=(24,24))
            button.name = str(i)
            gsizer.Add(button,0,0,0)      
        self.SetSizerAndFit(gsizer)  

if __name__ == '__main__':
    app = App(False) 
    wx.lib.inspection.InspectionTool().Show()
    app.MainLoop()

2019-07-12_102917.jpg