All associated wiki pages:
BoxSizerFromTheGroundUp/ControlsResizing |
||
This page's Table of Contents:
Resizing Controls
The BoxSizer can be used to expand a control "to fill the space allotted to the item". See http://www.wxpython.org/docs/api/wx.Sizer-class.html. That's probably as glib as humanly possible. Exactly how much space will be "allotted to the item" ? For that matter, what is an "item" ? What the WxWidget's documentors didn't bother to write is that any control will be expanded to take up all the space in the container client area excluding the space taken up by fixed-sized controls and fixed-sized spacers. If there are multiple controls or spacers that will be wx.EXPANDed then the unclaimed space will divided among them.
wx.EXPAND and wx.GROW are synonyms.
To demonstrate a control's expansion a frame will be created with just two wx.Panels situated side-by-side. The panel colors will be different to make it obvious which panel is which. The two panels will be .Add()ed to a horizontal BoxSizer.
1 #!/usr/bin/python
2
3 # wxEXPAND_DEMO_A_1.PY
4
5 import wx
6
7 #------------------------------------------------------------------------------
8
9 class AppFrame( wx.Frame ) :
10
11 def __init__( self ) :
12
13 #----- Configure the Frame.
14
15 wx.Frame.__init__( self, parent=None, title='wxEXPAND_DEMO_A_1' )
16 self.Position = (200, 0)
17 self.ClientSize = (300, 200)
18 self.BackgoundColour = 'white'
19
20 # A panel is needed for tab-traversal and platform background color consistency.
21 # The first control instantiated in a Frame automatically expands
22 # to the size Frame.ClientSize. This is unique to Frames.
23 frm_pnl = wx.Panel( self )
24 frm_pnl.BackgroundColour = (255, 255, 230) # Contrast with panels below.
25
26 #----- Create the panel's controls
27
28 left_pnl = wx.Panel( frm_pnl )
29 left_pnl.BackgroundColour = (200, 240, 200) # light green
30
31 right_pnl = wx.Panel( frm_pnl )
32 right_pnl.BackgroundColour = (200, 230, 250) # light blue
33
34 #----- Create the sizer and add the controls to it.
35
36 frmPnl_horzSizer = wx.BoxSizer( wx.HORIZONTAL )
37 frmPnl_horzSizer.Add( left_pnl )
38 frmPnl_horzSizer.Add( right_pnl )
39
40 frm_pnl.SetSizer( frmPnl_horzSizer )
41 frm_pnl.Layout()
42
43 #end __init__ def
44
45 #end AppFrame class
46
47 #==============================================================================
48
49 myApp = wx.App( redirect=False )
50 AppFrame().Show()
51 myApp.MainLoop()
No size or position parameters are given because it's the sizer's job to set these.The flag=wx.EXPAND parameter has intentionally been left out to show what happens :
This is definitely not what is wanted. But, the two panels are visible, barely, and the blue right-side one is not on top of the left-side green, which is what would have happened if one or both panels were not added to the sizer. Most controls do not have a "best minimum" size. A few controls, such as wx.Buttons and wx.StaticTexts appropriately "self-size" themselves, so to speak.. On MS Windows platforms a control such as a wx.Panel which has not had its size defined will be reduced to a 20 pixel square. That's much better for debugging purposes than it being reduced to a 0 by 0 sized invisible square.
Now wx.EXPAND (wx.GROW) parameters can be given in the .Add() statements. Keep in mind that wx.EXPAND affects only the minor axis and that the sizer is wx.HORIZONTAL.
And there we have it ! Well... not quite. The panels did get wx.EXPANDed along the sizer's minor axis. But, exactly how is expansion along the major axis done ? This is the function of the proportion= argument that we have already seen. Since the panels are supposed to end up the same size, the integer values for the proportion= parameters need to be the same positive value. But, which integer value should be chosen ? Any value >= 1 will work. However, in an effort to promote overall coding clarity the value 1 should be used so that anyone, including yourself, who reads the code at a later time will be able to immediately understand what is the intention of this parameter value.
That's better ! Try resizing the frame horizontally to see how the sizer constantly maintains the panels' width ratio 1:1.
It's time to apply everything we've learned so far to the single-sizer/two-panel frame above. Border padding and spacers will be used achieve this appearance :
You can match up my annotations added in the following screen shot to the actual demo code.
To show how accurate how accurate is the BoxSizer's proportional allocation of horizontal room the demo above has been modified to calculate the two panel's width given the client width and the three fixed spacers. The caculations follow the formulas :
alreadyAllocatedSpace = 2*leftAndRightSpacing - middleSpacing
allocatableSpace = clientWidth - alreadyAllocatedSpace
leftControlWidth = allocatableSpace * (winLeft_horzProp / (winLeft_horzProp + winRight_horzProp))
rightControlWidth = allocatableSpace * (winRight_horzProp / (winLeft_horzProp + winRight_horzProp))
Here's some test calculation output using the demo's sizers and controls. The actual widths the sizer sets to the panels are always within 1 pixel of test program's calculated widths. This proves that the sizer is doing its proportional size allocations properly.
More Complicated Layouts
Many page layouts need to be much more complicated than this. They can be very, very complicated when an intricate display is needed. This requires using multiple sizers.