Search code examples
pythonwxpythonwxwidgets

Resize multiple items inside of a WxPython BoxSizer evenly?


I'm attempting to stack multiple widgets in a Horizontal BoxSizer. However, I'm getting a bit of unexpected behavior. Rather than the items in the Sizer resizing evenly, once a certain size is reached, the items will stop resizing along with the window.

This is best understood visually, I think. So, in gif form:

Current Behavior:

enter image description here

If you'll notice, the two TextCtrls resize in step with each other until about the half-way mark, at which point they both stop resizing and instead get "pushed" underneath the window.

Desired Behavior:

enter image description here

The desired Behavior is that, even at the smallest size, the two TextCtrlwould still be split evenly (The above was achieved via photoshop)

For just the two widgets shown, it's not really a huge issue, as the window can be resized smaller than any user ever would before the uneven TextCtrl issue ever pops up. However! In the actual application, I need to have anywhere from 3-5 of these (made of of various widget types) stacked next to each other. While two isn't an issue, adding more (especially when space and padding is added) quickly makes the problem more apparent.

enter image description here

Full Code:

import wx
from wx.lib.scrolledpanel import ScrolledPanel


class TestPanel(ScrolledPanel):
  def __init__(self, parent):
    ScrolledPanel.__init__(self, parent)
    self.SetupScrolling(scroll_x=False)

    self.textctrls = [wx.TextCtrl(self) for _ in range(4)]

    sizer = wx.BoxSizer(wx.VERTICAL)
    hsizer = wx.BoxSizer(wx.HORIZONTAL)
    for textctrl in self.textctrls:
      hsizer.Add(textctrl, 1, wx.EXPAND)

    sizer.Add(hsizer, 0, wx.EXPAND)
    self.SetSizer(sizer)

class MyFrame(wx.Frame):
  def __init__(self, parent):
    wx.Frame.__init__(self, parent, title="test", size=(320, 240))
    self.SetBackgroundColour('#ffffff')
    self.panel = TestPanel(self)
    self.Show()

if __name__ == '__main__':
  app = wx.App(False)
  MyFrame(None)
  app.MainLoop()

The code should be relatively straight forward. All the heavy listing is done in the ScrolledPanel subclass. I create the buttons, add each one to a Horizontal BoxSizer, and finally add the Horizontal sizer into a vertical container.

Could anyone identify why the widgets in the sizer are not resizing correctly?


Solution

  • set the textctrls minsize to zero so they can go smaller then their default minsize.

    import wx
    from wx.lib.scrolledpanel import ScrolledPanel
    
    
    class TestPanel(ScrolledPanel):
      def __init__(self, parent):
        ScrolledPanel.__init__(self, parent)
        self.SetupScrolling(scroll_x=False)
    
        self.textctrls = [wx.TextCtrl(self) for _ in range(4)]
    
        sizer = wx.BoxSizer(wx.VERTICAL)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        for textctrl in self.textctrls:
          hsizer.Add(textctrl, 1, wx.EXPAND)
          textctrl.SetMinSize((0, -1))
    
        sizer.Add(hsizer, 0, wx.EXPAND)
        self.SetSizer(sizer)
    
    class MyFrame(wx.Frame):
      def __init__(self, parent):
        wx.Frame.__init__(self, parent, title="test", size=(320, 240))
        self.SetBackgroundColour('#ffffff')
        self.panel = TestPanel(self)
        self.Show()
    
    if __name__ == '__main__':
      app = wx.App(False)
      MyFrame(None)
      app.MainLoop()