ScrolledWindow behavior

I posted this first in Google Groups. Hopefully it is not an annoying cross-post to go here also.

I am trying to understand how ScrolledWindow decides where to position
scrollbars.

The sample code simulates a small piece of our application. In the
application, the panels are actually contained in a notebook within
the scrolled window.
For the sample, I made a simple scrolled window containing a panel
that is bigger than containing window. When you run the application,
the scrollbars are initially positioned to the far right and bottom of
the scrolled window. I want them to be positioned to the left top. I
can make that happen by calling Scroll(0,0) for the scrolled window
after Show() for the frame, but if I click on the window, the
scroll bars reposition to the far right and bottom by themselves.

How can I reliably position the scrollbars to (0,0)?

We maintain the GUI for our application in wxGlade, I have little
flexibility to make major changes in the classes used to build the app
at this time. I can insert code that modifies the behavior of widgets
after the wxGlade generated layout is complete. This sample is a
cleaned up version of code generated by wxGlade.

Here are some tests I have run:
A. with Scroll(0,0) in MyApp.init() commented out

  1. scrollbars initially positioned to bottom right
  2. click on title bar or text control, positions scrolled window to

beginning of text box, almost top left
B. with Scroll(0,0) in MyApp.init() active

  1. scrollbars initially positioned to top left
  2. click on title bar or text control, positions scrolled window to
    bottom right

Here is what I want to have happen:

  1. Screen should initially position to (0,0)
  2. Automatically scroll if selecting a control that is not visible on
    screen (I think this works, but because of the other problems I can’t
    prove it)
  3. As mentioned before, the problem exists for panels contained in a
    Notebook. I need the behavior to be consistent for those panels also.

Environment:
Windows XP Service Pack 3
wx 2.8.9.2 - but I am pretty sure same behavior exists on earlier
versions

---------------- sample code starts here

import wx

class MyFrame(wx.Frame):
def init(self, *args, **kwds):
kwds[“style”] = wx.DEFAULT_FRAME_STYLE
wx.Frame.init(self, *args, **kwds)
# main scrolled window
self.scroller = wx.ScrolledWindow(self, -1, style=wx.TAB_TRAVERSAL)
# a panel in the scroller
self.panel = wx.Panel(self.scroller, -1)
self.text = wx.StaticText(self.panel, -1, “tab2 text”)
self.text_ctrl = wx.TextCtrl(self.panel, -1, “”)

    self.__set_properties()
    self.__do_layout()

def __set_properties(self):
    self.SetSize((700, 500))
    self.text_ctrl.SetMinSize((800,800))

self.scroller.SetScrollRate(20, 20)

def __do_layout(self):

    # layout the panel

    sizer_panel = wx.BoxSizer(wx.VERTICAL)

    sizer_panel.Add(self.text, 0, wx.EXPAND, 0)

    sizer_panel.Add(self.text_ctrl, 1, wx.ALL|wx.EXPAND, 5)

    self.panel.SetSizer(sizer_panel)

    # layout the scroller

    scrollsizer = wx.BoxSizer(wx.HORIZONTAL)

    scrollsizer.Add(self.panel, 1, wx.EXPAND, 0)

    self.scroller.SetSizer(scrollsizer)

    # layout the frame

    main_sz = wx.BoxSizer(wx.VERTICAL)

    main_sz.Add(self.scroller, 1, wx.EXPAND, 0)

    self.SetSizer(main_sz)

    main_sz.SetSizeHints(self)

    self.Layout()

    # end wxGlade

    self.SetSize((700,500))

class MyApp(wx.App):

def OnInit(self):

    myframe = MyFrame(None, -1, "force scroll to (0,0) [wx:%s]"%wx.version())

    myframe.Show()

    #myframe.scroller.Scroll(0,0)

    self.SetTopWindow(myframe)

    return 1

if name == “main”:

app = MyApp(0)

import wx.lib.inspection

wx.lib.inspection.InspectionTool().Show()

app.MainLoop()
···


Mike Conley

Mike Conley wrote:

I posted this first in Google Groups. Hopefully it is not an annoying cross-post to go here also.

I am trying to understand how ScrolledWindow decides where to position
scrollbars.

The sample code simulates a small piece of our application. In the
application, the panels are actually contained in a notebook within
the scrolled window.
For the sample, I made a simple scrolled window containing a panel
that is bigger than containing window. When you run the application,
the scrollbars are initially positioned to the far right and bottom of
the scrolled window. I want them to be positioned to the left top. I
can make that happen by calling Scroll(0,0) for the scrolled window
after Show() for the frame, but if I click on the window, the
scroll bars reposition to the far right and bottom by themselves.

How can I reliably position the scrollbars to (0,0)?

We maintain the GUI for our application in wxGlade, I have little
flexibility to make major changes in the classes used to build the app
at this time. I can insert code that modifies the behavior of widgets
after the wxGlade generated layout is complete. This sample is a
cleaned up version of code generated by wxGlade.

Here are some tests I have run:
A. with Scroll(0,0) in MyApp.__init__() commented out
1. scrollbars initially positioned to bottom right
2. click on title bar or text control, positions scrolled window to
     beginning of text box, almost top left
B. with Scroll(0,0) in MyApp.__init__() active
1. scrollbars initially positioned to top left
2. click on title bar or text control, positions scrolled window to
    bottom right

Here is what I want to have happen:
1. Screen should initially position to (0,0)
2. Automatically scroll if selecting a control that is not visible on
screen (I think this works, but because of the other problems I can't
prove it)
3. As mentioned before, the problem exists for panels contained in a
Notebook. I need the behavior to be consistent for those panels also.

Environment:
Windows XP Service Pack 3
wx 2.8.9.2 - but I am pretty sure same behavior exists on earlier
versions

The problem you are seeing is due to your #2. wx.ScrolledWindow
recently got some functionality like what we've had in
wx.lib.scrolledpanel for ages, it will attempt to scroll a child into
view when that child gets the focus. However in this case the child is
larger than the viewable area and so it ends up with the lower-right
corner of the child in view but not the upper left.

You might try using a ScrolledPanel instead, as I think we added
something a while back to compensate for this situation. Or you can
just intercept the EVT_CHILD_FOCUS event and deal with it yourself
instead of letting the scrolled window have it.

···

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