| 1 | \section{Constraints overview}\label{constraintsoverview} |
| 2 | |
| 3 | Classes: \helpref{wxLayoutConstraints}{wxlayoutconstraints}, \helpref{wxIndividualLayoutConstraint}{wxindividuallayoutconstraint}. |
| 4 | |
| 5 | {\bf Note:} constraints are now deprecated and you should use \helpref{sizers}{sizeroverview} instead. |
| 6 | |
| 7 | Objects of class wxLayoutConstraint can be associated with a window to define |
| 8 | the way it is laid out, with respect to its siblings or the parent. |
| 9 | |
| 10 | The class consists of the following eight constraints of class wxIndividualLayoutConstraint, |
| 11 | some or all of which should be accessed directly to set the appropriate |
| 12 | constraints. |
| 13 | |
| 14 | \begin{itemize}\itemsep=0pt |
| 15 | \item {\bf left:} represents the left hand edge of the window |
| 16 | \item {\bf right:} represents the right hand edge of the window |
| 17 | \item {\bf top:} represents the top edge of the window |
| 18 | \item {\bf bottom:} represents the bottom edge of the window |
| 19 | \item {\bf width:} represents the width of the window |
| 20 | \item {\bf height:} represents the height of the window |
| 21 | \item {\bf centreX:} represents the horizontal centre point of the window |
| 22 | \item {\bf centreY:} represents the vertical centre point of the window |
| 23 | \end{itemize} |
| 24 | |
| 25 | The constraints are initially set to have the relationship wxUnconstrained, |
| 26 | which means that their values should be calculated by looking at known constraints. |
| 27 | To calculate the position and size of the control, the layout algorithm needs to |
| 28 | know exactly 4 constraints (as it has 4 numbers to calculate from them), so you |
| 29 | should always set exactly 4 of the constraints from the above table. |
| 30 | |
| 31 | If you want the controls height or width to have the default value, you may use |
| 32 | a special value for the constraint: wxAsIs. If the constraint is wxAsIs, the |
| 33 | dimension will not be changed which is useful for the dialog controls which |
| 34 | often have the default size (e.g. the buttons whose size is determined by their |
| 35 | label). |
| 36 | |
| 37 | The constrains calculation is done in \helpref{wxWindow::Layout}{wxwindowlayout} |
| 38 | function which evaluates constraints. To call it you can either call |
| 39 | \helpref{wxWindow::SetAutoLayout}{wxwindowsetautolayout} if the parent window |
| 40 | is a frame, panel or a dialog to tell default OnSize handlers to call Layout |
| 41 | automatically whenever the window size changes, or override OnSize and call |
| 42 | Layout yourself (note that you do have to call |
| 43 | \helpref{Layout}{wxwindowlayout} yourself if the parent window is not a |
| 44 | frame, panel or dialog). |
| 45 | |
| 46 | \subsection{Constraint layout: more detail} |
| 47 | |
| 48 | By default, windows do not have a wxLayoutConstraints object. In this case, much layout |
| 49 | must be done explicitly, by performing calculations in OnSize members, except |
| 50 | for the case of frames that have exactly one subwindow (not counting toolbar and |
| 51 | statusbar which are also positioned by the frame automatically), where wxFrame::OnSize |
| 52 | takes care of resizing the child to always fill the frame. |
| 53 | |
| 54 | To avoid the need for these rather awkward calculations, the user can create |
| 55 | a wxLayoutConstraints object and associate it with a window with wxWindow::SetConstraints. |
| 56 | This object contains a constraint for each of the window edges, two for the centre point, |
| 57 | and two for the window size. By setting some or all of these constraints appropriately, |
| 58 | the user can achieve quite complex layout by defining relationships between windows. |
| 59 | |
| 60 | In wxWidgets, each window can be constrained relative to either its {\it |
| 61 | siblings} on the same window, or the {\it parent}. The layout algorithm |
| 62 | therefore operates in a top-down manner, finding the correct layout for |
| 63 | the children of a window, then the layout for the grandchildren, and so |
| 64 | on. Note that this differs markedly from native Motif layout, where |
| 65 | constraints can ripple upwards and can eventually change the frame |
| 66 | window or dialog box size. We assume in wxWidgets that the {\it user} is |
| 67 | always `boss' and specifies the size of the outer window, to which |
| 68 | subwindows must conform. Obviously, this might be a limitation in some |
| 69 | circumstances, but it suffices for most situations, and the |
| 70 | simplification avoids some of the nightmarish problems associated with |
| 71 | programming Motif. |
| 72 | |
| 73 | When the user sets constraints, many of the constraints for windows |
| 74 | edges and dimensions remain unconstrained. For a given window, |
| 75 | the wxWindow::Layout algorithm first resets all constraints |
| 76 | in all children to have unknown edge or dimension values, and then iterates through the constraints, |
| 77 | evaluating them. For unconstrained edges and dimensions, it |
| 78 | tries to find the value using known relationships that always hold. For example, |
| 79 | an unconstrained {\it width} may be calculated from the {\it left} and {\it right edges}, if |
| 80 | both are currently known. For edges and dimensions with user-supplied constraints, these |
| 81 | constraints are evaluated if the inputs of the constraint are known. |
| 82 | |
| 83 | The algorithm stops when all child edges and dimension are known (success), or |
| 84 | there are unknown edges or dimensions but there has been no change in this cycle (failure). |
| 85 | |
| 86 | It then sets all the window positions and sizes according to the values it has found. |
| 87 | |
| 88 | Because the algorithm is iterative, the order in which constraints are considered is |
| 89 | irrelevant, however you may reduce the number of iterations (and thus speed up |
| 90 | the layout calculations) by creating the controls in such order that as many |
| 91 | constraints as possible can be calculated during the first iteration. For example, if |
| 92 | you have 2 buttons which you'd like to position in the lower right corner, it is |
| 93 | slightly more efficient to first create the second button and specify that its |
| 94 | right border IsSameAs(parent, wxRight) and then create the first one by |
| 95 | specifying that it should be LeftOf() the second one than to do in a more |
| 96 | natural left-to-right order. |
| 97 | |
| 98 | \subsection{Window layout examples}\label{layoutexamples} |
| 99 | |
| 100 | \subsubsection{Example 1: subwindow layout} |
| 101 | |
| 102 | This example specifies a panel and a window side by side, |
| 103 | with a text subwindow below it. |
| 104 | |
| 105 | \begin{verbatim} |
| 106 | frame->panel = new wxPanel(frame, -1, wxPoint(0, 0), wxSize(1000, 500), 0); |
| 107 | frame->scrollWindow = new MyScrolledWindow(frame, -1, wxPoint(0, 0), wxSize(400, 400), wxRETAINED); |
| 108 | frame->text_window = new MyTextWindow(frame, -1, wxPoint(0, 250), wxSize(400, 250)); |
| 109 | |
| 110 | // Set constraints for panel subwindow |
| 111 | wxLayoutConstraints *c1 = new wxLayoutConstraints; |
| 112 | |
| 113 | c1->left.SameAs (frame, wxLeft); |
| 114 | c1->top.SameAs (frame, wxTop); |
| 115 | c1->right.PercentOf (frame, wxWidth, 50); |
| 116 | c1->height.PercentOf (frame, wxHeight, 50); |
| 117 | |
| 118 | frame->panel->SetConstraints(c1); |
| 119 | |
| 120 | // Set constraints for scrollWindow subwindow |
| 121 | wxLayoutConstraints *c2 = new wxLayoutConstraints; |
| 122 | |
| 123 | c2->left.SameAs (frame->panel, wxRight); |
| 124 | c2->top.SameAs (frame, wxTop); |
| 125 | c2->right.SameAs (frame, wxRight); |
| 126 | c2->height.PercentOf (frame, wxHeight, 50); |
| 127 | |
| 128 | frame->scrollWindow->SetConstraints(c2); |
| 129 | |
| 130 | // Set constraints for text subwindow |
| 131 | wxLayoutConstraints *c3 = new wxLayoutConstraints; |
| 132 | c3->left.SameAs (frame, wxLeft); |
| 133 | c3->top.Below (frame->panel); |
| 134 | c3->right.SameAs (frame, wxRight); |
| 135 | c3->bottom.SameAs (frame, wxBottom); |
| 136 | |
| 137 | frame->text_window->SetConstraints(c3); |
| 138 | \end{verbatim} |
| 139 | |
| 140 | \subsubsection{Example 2: panel item layout} |
| 141 | |
| 142 | This example sizes a button width to 80 percent of the panel width, and centres |
| 143 | it horizontally. A listbox and multitext item are placed below it. The listbox |
| 144 | takes up 40 percent of the panel width, and the multitext item takes up |
| 145 | the remainder of the width. Margins of 5 pixels are used. |
| 146 | |
| 147 | \begin{verbatim} |
| 148 | // Create some panel items |
| 149 | wxButton *btn1 = new wxButton(frame->panel, -1, "A button") ; |
| 150 | |
| 151 | wxLayoutConstraints *b1 = new wxLayoutConstraints; |
| 152 | b1->centreX.SameAs (frame->panel, wxCentreX); |
| 153 | b1->top.SameAs (frame->panel, wxTop, 5); |
| 154 | b1->width.PercentOf (frame->panel, wxWidth, 80); |
| 155 | b1->height.PercentOf (frame->panel, wxHeight, 10); |
| 156 | btn1->SetConstraints(b1); |
| 157 | |
| 158 | wxListBox *list = new wxListBox(frame->panel, -1, "A list", |
| 159 | wxPoint(-1, -1), wxSize(200, 100)); |
| 160 | |
| 161 | wxLayoutConstraints *b2 = new wxLayoutConstraints; |
| 162 | b2->top.Below (btn1, 5); |
| 163 | b2->left.SameAs (frame->panel, wxLeft, 5); |
| 164 | b2->width.PercentOf (frame->panel, wxWidth, 40); |
| 165 | b2->bottom.SameAs (frame->panel, wxBottom, 5); |
| 166 | list->SetConstraints(b2); |
| 167 | |
| 168 | wxTextCtrl *mtext = new wxTextCtrl(frame->panel, -1, "Multiline text", "Some text", |
| 169 | wxPoint(-1, -1), wxSize(150, 100), wxTE_MULTILINE); |
| 170 | |
| 171 | wxLayoutConstraints *b3 = new wxLayoutConstraints; |
| 172 | b3->top.Below (btn1, 5); |
| 173 | b3->left.RightOf (list, 5); |
| 174 | b3->right.SameAs (frame->panel, wxRight, 5); |
| 175 | b3->bottom.SameAs (frame->panel, wxBottom, 5); |
| 176 | mtext->SetConstraints(b3); |
| 177 | \end{verbatim} |
| 178 | |
| 179 | |