Scrollbars that won't appear, Layout that only happens sometimes?

This complete application demonstrates what looks to me like a bug. When
I destroy and recreate a scrolledwindow object in the __init__ method, the
scrollbars appear where they should. When I do the same thing from an
event, no scrollbars. Resizing the window, either manually or with a
SetSize call, causes the scrollbar to appear where it should be.

When you click in the scrolledwindow, it should go away and be replaced by
a new, identical one. Instead, the one that replaces it has no
scrollbars!

Also notable: the Layout() call. Try commenting it out; then run and
click in the window. When the app first appears you'll see the buttons
arranged in a column as they should be. In the window created from the
event, they are stacked up, as if no Layout() call had been made. Why oh
why?

The Layout problem I can work around by calling Layout() (duh), but I
can't seem to workaround the scrollbar problem. Manually calling SetSize
is obviously hackish, and doesn't even work when the frame is maximized.

···

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

class TryApp(wxApp):
    def OnInit(self):
        frame=TryFrame(None)
        frame.Show()
        return 1
        
class TryFrame(wxFrame):
    def __init__(self, prnt):
        wxFrame.__init__(self, parent=prnt, id=-1,
                         title='Try Scrolled Window')
        self.clientarea=TryScrolledWindow(self)
        self.clientarea.Destroy()
        self.clientarea=TryScrolledWindow(self)
        EVT_LEFT_DOWN(self.clientarea, self.OnClick)

    def OnClick(self, evt):
        self.clientarea.Destroy()
        self.clientarea=TryScrolledWindow(self) # inconsistent scrollbar
                                                # behavior

class TryScrolledWindow(wxScrolledWindow):
    def __init__(self, prnt):
        wxScrolledWindow.__init__(self, parent=prnt, id=-1,
                                  size=prnt.GetSize(),
                                  style=wxTAB_TRAVERSAL)
        sizer=wxBoxSizer(wxVERTICAL)
        self.SetSizer(sizer)
        for i in range(100):
            sizer.Add(wxButton(parent=self, id=-1, label="foo"*10))
        self.Layout() # comment me to see inconsistent layout behavior
        self.SetScrollRate(20,20)
        
if __name__=='__main__':
    TryApp().MainLoop()

__________________________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo
http://search.yahoo.com

Cory Dodt wrote:

This complete application demonstrates what looks to me like a bug. When
I destroy and recreate a scrolledwindow object in the __init__ method, the
scrollbars appear where they should. When I do the same thing from an
event, no scrollbars. Resizing the window, either manually or with a
SetSize call, causes the scrollbar to appear where it should be.

When you click in the scrolledwindow, it should go away and be replaced by
a new, identical one. Instead, the one that replaces it has no
scrollbars!

Because it is not identical :wink: The first one is automatically sized by the frame since it is the frame's only child and there was a EVT_SIZE event after the child was created. The second will still be the only child since you killed the other one first, but there is no new EVT_SIZE and so the child remains it's default size of (20,20) or something like that.

Also notable: the Layout() call. Try commenting it out; then run and
click in the window. When the app first appears you'll see the buttons
arranged in a column as they should be. In the window created from the
event, they are stacked up, as if no Layout() call had been made. Why oh
why?

Related to the above. The Layout is called automatically in the window's default EVT_SIZE handler, but since the frame has not sized the new scrolled window yet then the scrolled window's EVT_SIZE handler hasn't been called yet either.

The key to the fix is to get the new child to be resized to whatever size it should be. In this case just calling the frame's SendSizeEvent method should do it. In other scenarios where the new child is not the only child of a frame but is a member of a sizer then calling that sizer's Layout would do it.

···

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