dSizer lays out your UI elements along a one-dimensional arrangement. As a result, their key property is
Orientation, which can be either
Vertical. Objects controlled by the sizer are sized and positioned according to the values set when they are added to the sizer.
Sizers can be nested within other sizers to create very complex layouts.
Sizers are not actual physical objects in the UI; rather, they are best thought of as hierarchical rules that govern the layout of forms in the UI. Controls are physically contained by the form in which they are created, and some controls, such as dPanel, can contain other controls. Sizers are not a part of this containership. Rather, they are assigned to a container in order to govern how the objects contained within are to be positioned and sized. When a container receives a Resize message, it tells its Sizer to re-calculate the size and position of the items under its control to fit the new container size.
dForm and dPanel are both containers for other controls. Remember that a dPanel is required on Windows as the "background" of a form in order for the form to look "normal". A dPanel is also helpful in arranging controls into logical groupings. But having to physically define the position of every control to be placed on screen is a real pain. Particularly when you then want to run your program on another computer which has a different screen resolution or your friend wants to run it with the window at a different size. The look of the screen goes berzerk! (Other language that should not be spoken could also be used to describe the frustration of trying to make your window look the way that you had intended.)
It is to fight this battle that Sizers are such an important part of writing GUI programs. It does take a bit of work to become fluent with them, but it is well worth the effort. You will be rewarded a thousand fold over the next few years!
Example: Create two panels. One without a sizer, one with a sizer, and add a control to each(in this case just a simple label).
import dabo dabo.ui.loadUI("wx") class MainForm(dabo.ui.dForm): def afterInit(self): # Create an initial sizer to add to sz = self.Sizer = dabo.ui.dSizer("vertical") # Create a panel and add a control (in this case a label) by position pnl = dabo.ui.dPanel(self, BackColor=(255,200,200)) pnl.addObject(dabo.ui.dLabel, Name="MyLabel", Caption="I am a Label on the panel at \n position (100,40)", FontSize=18, Position=(100,40) ) # Create another panel and add a control to a sizer ! <<< Better ! pnl2 = dabo.ui.dPanel(self, BackColor="yellow") pz = pnl2.Sizer = dabo.ui.dSizer("vertical") pnllabel2 = dabo.ui.dLabel(pnl2, FontSize=14, Caption="I am a label working under sizer rules that belong to the lower panel !") pz.append(pnllabel2, layout="expand", proportion=1) # add the panels to the sizer sz.append(pnl, "expand", proportion=1) sz.append1x(pnl2) # Shorthand for writing almost the same as the last line # run the program and see how differently the two labels are treated. sz.layout() if __name__ == "__main__": app = dabo.dApp() app.MainFormClass = MainForm app.start()
Did you run that example? The two labels are treated very differently, all because the second one had the advantage of a sizer ! The Sizer stores a bunch of rules about how to display (layout) your controls on the screen. The Sizer is not the parent of your control. It is the containing object that is the parent to your control. The first containing object is the Form, and the one after that is probably going to be a panel. And you may well want to use more than one panel on a professional looking page. You can set your controls in place with fixed dimensions, but life is much happier when you use another sizer.
Example of how to add a sizer to a panel:
#!/usr/bin/env python # -*- coding: utf-8 -*- """ This sample code demonstrates how to add a sizer to a panel. In this example we create a dForm (MainForm) with a dSizer. On to this we add a dPanel (pnl), and a dSizer (psz). On to this we add two labels as examples of controls that could be added. """ import dabo dabo.ui.loadUI("wx") class MainForm(dabo.ui.dForm): def afterInit(self): self.Sizer = dabo.ui.dSizer("v") # self (MainForm) is the parent(containing object)using the property .Sizer pnl = self.Panel = dabo.ui.dPanel(self, BackColor="Yellow", FontSize=18) psz = pnl.Sizer = dabo.ui.dSizer("h") # pan.Sizer is the property to which this sizer is assigned lab1 = dabo.ui.dLabel(pnl, Caption="One") # pan= self.Panel is the parent(containing object) # the sizer is not the parent. It is the parent's rules. lab2 = dabo.ui.dLabel(pnl, Caption="Two") """In a typical family Dad, Mum and the kids live in a home. The kids (children) belong to Dad & Mum (the Parents), and the Parents set the rules for how the children will behave. Sizer is a property of any Containing Object, which 'stores the Rules' for how the child objects will be displayed (layed out). """ psz.append1x(lab1) # append the controls to the sizer which controls their layout psz.append1x(lab2) # Note that append1x is a nice shortcut command self.Sizer.append1x(pnl) # add the panel to the containing objects Sizer """Then use either the controlling sizer or the Containing object to apply the layout rules""" self.layout() # Apply the containing object layout rules #self.Sizer.layout() # or we could have used the controlling sizer layout rules. if __name__ == "__main__": app = dabo.dApp() app.MainFormClass = MainForm app.start()
It is best practice to use the containing object way of expressing the layout command as it is valid in all circumstances, regardless of whether a sizer was involved or not.
You only need to call
layout() for your Form. The effect of applying the rules will cascade down to all of its sizer's contained controls and their sizers, and essentially layout everything.
There are times when you would call the
layout() method of an inner container object / sizer...
This is normally done if you are updating the controls in a particular sizer. For example, suppose you have controls to take a pounds and ounces or kilograms input. The user can select the input that they want. On a selection change, you would hide the one set of controls and show the other set. Since the controls are taking up the same amount of space in the parent sizer, you only need to render the sizer that has these controls on it.
Another example is using a dPageFrameNoTabs control and rendering each page initially when it's shown. This approach helps speed up the initial form loading greatly.
So in the example above, you might want to call the panels
layout() method if you were further along in your program and just making changes to that one panel. E.g.
"""Then use either the controlling sizer or the Containing object to apply the layout rules""" #Change some control here, then... pnl.layout() # Containing Object or #psz.layout() # Controlling Sizer would have also been valid