Search code examples
pythongridwxpythonwxwidgets

Placing two wx Grids side by side


I am using python 2.7 and the latest version of wxpython.

I need to place 2 grids side by side and to be able to add rows dynamically. Ideally, the sizes of grids should grow dynamically, but "big enough" size should be ok for the time being.

How should I change (and simplify) my code to make this happen?

class MatricesFrame(wx.BoxSizer):        
    def __init__(self, parentPanel):
        super(MatricesFrame, self).__init__(wx.HORIZONTAL)

        self.outputsMatrix = self.addEmptyGrid(parentPanel)
        self.inputsMatrix = self.addEmptyGrid(parentPanel)

        addRowsButton = wx.Button(parentPanel, -1, " Add Rows")
        addRowsButton.Bind(wx.EVT_BUTTON, self.addRows)
        self.Add(addRowsButton)

    def initResize(self, ev = None):
        self.inputsMatrix.SetSize((500, 500)) 
        self.outputsMatrix.SetSize((500, 500)) 

    def addEmptyGrid(self, parentPanel):   
        panel_ = wx.Panel(parentPanel)
        sizer_ = wx.BoxSizer(wx.VERTICAL)
        panel_.SetSizer(sizer_)
        panel_.SetSize((500, 500)) 
        matrix_ = wx.grid.Grid(panel_)
        matrix_.SetRowLabelSize(0) 
        matrix_.SetColLabelSize(0) 
        matrix_.CreateGrid(1,1)
        sizer_.Add(matrix_)
        self.Add(panel_)
        return matrix_

    def addRows(self, ev=None):   
        self.inputsMatrix.AppendRows(1)
        self.outputsMatrix.AppendRows(1)

class TestFrame(wx.Frame):
    def __init__(self, parent):
        super(TestFrame, self).__init__(parent, title='test', size=(1280, 950))               
        panel = wx.Panel(self)
        box = wx.BoxSizer(wx.VERTICAL)
        self.matricesFrame = MatricesFrame(panel)      
        box.Add(self.matricesFrame)
        panel.SetSizer(box)
        self.matricesFrame.initResize()
        self.Centre()
        self.Show()
        self.matricesFrame.initResize()
        wx.EVT_IDLE(wx.GetApp(),  wx.WakeUpIdle())           

def main():
    app = wx.App(False)
    t= TestFrame(None)
    app.MainLoop()

if __name__ == '__main__':
    main()

Solution

  • For starters, if you convert your custom Sizer into a custom Panel I think it makes your code a lot easier to control. Take a look at what I came up with

    class MatricesPanel(wx.Panel):        
        def __init__(self, parent):
            super(MatricesPanel, self).__init__(parent)
    
            sizer = wx.BoxSizer(wx.HORIZONTAL)
    
            self.outputsMatrix = self.addEmptyGrid(sizer)
            self.inputsMatrix = self.addEmptyGrid(sizer)
    
            addRowsButton = wx.Button(self, -1, " Add Rows")
            addRowsButton.Bind(wx.EVT_BUTTON, self.addRows)
            sizer.Add(addRowsButton)
    
            self.SetSizer(sizer)
            self.SetAutoLayout(True)
            self.Layout()
    
        def initResize(self, ev = None):
            self.inputsMatrix.SetSize((500, 500)) 
            self.outputsMatrix.SetSize((500, 500))
            self.Layout()
    
        def addEmptyGrid(self, sizer):   
            matrix_ = wx.grid.Grid(self)
            matrix_.SetRowLabelSize(0) 
            matrix_.SetColLabelSize(0) 
            matrix_.CreateGrid(1,1)
            sizer.Add(matrix_)
            return matrix_
    
        def addRows(self, ev=None):   
            self.inputsMatrix.AppendRows(1)
            self.outputsMatrix.AppendRows(1)
            self.Layout() #refresh the frame
    

    Working with a Panel instead of a Sizer you greatly simplify your "addEmptyGrid" method as well as now you can try setting the size of your matricies using the size of the panel, not the size of the matrices themselves. Also, this allows you the flexibility to change from wx.Panel to wx.lib.scrolledpanel.ScrolledPanel if you wanted to add scroll bars (for if you add a lot of rows).

    You can then init your new panel as below:

    class TestFrame(wx.Frame):
        def __init__(self, parent):
            super(TestFrame, self).__init__(parent, title='test', size=(1280, 950))
            self.matricesPanel = MatricesPanel(self)
    
            sizer = wx.BoxSizer()
            sizer.Add(self.matricesPanel, flag=wx.EXPAND)
            self.SetSizer(sizer)
    
            self.Centre()
            self.Show()
            self.matricesPanel.initResize()
    
            wx.EVT_IDLE(wx.GetApp(),  wx.WakeUpIdle())
    

    Finally, so far as I can tell, columns in a Grid have a fixed width, so your matrix.SetSize((500, 500)) calls arent' doing much. If you can find a way to set the width of the column then I suggest you rewrite initResize() to set the width relative to the width of the panel.