Cam Jackson
Cam Jackson

Reputation: 12304

When its containing panel or frame becomes too small, wxListBox stops using its horizontal scrollbar and expands to take up too much space

SSCCE is at the bottom

My layout has two wx.ListBoxes, side-by side in a wx.FlexGridSizer:

OK so far

My real layout is more complex, thus the FGS, but this small example still exhibits the problem.

As you can see above, I have successfully used style = wx.LB_HSCROLL to make each listbox use a horizontal scroll bar when one of its elements would make it too large to fit in the wx.Frame.

However, as I resize the window smaller and smaller, eventually some critical point is reached, the first listbox decides it doesn't want to use its scrollbar anymore, and instead expands to its full size, pushing the second box to the right:

Window gets too small!

The point at which the list goes crazy depends on how long the string is. If I put a long enough string in the first box, then the above process is reversed: the layout starts off wrong and I have to resize the window up to the critical point, where all of a sudden the listbox starts using its scrollbar, gets a lot smaller, and the window becomes split down the middle as it should be.

I'm not sure if this is a bug in wxWidgets/wxPython or if I'm doing something wrong, but it's frustrating either way. Here is the simplest code I can come up with that shows the problem:

import wx

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, parent = None, size = (640, 480))

        self.list1 = wx.ListBox(self, style = wx.LB_HSCROLL)
        self.list2 = wx.ListBox(self, style = wx.LB_HSCROLL)

        self.list1.Append('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
        self.list2.Append('bbbbbbbbbbb')

        self.fgs = wx.FlexGridSizer(1, 2)
        self.fgs.AddMany([(self.list1, 1, wx.EXPAND), (self.list2, 1, wx.EXPAND)])
        self.fgs.AddGrowableRow(0, 1)
        self.fgs.AddGrowableCol(0, 1)
        self.fgs.AddGrowableCol(1, 1)

        self.Bind(wx.EVT_SIZE, self.OnSize)

        self.Sizer = fgs
        self.Layout()
        self.Show()

    def Exit(self, event):
        self.Close(True)

app = wx.App(False)
frame = MyFrame()
app.MainLoop()

EDIT: Here is my implementation of ravenspoint's code in python (code above was changed slightly to support this):

def OnSize(self, event):
    if not self.list1 or not self.list2;
        return

    clientRect = self.GetClientRect()
    min = wx.Size(clientRect.width / 2, clientRect.height)

    self.list1.MinSize = min
    self.list2.MinSize = min

Upvotes: 2

Views: 993

Answers (2)

Chris.Wilson
Chris.Wilson

Reputation: 131

Since I ran into this problem as well, I'll post this for future reference. At least with wxPython, you must specify a min size or it will use the best size (at least for list boxes) and the sizer could possibly shove widgets outside of the current window frame. Thus, the added code to get the above code working as desired is:

    self.list1.SetMinSize((10,10));
    self.list2.SetMinSize((10,10));

The total working answer is:

import wx
class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, parent = None, size = (640, 480))

        self.list1 = wx.ListBox(self, style = wx.LB_HSCROLL)
        self.list2 = wx.ListBox(self, style = wx.LB_HSCROLL)

        self.list1.Append('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
        self.list2.Append('bbbbbbbbbbb')

        self.fgs = wx.FlexGridSizer(1, 2)
        self.fgs.AddMany([(self.list1, 1, wx.EXPAND), (self.list2, 1, wx.EXPAND)])
        self.fgs.AddGrowableRow(0, 1)
        self.fgs.AddGrowableCol(0, 1)
        self.fgs.AddGrowableCol(1, 1)

        # Don't forget these two lines to allow for correct 
        # expansion/contraction of the sizer!
        self.list1.SetMinSize((10,10));
        self.list2.SetMinSize((10,10));

        self.Sizer = self.fgs
        self.Layout()
        self.Show()

if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

Upvotes: 1

ravenspoint
ravenspoint

Reputation: 20616

You may have to look after handling the resize event yourself. In C++ the handler would look something like this:

void MyFrame::OnSize(wxSizeEvent& )
{
    if( ! ( list1 && list2 ) )
        return;
    wxRect frame_client = GetClientRect();
    wxSize min(frame_client.width/2,frame_client.height );
    list1->SetMinSize(min);
    list2->SetMinSize(min);
    fgs->Layout();
}

Upvotes: 1

Related Questions