I have a panel that is a list of buttons. The number of buttons changes during runtime (due to user action elsewhere). I use a wxWrapSizer
to manage these button since I want the height of this panel to remain the same and create a second column of buttons when it runs out of vertical space. The height is managed by the parent sizer based on the other widgets height. This almost works fine but the second column of buttons does not appear until after the window is manually resized.
I have created a minimal example to reproduce the issue:
import wx
start_buttons = 5
class ButtonsPanel(wx.Panel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.SetSizer(wx.WrapSizer(wx.VERTICAL))
for i in range(start_buttons):
self.add_button()
def add_button(self):
self.GetSizer().Add(wx.Button(self, label='foo'),
wx.SizerFlags().Expand())
class MyPanel(wx.Panel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# hardcoded size for sake of example only
add_button = wx.Button(self, label="add", size=(80, 250))
add_button.Bind(wx.EVT_BUTTON, self.OnAddButton)
self.buttons_panel = ButtonsPanel(self)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(add_button)
sizer.Add(self.buttons_panel, wx.SizerFlags().Expand())
self.SetSizer(sizer)
def OnAddButton(self, evt):
self.buttons_panel.add_button()
self.buttons_panel.Layout()
class MyFrame(wx.Frame):
def __init__(self, *args):
super().__init__(*args)
panel = MyPanel(self)
app = wx.App()
frame = MyFrame(None)
frame.Show()
app.MainLoop()
Clicking the large "Add" button will add new "foo" buttons but then it stops once it reaches the bottom of the frame. Manually resizing the frame will make the hidden second column appear.
Perform a Layout()
of the main panel's sizer rather than the buttons panel sizer.
As the buttons panel's sizer "lives" inside the main panel's sizer, this is the one that needs to be recalculated, as it will recalculate it's children.
def OnAddButton(self, evt):
self.buttons_panel.add_button()
#self.buttons_panel.Layout()
self.Layout()
Edit:
for more complex setups you may need to note the parent
or grandparent
and update from within the buttonpanel i.e.
import wx
start_buttons = 5
class ButtonsPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.SetSizer(wx.WrapSizer(wx.VERTICAL))
self.parent = parent
for i in range(start_buttons):
self.add_button()
def add_button(self):
self.GetSizer().Add(wx.Button(self, label='foo'),
wx.SizerFlags().Expand())
self.parent.Layout()
class MyPanel(wx.Panel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# hardcoded size for sake of example only
add_button = wx.Button(self, label="add", size=(80, 250))
add_button.Bind(wx.EVT_BUTTON, self.OnAddButton)
self.buttons_panel = ButtonsPanel(self)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(add_button)
sizer.Add(self.buttons_panel, wx.SizerFlags().Expand())
self.SetSizer(sizer)
def OnAddButton(self, evt):
self.buttons_panel.add_button()
#self.buttons_panel.Layout()
class MyFrame(wx.Frame):
def __init__(self, *args):
super().__init__(*args)
panel = MyPanel(self)
app = wx.App()
frame = MyFrame(None)
frame.Show()
app.MainLoop()
If it gets truly hellish, you could use pubsub
to fire a Layout
in the right place.