Programming with Sizers

team bbl


To create a sizer-based layout, create a top-level sizer (any kind of sizer may be used) and associate it with the parent window with wxWindow::SetSizer. Now you can hang your hierarchy of windows and further sizers from the top-level sizer. If you want the top-level window to fit itself around the contents, you call wxSizer::Fit passing the top-level window. If the window should never be resized smaller than the initial size, call wxSizer::SetSizeHints passing the top-level window. This will call wxWindow::SetSizeHints with the appropriate values.

Instead of the three functions described in the previous paragraph, you can simply call the function wxWindow::SetSizerAndFit, which sets the sizer, calls Fit, and also calls SetSizeHints.

If you have a panel inside a frame, you may be wondering which window gets the top-level sizer. Assuming you only have one panel in the frame, the frame already knows how to size the panel to fill the frame's client area when the frame size is changed. Therefore, you should set the sizer for the panel to manage the panel's children. If you had more than one panel in the frame, you might set a top-level sizer for the frame, which would manage the frame's children. However, you would still need a top-level sizer for each child panel that had its own children to lay out.

The following sections describe each kind of sizer and how to use it.

Programming with wxBoxSizer

wxBoxSizer can lay out its children either vertically or horizontally, depending on the style passed to its constructor. When using a vertical sizer, each child can be centered, aligned to the right, or aligned to the left. Correspondingly, when using a horizontal sizer, each child can be centered, aligned at the bottom, or aligned at the top. The stretch factor described previously is used for the main orientation, so when using a horizontal box sizer, the stretch factor determines how much the child can be stretched horizontally. Figure 7-7 shows the same dialog as in Figure 7-6, except that the sizer is a vertical box sizer.

Figure 7-7. A verical wxBoxSizer


You add child elements to a box sizer with Add:

 // Add a window void Add(wxWindow* window, int stretch = 0, int flags = 0,          int border = 0); // Add a sizer void Add(wxSizer* window, int stretch = 0, int flags = 0,          int border = 0); 

The first parameter is a window or sizer.

The second is the proportion or stretch factor.

The third parameter is a bit-list specifying alignment behavior and borders. The alignment flags specify what happens when a vertical sizer changes its width, or when a horizontal sizer changes its height. The allowed values for specifying alignment and borders are shown in Table 7-1. The default alignment is wxALIGN_LEFT | wxALIGN_TOP.

Table 7-1. Sizer Flags

0

Indicates that the window will preserve its original size.

wxGROW

Forces the window to grow with the sizer. wxEXPAND is a synonym for wxGROW.

wxSHAPED

Tells the window to change its size proportionally, preserving the original aspect ratio.

wxALIGN_LEFT

Aligns to the left edge of the sizer.

wxALIGN_RIGHT

Aligns to the right edge of the sizer.

wxALIGN_TOP

Aligns to the top edge of the sizer.

wxALIGN_BOTTOM

Aligns to the bottom edge of the sizer.

wxALIGN_CENTER_HORIZONTAL

Centers horizontally.

wxALIGN_CENTER_VERTICAL

Centers vertically.

wxALIGN_CENTER

Centers both horizontally and vertically. Defined as wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL.

wxLEFT

Specifies a border on the left edge of the element.

wxRIGHT

Specifies a border on the right edge of the element.

wxTOP

Specifies a border on the top edge of the element.

wxBOTTOM

Specifies a border on the bottom edge of the element.

wxALL

Specifies a border on all edges of the element. Defined as wxLEFT | wxRIGHT | wxTOP | wxBOTTOM.


The fourth parameter specifies the size of the border (on the edges that have been specified in the flags parameter).

You can also add a spacer. There are three ways to do this:

 // Add a spacer (old method) void Add(int width, int height, int stretch = 0, int flags = 0,          int border = 0); // Add a fixed-size spacer void AddSpacer(int size); // Add a stretching spacer void AddStretchSpacer(int stretch = 1); 

The second method is the equivalent of calling Add(size, size, 0), and the third method is equivalent to calling Add(0, 0, stretch).

As an example, we will construct a dialog that will contain a text field at the top and two buttons at the bottom. This can be seen at the top level as a column with the text at the top and buttons at the bottom, and at the second level as a row with an OK button to the left and a Cancel button to the right. In many cases, the main window will be resizable by the user, and this change of size will have to be propagated to its children. Here, we want the text area to grow with the dialog, whereas the buttons should have a fixed size. In addition, the buttons will be centered as the width of the dialog changes. Figure 7-8 shows how it will look.

Figure 7-8. A simple dialog using sizers


Here's the code that produces this dialog:

 // A dialog with a stretching text control MyDialog::MyDialog(wxWindow *parent, wxWindowID id,                      const wxString &title )         :  wxDialog(parent, id, title,                      wxDefaultPosition, wxDefaultSize,                      wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {     wxBoxSizer  *topSizer = new wxBoxSizer( wxVERTICAL );     // Create text ctrl with minimal size 100x60     topSizer->Add(         new wxTextCtrl( this, wxID_ANY, "My text.",             wxDefaultPosition, wxSize(100,60), wxTE_MULTILINE),         1,         // make vertically stretchable         wxEXPAND|  // make horizontally stretchable         wxALL,     // and make border all around         10 );      // set border width to 10     wxBoxSizer *buttonSizer = new wxBoxSizer( wxHORIZONTAL );     buttonSizer->Add(        new wxButton( this, wxID_OK, "OK" ),        0,          // make horizontally unstretchable        wxALL,     // make border all around: implicit top alignment        10 );      // set border width to 10     buttonSizer->Add(        new wxButton( this, wxID_CANCEL, "Cancel" ),        0,         // make horizontally unstretchable        wxALL,     // make border all around (implicit top alignment)        10 );      // set border width to 10     topSizer->Add(        buttonSizer,        0,                // make vertically unstretchable        wxALIGN_CENTER ); // no border and centre horizontally     SetSizer( topSizer ); // use the sizer for layout     topSizer->Fit( this );          // fit the dialog to the contents     topSizer->SetSizeHints( this ); // set hints to honor min size } 

Programming with wxStaticBoxSizer

wxStaticBoxSizer is a sizer derived from wxBoxSizer that manages a static box around the sizer. Note that this static box has to be created separately. Create wxStaticBoxSizer by passing a pointer to the static box and the orientation (wxHORIZONTAL or wxVERTICAL). The Add function is the same as for wxBoxSizer.

Figure 7-9 shows an example of a dialog with a static box containing a check box control.

Figure 7-9. A wxStaticBoxSizer


Here's the corresponding code:

 MyDialog::MyDialog(wxWindow *parent, wxWindowID id,                    const wxString &title )         : wxDialog(parent, id, title,                    wxDefaultPosition, wxDefaultSize,                    wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {     // Create top-level sizer     wxBoxSizer* topLevel = new wxBoxSizer(wxVERTICAL);     // Create static box and static box sizer     wxStaticBox* staticBox = new wxStaticBox(this,         wxID_ANY, wxT("General settings"));     wxStaticBoxSizer* staticSizer = new wxStaticBoxSizer(staticBox,         wxVERTICAL);     topLevel->Add(staticSizer, 0,         wxALIGN_CENTER_HORIZONTAL|wxALL, 5);     // Create a check box inside the static box sizer     wxCheckBox* checkBox = new wxCheckBox( this, ID_CHECKBOX,         wxT("&Show splash screen"), wxDefaultPosition, wxDefaultSize);     staticSizer->Add(checkBox, 0, wxALIGN_LEFT |wxALL, 5);     SetSizer(topLevel);     topLevel->Fit(this);     topLevel->SetSizeHints(this); } 

Programming with wxGridSizer

wxGridSizer is a sizer that lays out its children in a two-dimensional table with all table fields having the same size; that is, the width of each field is the width of the widest child, and the height of each field is the height of the tallest child. Create a wxGridSizer by passing the number of rows, number of columns, extra vertical gap between children, and extra horizontal gap between children. Add is the same as for wxBoxSizer.

Figure 7-10 shows a grid sizer with three columns and two rows. The extra size of the second button has caused the space occupied by all the buttons to increase because all the cells of a wxGridSizer are the same size.

Figure 7-10. A wxGridSizer


Here's the code:

 MyDialog::MyDialog(wxWindow *parent, wxWindowID id,                    const wxString &title )         : wxDialog(parent, id, title,                    wxDefaultPosition, wxDefaultSize,                    wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {     // Create top-level grid sizer     wxGridSizer* gridSizer = new wxGridSizer(2, 3, 0, 0);     SetSizer(gridSizer);     wxButton* button1 = new wxButton(this, ID_BUTTON1, wxT("One"));     gridSizer->Add(button1, 0, wxALIGN_CENTER_HORIZONTAL|                                wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button2 = new wxButton(this, ID_BUTTON2, wxT("Two (the second button)"));     gridSizer->Add(button2, 0, wxALIGN_CENTER_HORIZONTAL|                                wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button3 = new wxButton(this, ID_BUTTON3, wxT("Three"));     gridSizer->Add(button3, 0, wxALIGN_CENTER_HORIZONTAL|                                wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button4 = new wxButton(this, ID_BUTTON4, wxT("Four"));     gridSizer->Add(button4, 0, wxALIGN_CENTER_HORIZONTAL|                                wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button5 = new wxButton(this, ID_BUTTON5, wxT("Five"));     gridSizer->Add(button5, 0, wxALIGN_CENTER_HORIZONTAL|                                wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button6 = new wxButton(this, ID_BUTTON6, wxT("Six"));     gridSizer->Add(button6, 0, wxALIGN_CENTER_HORIZONTAL|                                wxALIGN_CENTER_VERTICAL|wxALL, 5);     gridSizer->Fit(this);     gridSizer->SetSizeHints(this); } 

Programming with wxFlexGridSizer

wxFlexGridSizer is a sizer that lays out its children in a two-dimensional table with all table fields in one row having the same height and all fields in one column having the same width. However, unlike wxGridSizer, all rows or all columns are not necessarily the same height or width: this will depend on the size of elements in a row or column. Additionally, columns and rows can be declared to be stretchable, which means that as the sizer is expanded, these columns or rows will be allocated extra space.

Create a wxFlexGridSizer by passing the number of rows, number of columns, extra vertical gap between children, and extra horizontal gap between children. Add is the same as for wxBoxSizer.

Figure 7-11 shows a flex grid sizer at its initial size, where the first column has been made stretchable. It's essentially the same as the wxGridSizer example, but as you can see, the layout is more compact because the size of the middle column is not reflected in the other columns.

Figure 7-11. A wxFlexGridSizer at its initial size


Initially, we don't see the effect of making the first column stretchable, but if we stretch it horizontally, as in Figure 7-12, we can see this column (containing buttons One and Four) taking up the extra space, with the buttons centered in the column.

Figure 7-12. A resized wxFlexGridSizer


Here's the code that creates the dialogs we've shown:

 MyDialog::MyDialog(wxWindow *parent, wxWindowID id,                    const wxString &title )         : wxDialog(parent, id, title,                    wxDefaultPosition, wxDefaultSize,                    wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {     // Create top-level flex grid sizer     wxFlexGridSizer* flexGridSizer = new wxFlexGridSizer(2, 3, 0, 0);     this->SetSizer(flexGridSizer);     // Make the 1st row growable     flexGridSizer->AddGrowableCol(0);     wxButton* button1 = new wxButton(this, ID_BUTTON1, wxT("One"));     flexGridSizer->Add(button1, 0, wxALIGN_CENTER_HORIZONTAL|                                    wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button2 = new wxButton(this, ID_BUTTON2, wxT("Two (the second button)"));     flexGridSizer->Add(button2, 0, wxALIGN_CENTER_HORIZONTAL|                                    wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button3 = new wxButton(this, ID_BUTTON3, wxT("Three"));     flexGridSizer->Add(button3, 0, wxALIGN_CENTER_HORIZONTAL|                                    wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button4 = new wxButton(this, ID_BUTTON4, wxT("Four"));     flexGridSizer->Add(button4, 0, wxALIGN_CENTER_HORIZONTAL|                                    wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button5 = new wxButton(this, ID_BUTTON5, wxT("Five"));     flexGridSizer->Add(button5, 0, wxALIGN_CENTER_HORIZONTAL|                                    wxALIGN_CENTER_VERTICAL|wxALL, 5);     wxButton* button6 = new wxButton(this, ID_BUTTON6, wxT("Six"));     flexGridSizer->Add(button6, 0, wxALIGN_CENTER_HORIZONTAL|                                    wxALIGN_CENTER_VERTICAL|wxALL, 5);     flexGridSizer->Fit(this);     flexGridSizer->SetSizeHints(this); } 

Programming with wxGridBagSizer

This sizer attempts to reconcile the worlds of absolute positioning and sizer-based layout. It can lay out elements in a virtual grid, like a flex grid sizer, but in this case item row and column positions are specified using wxGBPosition, and items can optionally span more than one row and/or column using wxGBSpan.

When creating a wxGridBagSizer, optionally pass sizers for vertical and horizontal gaps between rows and columns (defaulting to zero). Use the Add function to add windows or sizers, passing the position and optional span, plus optional flags and border size as for wxBoxSizer.

Figure 7-13 shows a simple grid bag sizer example with four buttons, one of them spanning two columns (button Two). We also specify that the second row and third column are growable so that when we resize the dialog, we get the effect shown in Figure 7-14.

Figure 7-13. A wxGridBagSizer at its original size


Figure 7-14. A wxGridBagSizer after resizing


Here's the code that produces this layout:

 MyDialog::MyDialog(wxWindow *parent, wxWindowID id,                    const wxString &title )         : wxDialog(parent, id, title,                    wxDefaultPosition, wxDefaultSize,                    wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {     wxGridBagSizer* gridBagSizer = new wxGridBagSizer();     SetTopSizer(gridBagSizer);     wxButton* b1 = new wxButton(this, wxID_ANY, wxT("One (0,0)"));     gridBagSizer->Add(b1, wxGBPosition(0, 0));     wxButton* b2 = new wxButton(this, wxID_ANY, wxT("Two (2,2)"));     gridBagSizer->Add(b2, wxGBPosition(2, 2), wxGBSpan(1, 2),                       wxGROW);     wxButton* b3 = new wxButton(this, wxID_ANY, wxT("Three (3,2)"));     gridBagSizer->Add(b3, wxGBPosition(3, 2));     wxButton* b4 = new wxButton(this, wxID_ANY, wxT("Four (3,3)"));     gridBagSizer->Add(b4, wxGBPosition(3, 3));     gridBagSizer->AddGrowableRow(3);     gridBagSizer->AddGrowableCol(2);     gridBagSizer->Fit(this);     gridBagSizer->SetSizeHints(this); } 

    team bbl



    Cross-Platform GUI Programming with wxWidgets
    Cross-Platform GUI Programming with wxWidgets
    ISBN: 0131473816
    EAN: 2147483647
    Year: 2005
    Pages: 262

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net