Resizing problem with GridBagLayout

Hi, I am struggling to get a custom widget containing a wx.Grid to resize correctly when used in a GridBagLayout.

image

I want column 0 of the grid to expand, and column 1 to stay the same size so I’m connecting to the EVT_SIZE on the custom widget and changing the column sizes. This works fine and when the frame is made larger the column grows as required.

However strangely, when the frame is shrunk the custom widget size allocation does not change and the second column just disappears off the window!

image

I’ve attached a much simplified version of the code which shows the problem. If I change the GridBagSizer to a vertical BoxSizer it works (but I can’t do that in the actual code).

broken.py (1.8 KB)

Any ideas? I had to confess I find layout in wx incredibly confusing and there seem to be no end of questions about how to do quite simple things like this. Interestingly it works if I replace my custom panel with a standard control, e.g. a wx.TextCtrl, so evidently it is possible.

Thanks for any help,
Martin

I think you are using SetColSize beyond the actual size of the Grid, which is causing SetColSize to panic-add some size to the Grid to make it possible. When you later SetColSize back down, then there is no panic, so no reverse action happens.

Probably something needs to be re-Layout-ed as the frame size changes.

It can be, that’s why I wrote wxWize. (Shameless plug, I know, but I do believe it makes this sort of issue much easier to troubleshoot, or better yet, avoid in the first place.)

It’s actually easier, for me anyway, to rewrite the whole thing with wxWize than it is to figure out what’s going wrong. So here’s sorta the same thing, rewritten with wxWize:

import wx.grid
import wize as iz

class Gui(wx.Frame):
    def __init__(self, parent):
        with iz.Frame(init=self, parent=parent, title="less broken", style=wx.DEFAULT_FRAME_STYLE):
            with iz.Panel(orient=wx.VERTICAL):
                with iz.Notebook(style=wx.BK_DEFAULT, proportion=1, flag=wx.EXPAND):
                    with iz.Page("tab"):
                        with iz.Panel(proportion=1) as self.Tab:
                            with iz.GridBagSizer(proportion=1, flag=wx.EXPAND) as gbz:
                                with iz.Grid(x=0, y=0, proportion=1) as self.grid:
                                    pass
                                self.grid.CreateGrid(2,2)
                                self.grid.SetRowLabelSize(0)
                                self.grid.SetColLabelSize(0)
                            gbz.AddGrowableCol(0)
    
        self.Bind(wx.EVT_SIZE, self._resize_cols)
        self.Layout()

    def _resize_cols(self, event):
        self.Layout()
        width, _height = self.Tab.GetClientSize()
        width0 = 50
        width1 = max(50, width - width0)
        self.grid.SetColSize(0, width1)
        self.grid.SetColSize(1, width0)

app = wx.App()
fr = Gui(None)
fr.Show()
app.MainLoop()

Added a .Layout(), made sure width didn’t become negative, and moved the EVT_SIZE to the frame. There’s still issues, but the column sizing seems to work on frame resize at least, so maybe you can work from that.

1 Like

Thanks - I tried some of your ideas, the max() to prevent -ve widths is a good point, but didn’t solve the problem. Your second idea - moving the EVT_SIZE to a parent window instead of the custom widget itself - sorted it however. I put it in the tab window rather than the frame. Still no idea why the size event on the panel doesn’t handle shrinking and would be interested in a solution to that. But immediate problem solved, so thanks again!

Hi, Martin_Craig

Try to keep the ‘matryoshka’ panels simple. :slightly_smiling_face:

-       notebook.AddPage(Tab(notebook), "tab")
+       notebook.AddPage(Table(notebook), "tab")

Then, your code worked fine on my PC.

True, but this was just a simplified example. The real application needs to have a more complex layout on each tab.

Probably many of us have such or similar libraries.
I started my ‘ActiveControls’ wrapper in 1999 as I had problems getting the sizer layouts right and wanted to have event callbacks with more flexible arguments.
I’m still using this in the application that I started in the year 2000.
For anything else, I’m glad I can use wxGlade now and need not think about coding the layout. Being able to re-arrange things in a visual editor makes it easier to find a final, user friendly GUI.
For the event callbacks I can now use lambda functions if required…

Regards,
Dietmar

1 Like

Choosing the proper sizer mix right from the beginning is essential in GUI coding and, luckily, there are good tutorials available (I favour less is more :cowboy_hat_face:)

Yes, true again, but like I said this is a cut down version of the real application, which does indeed need a GridBagSizer, and I would still be interested in understanding why it does not work as I expected in this case - I’m sure there is a good reason but so far nobody seems to know!

Thanks for the wxGlade pointer - I will look into this. I used glade a long time ago with GTK but wasn’t aware that there was a wx port.

By using the GridBagSizer an additional degree of size enters the stage: AddGrowableCol and thus for resizing the grid you may have to use GetColWidths instead of client size :roll_eyes:

Hi Martin,
why don’t use wx.FlexGridSizer ?
broken.py (2.2 KB)

oh, I forgot the coding…

not_broken.py (1.8 KB)

wxGlade is not a port. Except name and icons I think they have nothing in common.
Usually, the master branch in the git repository should be fine to work with. The release version is a bit behind and has no undo/re-do yet.
A tutorial is included.

Place this in your event handler and you will see the root cause:

print( self, self.GetClientSize(), self.GetSize() )
print( self.Parent, self.Parent.GetClientSize(), self.Parent.GetSize() )

The quick fix:
width, _height = self.Parent.GetClientSize()

I don’t know whether this is a bug.

Your structure is very unusual and way too complex.
Just use Frame -> Notebook -> Panel -> GridBagSizer -> Grid

1 Like