Sizer not updating its size

I've been extremely frustrated with this problem I've been having so I
thought I'd turn to some group therapy for help.

I'm building an application that, in essence, displays two panels. In
the first panel is a list of objects where the user can select one.
The second panel then displays a list of editable fields specific to
the selected object. Every time the selection is changed, the "Editor"
panel needs to be re-created. To do this I call an update() function.

The problem is that the Sizer isn't immediately updating its size
based on its contents. Thus, for instance, the containing scrollbars
won't be properly set to the proper size. However, If the containing
program window itself is resized, then the Editor panel assumes the
correct size and everything is copacetic. It's as if the AutoLayout()
function is working fine, but the manual Layout() isn't. The panel is
also sized correctly after the first update().

After I call a second update(), if I inspect the value of
Editor.panel.Sizer.Size I can see that the value is incorrect. How can
I force the Sizer to update its size? Should I be using a different
approach to clear and then recreate a panel in my GUI?

Cheers,

Paul

Here's the whittled-down pseudo-code.

···

====================

import wx
from wx.lib.scrolledpanel import ScrolledPanel

class FieldEditor(ScrolledPanel):

    def __init__(self, parent_frame):

        ScrolledPanel.__init__(self, parent_frame, style=wx.SUNKEN_BORDER)
        self.SetScrollRate(5,5)

    def update(self, textarray):

        # Try and delete any existing content
        try:
            self.panel.Destroy()
        except AttributeError:
            pass

        # Create a panel that will contain all the "content"
        self.panel = wx.Panel(self, style=wx.SIMPLE_BORDER)

        fillbox = wx.BoxSizer(wx.VERTICAL)
        fillbox.Add(self.panel, proportion=1, flag=wx.EXPAND)
        self.SetSizer(fillbox)

        # Start with a vertical grid of elements
        grid = wx.BoxSizer(wx.VERTICAL)

        for entry in textarray:
            grid.Add(wx.StaticText(self.panel, label=entry),
flag=wx.EXPAND, border=5)

        self.panel.SetSizer(grid)

        # Force the frame to use the use the sizer to perform a layout
of all the content
        # Probably some redundancy here...
        self.panel.SetAutoLayout(True)
        self.panel.Refresh()
        self.panel.Update()
        self.panel.Layout()

...
...
Editor = FieldEditor(parent)
Editor.update(['Frank'])
Editor.update(['Paul','Mike','Blah blah blah some really long text
that should make the scrollbars appear'])
# panel retains its small size until the entire program is resized

Paul wrote:

I've been extremely frustrated with this problem I've been having so I
thought I'd turn to some group therapy for help.

I'm building an application that, in essence, displays two panels. In
the first panel is a list of objects where the user can select one.
The second panel then displays a list of editable fields specific to
the selected object. Every time the selection is changed, the "Editor"
panel needs to be re-created. To do this I call an update() function.

The problem is that the Sizer isn't immediately updating its size
based on its contents. Thus, for instance, the containing scrollbars
won't be properly set to the proper size. However, If the containing
program window itself is resized, then the Editor panel assumes the
correct size and everything is copacetic. It's as if the AutoLayout()
function is working fine, but the manual Layout() isn't. The panel is
also sized correctly after the first update().

After I call a second update(), if I inspect the value of
Editor.panel.Sizer.Size I can see that the value is incorrect. How can
I force the Sizer to update its size? Should I be using a different
approach to clear and then recreate a panel in my GUI?

Cheers,

Paul

Here's the whittled-down pseudo-code.

====================

import wx
from wx.lib.scrolledpanel import ScrolledPanel

class FieldEditor(ScrolledPanel):

    def __init__(self, parent_frame):

        ScrolledPanel.__init__(self, parent_frame, style=wx.SUNKEN_BORDER)
        self.SetScrollRate(5,5)

    def update(self, textarray):

        # Try and delete any existing content
        try:
            self.panel.Destroy()
        except AttributeError:
            pass

        # Create a panel that will contain all the "content"
        self.panel = wx.Panel(self, style=wx.SIMPLE_BORDER)

        fillbox = wx.BoxSizer(wx.VERTICAL)
        fillbox.Add(self.panel, proportion=1, flag=wx.EXPAND)
        self.SetSizer(fillbox)

        # Start with a vertical grid of elements
        grid = wx.BoxSizer(wx.VERTICAL)

        for entry in textarray:
            grid.Add(wx.StaticText(self.panel, label=entry),
flag=wx.EXPAND, border=5)

        self.panel.SetSizer(grid)

        # Force the frame to use the use the sizer to perform a layout
of all the content
        # Probably some redundancy here...
        self.panel.SetAutoLayout(True)
        self.panel.Refresh()
        self.panel.Update()
        self.panel.Layout()

...
Editor = FieldEditor(parent)
Editor.update(['Frank'])
Editor.update(['Paul','Mike','Blah blah blah some really long text
that should make the scrollbars appear'])
# panel retains its small size until the entire program is resized

I'm guessing here, but I think because you destroyed the panel and then created a new one, the Layout isn't working. Try calling self.Layout() instead. Or iterate over the children of the panel and destroy them:

children = self.panel.GetChildren()
for child in children:
     child.Destroy()

Something like that...then the self.panel.Layout might work...

···

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org
Python Extension Building Network: http://www.pythonlibrary.org

Paul wrote:

I've been extremely frustrated with this problem I've been having so I
thought I'd turn to some group therapy for help.

I'm building an application that, in essence, displays two panels. In
the first panel is a list of objects where the user can select one.
The second panel then displays a list of editable fields specific to
the selected object. Every time the selection is changed, the "Editor"
panel needs to be re-created. To do this I call an update() function.

The problem is that the Sizer isn't immediately updating its size
based on its contents. Thus, for instance, the containing scrollbars
won't be properly set to the proper size. However, If the containing
program window itself is resized, then the Editor panel assumes the
correct size and everything is copacetic. It's as if the AutoLayout()
function is working fine, but the manual Layout() isn't. The panel is
also sized correctly after the first update().

After I call a second update(), if I inspect the value of
Editor.panel.Sizer.Size I can see that the value is incorrect. How can
I force the Sizer to update its size? Should I be using a different
approach to clear and then recreate a panel in my GUI?

Cheers,

Paul

Here's the whittled-down pseudo-code.

====================

import wx
from wx.lib.scrolledpanel import ScrolledPanel

class FieldEditor(ScrolledPanel):

    def __init__(self, parent_frame):

        ScrolledPanel.__init__(self, parent_frame, style=wx.SUNKEN_BORDER)
        self.SetScrollRate(5,5)

    def update(self, textarray):

        # Try and delete any existing content
        try:
            self.panel.Destroy()
        except AttributeError:
            pass

        # Create a panel that will contain all the "content"
        self.panel = wx.Panel(self, style=wx.SIMPLE_BORDER)

        fillbox = wx.BoxSizer(wx.VERTICAL)
        fillbox.Add(self.panel, proportion=1, flag=wx.EXPAND)
        self.SetSizer(fillbox)

        # Start with a vertical grid of elements
        grid = wx.BoxSizer(wx.VERTICAL)

        for entry in textarray:
            grid.Add(wx.StaticText(self.panel, label=entry),
flag=wx.EXPAND, border=5)

        self.panel.SetSizer(grid)

The line above will facilitate the layout of the items on the panel, within the space available in the panel, but you don't do anything to cause the panel itself to become large enough to hold all the items. Try getting rid of the lines below and simply add:

  self.Layout()

That will use the scrolled window's sizer to size and position it's children (the panel) and will then cause a recursive layout of the children that changed size and also have sizers of their own.

···

        # Force the frame to use the use the sizer to perform a layout
of all the content
        # Probably some redundancy here...
        self.panel.SetAutoLayout(True)
        self.panel.Refresh()
        self.panel.Update()
        self.panel.Layout()

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