Relayout of wx.BoxSizer if child resizes

898 Views Asked by At

If the size of a children in a wx.BoxSizer changes the boxsizer is not relayouted:

import wx

class MyButton(wx.Button):
    def __init__(self, parent):
        wx.Button.__init__(self, parent, -1, style=wx.SUNKEN_BORDER, label="ABC")
        self.Bind(wx.EVT_BUTTON, self.OnClick)

    def OnClick(self, event):
        self.SetSize((200, 200))
        self.SetSizeHints(200, 200)

class MyFrame(wx.Frame):
    def __init__(self, parent, ID, title):
       wx.Frame.__init__(self, parent, ID, title, size=(300, 250))

       self.button = MyButton(self)
       button2 = wx.Button(self, -1, style=wx.SUNKEN_BORDER, label="DEF")

       # self.button.Bind(wx.EVT_SIZE, self.OnButtonResize)

       box = wx.BoxSizer(wx.HORIZONTAL)
       box.Add(self.button, 1, wx.EXPAND)
       box.Add(button2, 1, wx.EXPAND)

       self.SetAutoLayout(True)
       self.SetSizer(box)
       self.Layout()

    def OnButtonResize(self, event):
        event.Skip()
        self.Layout()

app = wx.App()
frame = MyFrame(None, -1, "Sizer Test")
frame.Show()
app.MainLoop()

After the click on the left button his size changes, but layout is broken. After resizeing child

If a manually relayout on a resize of the button (comment line), than a get a endless recursion.

In my real use case I can't change MyButton and MyButton is a wx.Panel which changes on an event I can't trigger on.

2

There are 2 best solutions below

0
On BEST ANSWER

I found a own solution. If you check for size changes in the event callback before doing the relayout, you don't get a endless recursion:

class MyFrame(wx.Frame):
    def __init__(self, parent, ID, title):
       wx.Frame.__init__(self, parent, ID, title, size=(300, 250))

       self.button = MyButton(self)
       button2 = wx.Button(self, -1, style=wx.SUNKEN_BORDER, label="DEF")

       self.button.Bind(wx.EVT_SIZE, self.OnButtonResize)

       box = wx.BoxSizer(wx.HORIZONTAL)
       box.Add(self.button, 1, wx.EXPAND)
       box.Add(button2, 1, wx.EXPAND)

       self.buttonSize = None
       self.SetSizer(box)
       self.Layout()

    def OnButtonResize(self, event):
        event.Skip()

        if self.buttonSize != event.Size:
            self.buttonSize = event.Size
            self.Layout()
0
On

It is not part of the wx.Sizer design for size changes to automatically flow up the containment hierarchy for redoing the layout. Instead you need to trigger the relayout yourself. This is because there may be multiple changes happening and only you know when it is a good time to do it. If it was automated then it would be too easy to fall into a situation where one resize causes another resize which causes another which causes the first one to resize again.

So Sizers are instead designed to do top-down layout management (for example, a frame resize causes position or resize of children of the frame,) and when there is a situation where a bottom-up change needs to happen then the programmer needs to help it in some way. In your example you can just add the following line to the OnClick method:

self.GetContainingSizer().Layout()

For more complex layouts then something else may be required.