Relayout problem with wxBoxSizer on wxGTK

Hi,
I ran into a relayout problem on wxGTK. The problem is described
in the docstrings of the attached test program.

Using Python 2.2.3 and wxPython 2.4.0.7 on Windows 2000 works.
The wxGTK problem happens on a Debian based system using
Python 2.2.2 and wxPython 2.4.0.8.

Fortunately for this particular case, I can work around this oddity by
using a GridSizer instead of a BoxSizer.
Still I would really appreciate if somebody could explain what is
going on because relayout is my primary 'waste a day' discipline.

Thanks in advance,
Michael

···

--------------------------------------------------------------------
#!/bin/env python

from wxPython.wx import *

MAX_TEXTS = 3

class TextHeadings(wxPanel):

    """This class displays some texts headers.

    Each text header gets an equal amount of the total available width of this panel.
    If the number of text headers decreases from three to one the width of the text headers
    is correctly adjusted.
    When the number of text headers increases while using a wxBoxSizer on wxGTK, the first text
    header is still displayed using the full with of the panel.
    Using a wxGridSizer or wxMSW instead of wxGTK works as expected.
    """

    def __init__(self, parent, id=-1, pos=wxDefaultPosition, size=wxDefaultSize):
        wxPanel.__init__(self, parent, id, pos, size)

        sizer, self.gps = self._initHeaders(parent)
        self.layoutHeaders(3)

    def layoutHeaders(self, num):
        # Using a wxBoxSizer works on wxMSW, but not on wxGTK
        sizer = wxBoxSizer(wxHORIZONTAL)

        # Using wxGridSizer works on wxMSW and wxGTK
        # sizer = wxGridSizer(1, num, 0, 0)

        for i in range(MAX_TEXTS):
            self.gps[i].SetSize((-1, -1))
            if i < num:
                self.gps[i].Show()
                sizer.AddWindow(self.gps[i], 1, wxALIGN_CENTRE|wxLEFT|wxRIGHT, 3)
            else:
                self.gps[i].Hide()

        self.SetSizer(sizer)
        sizer.SetSizeHints(self)

        self.Layout()
        self.GetParent().Layout()

    def _initHeaders(self, parent):
        gps = []
        sizer = wxBoxSizer(wxHORIZONTAL)
        for i in range(MAX_TEXTS):
            item1 = wxStaticText( self, -1, "Text %d" % i, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE|wxST_NO_AUTORESIZE)
            sizer.AddWindow( item1, 1, wxALIGN_CENTRE|wxLEFT|wxRIGHT, 3)
            gps.append(item1)
            
        return sizer, gps

class HeadingFrame(wxFrame):
    """Displays a panel of text headers.

    The left part of the frame receives left- and right clicks which
    decreased and increases the number of text headers displayed respectively.
    """
    def __init__(self, parent):
        wxFrame.__init__(self, parent, -1, "Heading Frame")

        self.num = MAX_TEXTS

        self.sizer = wxBoxSizer(wxHORIZONTAL)

        self.th = TextHeadings(self)

        self.sizer.AddSpacer( 20, 20, 0, wxALIGN_CENTRE|wxALL, 5 )
        self.sizer.AddWindow( self.th, 1, wxALIGN_CENTRE|wxALL, 5 )

        self.SetAutoLayout(true)
        self.SetSizer(self.sizer)
        self.sizer.Fit(self)
        self.sizer.SetSizeHints( self )

        EVT_LEFT_DOWN(self, self.LeftDown)
        EVT_RIGHT_DOWN(self, self.RightDown)

    def LeftDown(self, event):
        if self.num > 1:
            self.num -= 1
            self.adjustWindow()

    def RightDown(self, event):
        if self.num < MAX_TEXTS:
            self.num += 1
            self.adjustWindow()

    def adjustWindow(self):
        print "Showing %d texts" % self.num
        self.th.layoutHeaders(self.num)
        self.printWinInfo(self)

    def printWinInfo(self, win, indent=0):
        methods = ['GetBestSize', 'GetSize', 'GetPosition']
        print "%s-- %s --" % (' ' * indent, `win`)
        for m in methods:
            func = getattr(win, m)
            ret = func()
            print "%s%s: %s" % (' ' * indent, m, ret)
        for c in win.GetChildren():
            self.printWinInfo(c, indent+4)
        
if __name__ == '__main__':
    app = wxPySimpleApp()
    frame = HeadingFrame(None)
    frame.Show(True)
    app.MainLoop()

--------------------------------------------------------------------

--
- Michael Krause
- Email michael@krause-software.de

Michael Krause wrote:

Hi,
I ran into a relayout problem on wxGTK.

[...]

Instead of this:

            self.gps[i].SetSize((-1, -1))

Do this:

             self.gps[i].SetSize(self.gps[i].GetBestSize())

Using -1 only means use the best size when the control is created. After that it normally means don't change the size.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

Instead of this:

            self.gps[i].SetSize((-1, -1))

Do this:

            self.gps[i].SetSize(self.gps[i].GetBestSize())

Or use the wxADJUST_MINSIZE flag when adding the items to the sizer, then everytimne the sizer adjusts the layout it will ask the items for their current best size.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!