wx.ScrolledWindow with wx.TextCtrl

Examples of wx.ScrolledWindow with some TextCtrl.

It is necessary to have a wx.ScrolledWindow or a wx.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.

   1 #!/usr/bin/python
   2 
   3 import wx
   4 
   5 class FicheFrame( wx.Frame ) :
   6 
   7     def __init__( self ) :
   8 
   9         wx.Frame.__init__( self, None,-1, "FicheFrame", size=(300, 400) )
  10 
  11         scrollWin = wx.PyScrolledWindow( self, -1 )
  12 
  13         x = 20       # Magic numbers !?
  14         y = 20
  15         for i in range( 50 ) :
  16 
  17             txtStr = " Text %02d  : " % (i+1)
  18             stTxt = wx.StaticText( scrollWin, -1, txtStr, pos=(x, y) )
  19 
  20             w, h = stTxt.GetSize()
  21             txtCtrl = wx.TextCtrl( scrollWin, -1, pos=(x+w+5, y) )
  22 
  23             dy = h + 10     # calculate for next loop
  24             y += dy
  25 
  26         #end for
  27 
  28         scrollWin.SetScrollbars( 0, dy,  0, y/dy+1 )
  29         scrollWin.SetScrollRate( 1, 1 )      # Pixels per scroll increment
  30 
  31     #end __init__ def
  32 
  33 #end class
  34 
  35 if __name__ == '__main__' :
  36 
  37     myapp = wx.App( redirect=False )
  38 
  39     myAppFrame = FicheFrame()
  40     myAppFrame.Show()
  41 
  42     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.

   1 #!/usr/bin/python
   2 
   3 import wx
   4 
   5 class FicheFrameWithFocus( wx.Frame ) :
   6 
   7     def __init__( self ) :
   8 
   9         wx.Frame.__init__( self, None, -1 ,"FicheFrameWithFocus", size=(275, 500) )
  10 
  11         self.scroll = wx.ScrolledWindow( self, -1 )
  12 
  13         self.frmPanel = wx.Panel( self.scroll, -1 )
  14 
  15         # A sizer allows the horizontal scrollbar to appear when needed.
  16         flGrSzr = wx.FlexGridSizer( 50, 2, 2, 2 )   # rows, cols, hgap, vgap
  17 
  18         for i in range( 50 ) :
  19 
  20             textStr = " Champ (txt) %2d  : " % (i+1)
  21             flGrSzr.Add( wx.StaticText( self.frmPanel, -1, textStr ) )
  22 
  23             txtCtrl = wx.TextCtrl( self.frmPanel, -1, size=(100, -1), style=0 )
  24             wx.EVT_SET_FOCUS( txtCtrl, self.OnFocus )
  25             flGrSzr.Add( txtCtrl )
  26 
  27         #end for
  28 
  29         # Create a border around frmPnlSizer to the edges of the frame.
  30         frmPnlSizer = wx.BoxSizer( wx.VERTICAL )
  31         frmPnlSizer.Add( flGrSzr, proportion=1, flag=wx.ALL, border=20 )
  32 
  33         self.frmPanel.SetSizer( frmPnlSizer )
  34         self.frmPanel.SetAutoLayout( True )
  35         self.frmPanel.Layout()
  36         self.frmPanel.Fit()     # frmPnlSizer borders will be respected
  37 
  38         self.Center()
  39         self.MakeModal( True )
  40 
  41         # Scrolling parameters must be set AFTER all controls have been laid out.
  42         self.frmPanelWid, self.frmPanelHgt = self.frmPanel.GetSize()
  43         self.unit = 1
  44         self.scroll.SetScrollbars( self.unit, self.unit, self.frmPanelWid/self.unit, self.frmPanelHgt/self.unit )
  45 
  46     #end __init__ def
  47 
  48     def OnFocus( self, event ) :
  49         """
  50         This makes the selected (the one in focus) textCtrl to be automatically
  51         repositioned to the top-left of the window. One of the scrollbars
  52         must have been moved for this to happen.
  53 
  54         The benefits for doing this are dubious. but this demonstrates how it can be done.
  55         """
  56 
  57         parentControl = self.FindWindowById( event.GetId() )  # The parent container control
  58         parentPosX, parentPosY = parentControl.GetPosition()
  59         hx, hy = parentControl.GetSizeTuple()
  60         clientSizeX, clientSizeY = self.scroll.GetClientSize()
  61 
  62         sx, sy = self.scroll.GetViewStart()
  63         magicNumber = 20        # Where did this value come from ?!
  64         sx = sx * magicNumber
  65         sy = sy * magicNumber
  66 
  67         if (parentPosY < sy ) :
  68             self.scroll.Scroll( 0, parentPosY/self.unit )
  69 
  70         if ( parentPosX < sx ) :
  71              self.scroll.Scroll( 0, -1 )
  72 
  73         if (parentPosX + sx) > clientSizeX  :
  74             self.scroll.Scroll( 0, -1 )
  75 
  76         if (parentPosY + hy - sy) > clientSizeY :
  77             self.scroll.Scroll( 0, parentPosY/self.unit )
  78 
  79     #end OnFocus def
  80 
  81 #end FicheFrameWithFocus class
  82 
  83 if __name__ == '__main__' :
  84 
  85     myapp = wx.App( redirect=False )
  86     appFrame = FicheFrameWithFocus()
  87     appFrame.Show()
  88     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.

   1 import wx
   2 class AScrolledWindow(wx.ScrolledWindow):
   3     def __init__(self, parent):
   4         self.parent = parent
   5         wx.ScrolledWindow.__init__(self, parent, -1, style=wx.TAB_TRAVERSAL)
   6         gb = wx.GridBagSizer(vgap=0, hgap=3)
   7         self.sizer = gb
   8         self._labels = []
   9         self._show_but = wx.Button(self, -1, "Show")
  10         self._hide_but = wx.Button(self, -1, "Hide")
  11         gb.Add(self._show_but, (0,0), (1,1))
  12         gb.Add(self._hide_but, (0,1), (1,1))
  13         for y in xrange(1,30):
  14             self._labels.append(wx.StaticText(self, -1, "Label #%d" % (y,)))
  15             gb.Add(self._labels[-1], (y,1), (1,1))
  16         self._show_but.Bind(wx.EVT_BUTTON, self.OnShow)
  17         self._hide_but.Bind(wx.EVT_BUTTON, self.OnHide)
  18         self.SetSizer(self.sizer)
  19         fontsz = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT).GetPixelSize()
  20         self.SetScrollRate(fontsz.x, fontsz.y)
  21         self.EnableScrolling(True,True)
  22 
  23     def OnShow(self, event):
  24         for lab in self._labels:
  25             self.sizer.Show(lab, True)
  26         self.OnInnerSizeChanged()
  27     def OnHide(self, event):
  28         for lab in self._labels:
  29             self.sizer.Show(lab, False)
  30         self.OnInnerSizeChanged()
  31     def OnInnerSizeChanged(self):
  32         w,h = self.sizer.GetMinSize()
  33         self.SetVirtualSize((w,h))
  34             
  35 class TestFrame(wx.Frame):
  36     def __init__(self):
  37         wx.Frame.__init__(self, None, -1, 'Programmatic size change')
  38         sz = wx.BoxSizer(wx.VERTICAL)
  39         pa = AScrolledWindow(self)
  40         sz.Add(pa, 1, wx.EXPAND)
  41         self.SetSizer(sz)
  42 
  43 def main():
  44     wxapp = wx.App()
  45     fr = TestFrame()
  46     fr.Show(True)
  47     wxapp.MainLoop()
  48 
  49 if __name__=='__main__':
  50     main()

ScrolledWindows (last edited 2013-12-19 08:56:59 by mail)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.