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()