== wx.ScrolledWindow with wx.TextCtrl ==
Examples of wx.ScrolledWindow with some TextCtrl.

It is necessary to have a wx.ScrolledWindow or a wx.[[ScrolledWindow|PyScrolledWindow]] be managed by a sizer to gaurantee that the scrollbars appear when they are needed.

The first example shows the basic way. When the focus goes to a TextCtrl the scrollbars do not move automatically.

The second example  moves the scrollbars when the focus goes to the control. This moves the TextCtrl in focus to the top-left of the Frame. It alse uses a wx.FlexGridSizer to efficiently arrange the controls.

The third example updates the scrollbars accordingly when the sizer contents grows and shrinks programmatically.

=== First example, basic ===
Thanks to Gary Simmons for clarifying my code.

{{{#!python
#!/usr/bin/python

import wx

class FicheFrame( wx.Frame ) :

    def __init__( self ) :

        wx.Frame.__init__( self, None,-1, "FicheFrame", size=(300, 400) )

        scrollWin = wx.PyScrolledWindow( self, -1 )

        x = 20       # Magic numbers !?
        y = 20
        for i in range( 50 ) :

            txtStr = " Text %02d  : " % (i+1)
            stTxt = wx.StaticText( scrollWin, -1, txtStr, pos=(x, y) )

            w, h = stTxt.GetSize()
            txtCtrl = wx.TextCtrl( scrollWin, -1, pos=(x+w+5, y) )

            dy = h + 10     # calculate for next loop
            y += dy

        #end for

        scrollWin.SetScrollbars( 0, dy,  0, y/dy+1 )
        scrollWin.SetScrollRate( 1, 1 )      # Pixels per scroll increment

    #end __init__ def

#end class

if __name__ == '__main__' :

    myapp = wx.App( redirect=False )

    myAppFrame = FicheFrame()
    myAppFrame.Show()

    myapp.MainLoop()
}}}
=== Second example: managed TextCtrl focus ===
This example moves the scrollbars automatically when the focus goes to a TextCtrl.  The comments describe when this happens. Multi-line TextCtrl's can be substituted.

{{{#!python
#!/usr/bin/python

import wx

class FicheFrameWithFocus( wx.Frame ) :

    def __init__( self ) :

        wx.Frame.__init__( self, None, -1 ,"FicheFrameWithFocus", size=(275, 500) )

        self.scroll = wx.ScrolledWindow( self, -1 )

        self.frmPanel = wx.Panel( self.scroll, -1 )

        # A sizer allows the horizontal scrollbar to appear when needed.
        flGrSzr = wx.FlexGridSizer( 50, 2, 2, 2 )   # rows, cols, hgap, vgap

        for i in range( 50 ) :

            textStr = " Champ (txt) %2d  : " % (i+1)
            flGrSzr.Add( wx.StaticText( self.frmPanel, -1, textStr ) )

            txtCtrl = wx.TextCtrl( self.frmPanel, -1, size=(100, -1), style=0 )
            wx.EVT_SET_FOCUS( txtCtrl, self.OnFocus )
            flGrSzr.Add( txtCtrl )

        #end for

        # Create a border around frmPnlSizer to the edges of the frame.
        frmPnlSizer = wx.BoxSizer( wx.VERTICAL )
        frmPnlSizer.Add( flGrSzr, proportion=1, flag=wx.ALL, border=20 )

        self.frmPanel.SetSizer( frmPnlSizer )
        self.frmPanel.SetAutoLayout( True )
        self.frmPanel.Layout()
        self.frmPanel.Fit()     # frmPnlSizer borders will be respected

        self.Center()
        self.MakeModal( True )

        # Scrolling parameters must be set AFTER all controls have been laid out.
        self.frmPanelWid, self.frmPanelHgt = self.frmPanel.GetSize()
        self.unit = 1
        self.scroll.SetScrollbars( self.unit, self.unit, self.frmPanelWid/self.unit, self.frmPanelHgt/self.unit )

    #end __init__ def

    def OnFocus( self, event ) :
        """
        This makes the selected (the one in focus) textCtrl to be automatically
        repositioned to the top-left of the window. One of the scrollbars
        must have been moved for this to happen.

        The benefits for doing this are dubious. but this demonstrates how it can be done.
        """

        parentControl = self.FindWindowById( event.GetId() )  # The parent container control
        parentPosX, parentPosY = parentControl.GetPosition()
        hx, hy = parentControl.GetSizeTuple()
        clientSizeX, clientSizeY = self.scroll.GetClientSize()

        sx, sy = self.scroll.GetViewStart()
        magicNumber = 20        # Where did this value come from ?!
        sx = sx * magicNumber
        sy = sy * magicNumber

        if (parentPosY < sy ) :
            self.scroll.Scroll( 0, parentPosY/self.unit )

        if ( parentPosX < sx ) :
             self.scroll.Scroll( 0, -1 )

        if (parentPosX + sx) > clientSizeX  :
            self.scroll.Scroll( 0, -1 )

        if (parentPosY + hy - sy) > clientSizeY :
            self.scroll.Scroll( 0, parentPosY/self.unit )

    #end OnFocus def

#end FicheFrameWithFocus class

if __name__ == '__main__' :

    myapp = wx.App( redirect=False )
    appFrame = FicheFrameWithFocus()
    appFrame.Show()
    myapp.MainLoop()
}}}

=== Third example: Scrollbars for variable-sized sizer ===

When the contents in a ScrolledWindow changes size, the scrollbar may need to appear or disappear.
This example shrinks and grows a GridBagSizer by hiding and re-showing the wx.StaticText's within.

{{{#!python
import wx
class AScrolledWindow(wx.ScrolledWindow):
    def __init__(self, parent):
        self.parent = parent
        wx.ScrolledWindow.__init__(self, parent, -1, style=wx.TAB_TRAVERSAL)
        gb = wx.GridBagSizer(vgap=0, hgap=3)
        self.sizer = gb
        self._labels = []
        self._show_but = wx.Button(self, -1, "Show")
        self._hide_but = wx.Button(self, -1, "Hide")
        gb.Add(self._show_but, (0,0), (1,1))
        gb.Add(self._hide_but, (0,1), (1,1))
        for y in xrange(1,30):
            self._labels.append(wx.StaticText(self, -1, "Label #%d" % (y,)))
            gb.Add(self._labels[-1], (y,1), (1,1))
        self._show_but.Bind(wx.EVT_BUTTON, self.OnShow)
        self._hide_but.Bind(wx.EVT_BUTTON, self.OnHide)
        self.SetSizer(self.sizer)
        fontsz = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT).GetPixelSize()
        self.SetScrollRate(fontsz.x, fontsz.y)
        self.EnableScrolling(True,True)

    def OnShow(self, event):
        for lab in self._labels:
            self.sizer.Show(lab, True)
        self.OnInnerSizeChanged()
    def OnHide(self, event):
        for lab in self._labels:
            self.sizer.Show(lab, False)
        self.OnInnerSizeChanged()
    def OnInnerSizeChanged(self):
        w,h = self.sizer.GetMinSize()
        self.SetVirtualSize((w,h))
            
class TestFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Programmatic size change')
        sz = wx.BoxSizer(wx.VERTICAL)
        pa = AScrolledWindow(self)
        sz.Add(pa, 1, wx.EXPAND)
        self.SetSizer(sz)

def main():
    wxapp = wx.App()
    fr = TestFrame()
    fr.Show(True)
    wxapp.MainLoop()

if __name__=='__main__':
    main()
}}}