tag:blogger.com,1999:blog-12004822274476408532024-02-20T07:33:42.026-08:00Layout Manager for Dialogs, Formviews, DialogBarsLinuxhttp://www.blogger.com/profile/01020619507546589145noreply@blogger.comBlogger1125tag:blogger.com,1999:blog-1200482227447640853.post-81421775085163835562009-05-08T09:35:00.000-07:002009-05-08T09:36:41.929-07:00THE CODE PROCET BEGINNER<p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr1.gif" alt="Sample Image" width="480" height="370" /></p> <h2>Introduction:</h2> <p>If you often use Dialogs and want to resize them you will have noticed that there is no feature in MFC that helps you arranging the dialog controls automatically after resizing. You have to do it by hand. Maybe you have seen some layouting mechanism in other languages (like Java) - then this one will look familiar to you.</p> <p>I will mostly refer to Dialogs, but this code can be used to layout any <code>CWnd</code>. Currently these classes/features are supported:</p><ul><li>Dialog</li><li>FormView</li><li>PropertySheet/Page</li><li>DialogBars (for the DialogBar support you have to use the <a href="http://msnhomepages.talkcity.com/WindowsWay/stasl/index.html">BCGControlBar Library</a>. You will need a Version higher than 4.52.</li><li>support for CTabCtrl and CStatic (groupbox)</li><li>sizing gripper (as the ones found in FrameWindows) <i>[optional]</i></li><li>constraint handling (automatic min/max tracking size handling)</li><li>almost no flicker on resizing</li><li>automatic re-/storage of windowsizes in the registry <i>[optional]</i></li></ul> <h2>General Usage:</h2> <p>This section will briefly describe how to incorporate Layout Management into your code. For a full description of the Layout Manager look at the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#orientation">later sections</a>.</p><ol><li><b>Include Files</b><p>First of all you need to include the headers. These are all located in the file <code>ETSLayout.h</code>. It's best to include it directly in your <code>stdafx.h</code>. All the classes are defined in the namespace 'ETSLayout', therefore it is suggested that you add the following line just below the <code><span class="code-preprocessor">#include</span><span class="code-preprocessor"></span></code> : </p> <div class="SmallText" id="premain0" style="width: 100%; cursor: pointer;"><img preid="0" src="http://www.codeproject.com/images/minus.gif" id="preimg0" width="9" height="9" /><span preid="0" style="margin-bottom: 0pt;" id="precollapse0"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre0">...<br /><span class="code-preprocessor">#include</span><span class="code-preprocessor"> <span class="code-string">"</span><span class="code-string">ETSLayout.h"</span><br /></span><br /><span class="code-keyword">using</span> <span class="code-keyword">namespace</span> ETSLayout;<br />...<br /></pre> <p>You also need to include the file <code>ETSLayout.cpp</code> to your project in order to use the classes. Do this directly from DevStudio under <b>Project > Add to Project > Files</b>. </p> </li><li><b>Change Baseclass</b><p>Let's say you want your Dialog <code>CMyDialog</code> to be resizable. Then you will have to change the baseclass of <code>CMyDialog</code> to <code>ETSLayoutDialog</code>. e.g. If <code>CMyDialog</code> is derived from <code>CDialog</code> you will just have to replace all occurrences of <code>CDialog</code> with <code>ETSLayoutDialog</code> </p><p>If you want to add a new resizable Dialog just add it as a normal <code>CDialog</code> and change the baseclass later as described above.</p> <p>The <code>WS_THICKFRAME</code> style is added automatically in <code>ETSLayoutDialog::OnInitDialog</code>, in case you forgot to give the dialog a resizable border in the resource editor.</p> </li><li><b><a name="sample">Define the Layout</a></b><p>Now comes the really important step: You will have to define the actual layout. This will describe the way you want the dialog items to be resized and arranged.</p> <p>In fact there are two different interfaces to define the layout. These will be described later in the reference section. I will show you the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#stream">Stream Interface</a> here.</p> <p>On the left side you see the dialog and all the control IDs that you want to define the layout for. On the right side you will find the proposed panes. You will notice that all vertical panes are marked red whereas all horizontal panes are blue.</p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr2.gif" alt="Sample Dialog IDs" width="287" height="284" /> <img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr3.gif" alt="Sample Dialog Panes" width="287" height="284" /></p> <p>Usually you define the layout in you dialog's <code>OnInitDialog()</code>-Handler. The first step is to create the Root Pane. In this case we need a <code>VERTICAL</code> one as the subpanes on the first level are <code>HORIZONTAL</code>. <b>Note that there is no semicolon at the end of the line as we will add items to the Root Pane with the streaming <code><span class="code-keyword">operator</span><span class="code-keyword"><</span><span class="code-keyword"><</span>()</code></b>.</p> <div class="SmallText" id="premain1" style="width: 100%; cursor: pointer;"><img preid="1" src="http://www.codeproject.com/images/minus.gif" id="preimg1" width="9" height="9" /><span preid="1" style="margin-bottom: 0pt;" id="precollapse1"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre1">BOOL CMyDialog::OnInitDialog()<br />{<br /> ETSLayoutDialog::OnInitDialog();<br /> <br /> <span class="code-comment">//</span><span class="code-comment"> define the Layout<br /></span><br /> CreateRoot(VERTICAL)<br /></pre> <p>The first Item we want to add is <code>IDC_NEW_ITEM_STATIC</code>, the topmost subitem of the Root Pane. As this is a simple static (text) we don't need to resize this item. Therefore it gets the resizing mode <code>NORESIZE</code>. For access to the root pane use the return value of <code>CreateRoot()</code> or the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#pointer">autopointer</a> <code>m_RootPane</code>:</p> <div class="SmallText" id="premain2" style="width: 100%; cursor: pointer;"><img preid="2" src="http://www.codeproject.com/images/minus.gif" id="preimg2" width="9" height="9" /><span preid="2" style="margin-bottom: 0pt;" id="precollapse2"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre2"> <span class="code-keyword"><</span><span class="code-keyword"><</span> item ( IDC_NEW_ITEM_STATIC, NORESIZE )<br /></pre> <p>The next two items (blue border) form a subpane, because we want them to be in one line (remember: the Root Pane is vertical, so all subpanes are horizontal). In the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#stream">Stream Interface</a> to the layout definition you have to add an open brace followed by a <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#pane">Pane creator function</a> (in this case <code>pane()</code>). All following items up to the closing brace are now placed into this subpane. We do want this subpane to expand horizontally, but the height should always stay the same (therefore the <code>ABSOLUTE_VERT</code> <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#resizing">Resizing Mode</a>). </p> <div class="SmallText" id="premain3" style="width: 100%; cursor: pointer;"><img preid="3" src="http://www.codeproject.com/images/minus.gif" id="preimg3" width="9" height="9" /><span preid="3" style="margin-bottom: 0pt;" id="precollapse3"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre3"> <span class="code-keyword"><</span><span class="code-keyword"><</span> ( pane(HORIZONTAL, ABSOLUTE_VERT )<br /></pre> <p>Here the horizontal subpane has just two items and no subpanes itself. The first item is the one we want to grow (the button shall stay at the right border). A <code>GREEDY</code> items uses as much space as it gets (it will share it equally with other <code>GREEDY</code> items, though. So if the next item is not sizable it will always be at the right border (as the first <code>GREEDY</code> one takes all the leftover space).</p> <div class="SmallText" id="premain4" style="width: 100%; cursor: pointer;"><img preid="4" src="http://www.codeproject.com/images/minus.gif" id="preimg4" width="9" height="9" /><span preid="4" style="margin-bottom: 0pt;" id="precollapse4"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre4"> <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_NEW_ITEM, GREEDY ) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_ADD_ITEM, NORESIZE )<br /></pre> <p>Note that <code>IDC_NEW_ITEM</code> will not be resized vertically because its parent pane has the <code>ABSOULUTE_VERT</code> <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#resizing">Resizing Mode</a>! Now the first subpane is complete and we can close the brace and thus end the definition of this subpane.</p> <div class="SmallText" id="premain5" style="width: 100%; cursor: pointer;"><img preid="5" src="http://www.codeproject.com/images/minus.gif" id="preimg5" width="9" height="9" /><span preid="5" style="margin-bottom: 0pt;" id="precollapse5"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre5"> )<br /></pre> <p>Next there is a simple static (text) item we have to add - you've seen that before...</p> <div class="SmallText" id="premain6" style="width: 100%; cursor: pointer;"><img preid="6" src="http://www.codeproject.com/images/minus.gif" id="preimg6" width="9" height="9" /><span preid="6" style="margin-bottom: 0pt;" id="precollapse6"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre6"> <span class="code-keyword"><</span><span class="code-keyword"><</span> item ( IDC_ITEM_LIST_STATIC, NORESIZE )<br /></pre> <p>Until now there were only items which either were not resizable at all or only in horizontal direction. If a dialog has only items of this kind, it won't be sizable in vertical direction at all! But in this example the next item (the listbox) can be resized in both horizontal and vertical direction. As in this case there is no limiting parent pane (in contrast to <code>IDC_NEW_ITEM</code> before) this item can be expanded vertically:</p> <div class="SmallText" id="premain7" style="width: 100%; cursor: pointer;"><img preid="7" src="http://www.codeproject.com/images/minus.gif" id="preimg7" width="9" height="9" /><span preid="7" style="margin-bottom: 0pt;" id="precollapse7"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre7"> <span class="code-keyword"><</span><span class="code-keyword"><</span> item ( IDC_ITEM_LIST, GREEDY )<br /></pre> <p>The last subpane is similar to the first one. If we want all the buttons on the right side there must be an item consuming all the remaining space to "push" the buttons to the right border. In this case there is no such item and that's where <code>itemGrowing()</code> comes into play. This adds the pseudopane (<code>paneNull</code>) that can always be used as a placeholder. It is not displayed nor is there any Control associated with it.</p> <p>The rest of this subpane is like the one above:</p> <div class="SmallText" id="premain8" style="width: 100%; cursor: pointer;"><img preid="8" src="http://www.codeproject.com/images/minus.gif" id="preimg8" width="9" height="9" /><span preid="8" style="margin-bottom: 0pt;" id="precollapse8"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre8"> <span class="code-keyword"><</span><span class="code-keyword"><</span> ( pane(HORIZONTAL, ABSOLUTE_VERT ) <span class="code-keyword"><</span><span class="code-keyword"><</span> itemGrowing( HORIZONTAL )<br /> <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDOK, NORESIZE ) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDCANCEL, NORESIZE ) );<br /></pre> <p>The definition of the layout is complete now. To activate the Layout you would have to call <code>UpdateLayout()</code> (if you don't call it the dialog will not be laid out until you resize it!)</p> <div class="SmallText" id="premain9" style="width: 100%; cursor: pointer;"><img preid="9" src="http://www.codeproject.com/images/minus.gif" id="preimg9" width="9" height="9" /><span preid="9" style="margin-bottom: 0pt;" id="precollapse9"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre9"> UpdateLayout();<br /> <span class="code-keyword">return</span> TRUE;<br />}<br /></pre> </li><li><b>Ready!</b><p>That's it: You just created a completely automatically laid-out dialog! Simple, isn't it? The only real thing to do is to define the layout correctly, which can be tricky for very complex layouts.</p> </li></ol> <h2><a name="orientation">Orientation:</a></h2> <p>The two orientations <code>HORIZONTAL</code> and <code>VERTICAL</code> for subpanes tell the LayoutManger how to add new items/subpane to that pane. For <code>HORIZONTAL</code> Panes all items are added from left to right. This however does <b>not</b> mean, that <code>HORIZONTAL</code> Panes are only horizontally sizable, it just refers to the orientation and direction in which items/subpanes are added! The orientation of a pane is also called its <i>primary direction</i></p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr4.gif" alt="HORIZONTAL" width="253" height="55" /></p> <h2><a name="resizing">Resize Modes:</a></h2> <p>The actual layout parameters are set for every item/subpane individually. The LayoutManager then composes all theses constraints into the global layout.</p> <p>There are numerous different Resizing Modes (or Layout Codes). Some of them may be used together with <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#alignment">Alignment Modes</a>. To combine the modes just use the <code>|</code> operator as in <code>NORESIZE | ALIGN_RIGHT</code>.</p> <p>The Resizing Modes are of type <code>layResizeMode</code>. In order to combine multiple modes with the <code>|</code>-operator I needed a little trick. Normally you can't just write <code>X | Y</code> if <code>X</code> and <code>Y</code> are enumerated types and the result has to be enumerated too. I could have used normal <code>DWORD</code> Values instead (internally they are handled like this anyway), but then I would have lost the static type checking for parameters. Therefore I just overloaded <code>layResizeMode operator|(layResizeMode X, layResizeMode Y)</code> to combine the <code>DWORD</code>-Values of <code>X</code> and <code>Y</code> with the standard <code>|</code>-operator and then casting the result back to <code>layResizeCode</code>.</p> <p>If you omit the Resizing Mode <code>GREEDY</code> is the default parameter. This means that by default the item/subpane grows into both orientations (horizontally and vertically).</p> <p>The explanations are mostly speaking of Items. This is for the sake of brevity. Of course the same is true for Subpanes. In fact the LayoutManager does not make a difference between Items and SubPanes because they both are derived from the same baseclass.</p> <p>Available space in primary direction is assigned in this order: </p><ol><li>First the space for all <code>ABSOLUTE_XXX</code> Items is subtracted from the available space. The <code>XXX</code> refers to the primary direction, i.e. <code>HORZ</code> when the Items are placed on a <code>HORIZONTAL</code> pane and analogous for <code>VERT</code> and <code>VERTICAL</code>. </li><li>Then all <code>RELATIVE_XXX</code> Items are taking their share of the remaining space (depending on the percentage value). Note that you should not add relative Items with a cumulated percentage of more than 100 :) </li><li>Lastly the remaining space is equally assigned to all <code>GREEDY</code> items. </li><li>It may happen (because of the constraints) that there is some space left over. In a fixup-step the LayoutManager tries to reassign this left over space. </li></ol> <h3><code>GREEDY</code> [default]</h3> <p>As already mentioned a greedy Item grows in both horizontal and vertical direction. If there is only one greedy Item in a pane it takes all the space that is left from other items. If there are multiple greedy items all the remaining space is equally distributed among them.</p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr5.gif" alt="GREEDY" width="247" height="49" /></p> <p>You may also use greedy items in combination with <code>paneNull</code> to fill up space (in order to keep some other items right or at the bottom).</p> <h3><code>ABSOLUTE_HORZ</code></h3> <p>If you want an Item not to change its horizontal extent you'll have to use this code. The current horizontal size as in the dialog template is used. Panes with this mode are calculating its initial horizontal extend based on its items.</p> <p>Note that panes with such a restriction will not allow items to be sized horizontally - even if these items themselves have the <code>GREEDY</code> Resize Mode. On the other hand a <code>GREEDY</code> pane with only <code>ABSOULTE_HORZ</code> items will not be able to resize itself horizontally either!</p> <h3><code>RELATIVE_HORZ</code></h3> <p>You may want some items which cover a certain percentage of available space. This is the Resize Mode you'll need to employ. When you use this Resize Mode you <b>must</b> supply a x-size for the item. The x-size is then interpreted as an percentage value (between 1 and 100), e.g. an x-size of 30 means that the item will take 30% of the available space in horizontal direction.</p> <p>To fill up the complete space you would either use a complementary sized <code>RELATIVE_HORZ</code> Item (e.g. if you have an 60% Item you would have to add an 40% Item) or just use a <code>GREEDY</code> Item which automatically fills the rest of the space</p> <p>Please note that an item with <code>RELATIVE_HORZ | RELATIVE_VERT</code> does <b>not</b> generally consume x% of horizontally and y% of vertically available space! This is because panes are laid-out in primary directions only (either horizontally for <code>HORIZONTAL</code> and vertically for <code>VERTICAL</code> orientation. But if you place a <code>RELATIVE_HORZ</code> Items in a <code>RELATIVE_VERT</code> Pane you can achieve this type of Layout.</p> <h3><code>ABSOLUTE_VERT</code></h3> <p>This is the same as <code>ABSOLUTE_HORZ</code> just for the vertical direction.</p> <h3><code>RELATIVE_VERT</code></h3> <p>This is the same as <code>RELATIVE_HORZ</code> just for the vertical direction.</p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr6.gif" alt="RELATIVE_VERT" width="247" height="49" /></p> <h3><code>NORESIZE</code></h3> <p>It is also possible to keep the initial size of an Item. Actually <code>NORESIZE</code> is defined as <code>ABSOLUTE_HORZ | ABSOLUTE_VERT</code>. A good example is the "Ok" Button, which usually shall keep it's initial size.</p> <h2><a name="alignment">Alignment Modes</a></h2> <p>Alignment Modes are used in conjunction with Resize Modes. When there is more than one Item in a pane and one item is not resizable this situation can occur:</p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr7.gif" alt="ALIGN Problem" width="315" height="64" /></p> <p>As the Item must not grow bigger there is more space available than the Item can use (I will refer to this as the <i>surplus space</i>). The question is, where should the Item be placed in the surplus space? </p><h3><code>ALIGN_LEFT</code></h3> <p>The item is aligned at the left border of the <i>surplus space</i>, if any.</p> <h3><code>ALIGN_RIGHT</code></h3> <p>The item is aligned at the right border of the <i>surplus space</i>, if any.</p> <h3><code>ALIGN_TOP</code></h3> <p>The item is aligned at the top border of the <i>surplus space</i>, if any.</p> <h3><code>ALIGN_BOTTOM</code></h3> <p>The item is aligned at the bottom border of the <i>surplus space</i>, if any.</p> <h3><code>ALIGN_HCENTER</code></h3> <p>The item is centered horizontally in the <i>surplus space</i>, if any.</p> <h3><code>ALIGN_VCENTER</code></h3> <p>The item is centered vertically in the <i>surplus space</i>, if any.</p> <h3><code>ALIGN_CENTER</code></h3> <p>The item is centered horizontally and vertically in the <i>surplus space</i>, if any. In fact <code>ALIGN_CENTER = ALIGN_HCENTER | ALIGN_VCENTER</code>.</p> <h3><code>ALIGN_FILL_HORZ</code></h3> <p>The item is stretched horizontally to fill the <i>surplus space</i>, regardless of it's Resize Mode.</p> <h3><code>ALIGN_FILL_VERT</code></h3> <p>The item is stretched vertically to fill the <i>surplus space</i>, regardless of it's Resize Mode.</p> <h3><code>ALIGN_FILL</code></h3> <p>The item is stretched horizontally and vertically to fill the <i>surplus space</i>, regardless of it's Resize Mode. In fact <code>ALIGN_FILL = ALIGN_HFILL | ALIGN_VFILL</code>.</p> <h2><a name="raw">Raw Interface:</a></h2> <p>The Raw Interface is the most basic way to define the layout of your dialog. Most of the methods used here are the same as with the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#stream">Stream Interface</a>. The difference is the way you compose the panes and subpanes. The Raw Interface uses a C style approach with member function calls, whereas the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#stream">Stream Interface</a> uses the C++ streaming operator. I recommend using the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#stream">Stream Interface</a> where possible.</p> <p>With the Raw Interface you assemble the layout in a <i>Bottom-Up</i> way. I.e. you first group your Dialog controls into panes, then these panes in further (parent-) panes until at some point you add these parent panes to the one and only root pane.</p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr11.gif" alt="SampleBottomUp" width="531" height="120" /></p> <h3><a name="pane">Panes</a></h3> <p>To create a new pane you just call the <code>pane()</code> member function (there is also support for <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#special">special controls</a> that contain items itself and thus are used as Panes. There are some arguments that you may alter to change the behavior:</p> <div class="SmallText" id="premain10" style="width: 100%; cursor: pointer;"><img preid="10" src="http://www.codeproject.com/images/minus.gif" id="preimg10" width="9" height="9" /><span preid="10" style="margin-bottom: 0pt;" id="precollapse10"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre10"> <span class="code-comment">//</span><span class="code-comment"> ETSLayoutMgr<br /></span><br /> CPane pane( layOrientation orientation,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeBorder = nDefaultBorder,<br /> <span class="code-keyword">int</span> sizeExtraBorder = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeSecondary = <span class="code-digit">0</span>);<br /></pre> <p><a name="border"><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr10.gif" alt="ALIGN Problem" width="301" height="187" /></a></p><ul><li>You have to set an <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#orientation">orientation</a> (primary direction) for each pane.</li><li>Set a <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#resizing">Resizing Mode</a> for the Pane. If you omit this the default value is <code>GREEDY</code></li><li>The third argument (which also may be omitted) sets a border <i>between</i> all items (see <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#border">picture</a>).</li><li>The fourth argument (which may also be omitted) sets an extra border <i>around</i> all the items (see <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#border">picture</a>).</li><li>If you add modes for the secondary direction (i.e. <code>ABSOLUTE_VERT</code> for a <code>HORIZONTAL</code> pane) then <code>sizeSecondary</code> is used as it's (secondary) size. If you do not specify <code>sizeSecondary</code> and the mode is <code>ABSOLUTE_VERT</code> (for a <code>HORIZONTAL</code> pane) it will be computed as the maximum height of all SubPanes (the same is true for <code>VERTICAL</code> panes and subpanes with <code>ABSOLUTE_HORZ</code>) </li></ul> <p>Normally you would write code like this to create a pane in OnInitDialog() or any other member of your derived class: </p> <div class="SmallText" id="premain11" style="width: 100%; cursor: pointer;"><img preid="11" src="http://www.codeproject.com/images/minus.gif" id="preimg11" width="9" height="9" /><span preid="11" style="margin-bottom: 0pt;" id="precollapse11"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre11"> <span class="code-comment">//</span><span class="code-comment"> in OnInitDialog()<br /></span><br /> CPane newItemPane = pane( HORIZONTAL );<br /></pre> <h3><a name="pointer">AutoPointer</a></h3> <p>As you see you don't have to worry about pointers if you use <code>CPane</code> and <code>CPaneBase</code> autopointers. These do automatic reference counting and can be used exactly as pointers <code>Pane*</code> and <code>PaneBase*</code> respectively. The use of <code>CPane</code> and <code>CPaneBase</code> is strongly encouraged! </p> <p>Use <code>CPane</code> if you are dealing with a <code>Pane</code>, <code>PaneTab</code> or <code>PaneCtrl</code>, because <code>CPaneBase</code> encapsulates a <code>PaneBase</code> pointer. <code>PaneBase</code> is the general base class for all sort of items and has <b>no</b> support for adding items. So you can't use it for subpanes. </p> <p>There is one thing you should never do: <b>Never use the <code>Pane*</code> you get with <code>GetPane()</code> or <code>GetPaneBase()</code> to construct a new <code>CPane</code> or <code>CPaneBase</code></b>! </p> <h3><a name="item">Items</a></h3> <p>An empty pane is - just nothing. You'll have to add items in order to make any use of them. To add items to a pane use the <code>Pane</code>'s member functions (and that's the big difference to the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#stream">Stream Interface</a>:</p> <div class="SmallText" id="premain12" style="width: 100%; cursor: pointer;"><img preid="12" src="http://www.codeproject.com/images/minus.gif" id="preimg12" width="9" height="9" /><span preid="12" style="margin-bottom: 0pt;" id="precollapse12"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre12"> <span class="code-comment">//</span><span class="code-comment"> members of Pane<br /></span><br /> <span class="code-keyword">bool</span> addItem( UINT nID,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeX = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeY = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeXMin = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeYMin = <span class="code-digit">0</span>);<br /> <br /> <span class="code-keyword">bool</span> addItem( CWnd* pWnd,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeX = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeY = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeXMin = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeYMin = <span class="code-digit">0</span>);<br /> <br /> <span class="code-keyword">bool</span> addPane( CPane pSubpane );<br /></pre> <p>The first two members are for adding controls to a pane.</p><ul><li>Specify either the control's Dialog ID <code>nID</code> or a subclassed member of the control through <code>pWnd</code></li><li>Set a <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#resizing">Resizing Mode</a> for the control</li><li>If you add modes for the secondary direction (i.e. <code>ABSOLUTE_VERT</code> for a <code>HORIZONTAL</code> pane) then <code>sizeSecondary</code> is used as it's (secondary) size. If you do not specify <code>sizeSecondary</code> and the mode is <code>ABSOLUTE_VERT</code> (for a <code>HORIZONTAL</code> pane) it will be computed as the maximum Height of all SubPanes (the same is true for <code>VERTICAL</code> panes and subpanes with <code>ABSOLUTE_HORZ</code>) </li><li>Set initial size of the control through <code>sizeX</code> and <code>sizeY</code>. You may omit these values (or set them to <code><span class="code-digit">0</span></code>). In this case the initial size is based on the size of the control in the dialog template.</li><li>Set the minimal size of the control through <code>sizeXMin</code> and <code>sizeYMin</code>. If you omit these values (or set them to <code>-<span class="code-digit">1</span></code>) the current size of the control as defined in the dialog template will be the minimal size for this control. The LayoutManager will ensure that the control is never made smaller than this. <i>The dialog items (and thus the dialog itself) will not be able to shrink smaller than in the dialog template (if you're just using the default parameters).</i> If you set <code>sizeXMin</code> and/or <code>sizeYMin</code> to <code><span class="code-digit">0</span></code> the item will be able to shrink (almost) completely. </li></ul> <h3><a name="special">Support for special Controls</a></h3> <p>There are some special cases which have to be taken into account. Normally no items in the layout are allowed to overlap. But if you want to use a CTabCtrl or a CStatic Groupbox there will be items you want to place <i>inside</i> these controls. Fortunately there are some special classes to support this. The corresponding constructing functions are:</p> <div class="SmallText" id="premain13" style="width: 100%; cursor: pointer;"><img preid="13" src="http://www.codeproject.com/images/minus.gif" id="preimg13" width="9" height="9" /><span preid="13" style="margin-bottom: 0pt;" id="precollapse13"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre13"> <span class="code-comment">//</span><span class="code-comment"> members of ETSLayoutMgr<br /></span><br /> CPane paneTab( CTabCtrl* pTab,<br /> layOrientation orientation,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeBorder = nDefaultBorder,<br /> <span class="code-keyword">int</span> sizeExtraBorder = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeSecondary = <span class="code-digit">0</span>);<br /> <br /> CPane paneCtrl( CWnd* pCtrl,<br /> layOrientation orientation,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeBorder = nDefaultBorder,<br /> <span class="code-keyword">int</span> sizeExtraBorder = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeTopExtra = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeSecondary = <span class="code-digit">0</span>);<br /> <br /> CPane paneCtrl( UINT nID,<br /> layOrientation orientation,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeBorder = nDefaultBorder,<br /> <span class="code-keyword">int</span> sizeExtraBorder = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeTopExtra = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeSecondary = <span class="code-digit">0</span>);<br /></pre> <p>As you may have guessed <code>paneTab</code> takes care of a TabCtrl. With <code>paneCtrl</code> you get something between a Pane and an item. It behaves like a Pane but does also resize a dialog control according to its own size. You will want to use this one for CStatic groupboxes.</p> <p>Special actions are taken to reduce flicker inside these controls.</p> <h3><a name="rootpane">Root Pane</a></h3> <p>Until now we know how to create panes and how to add items to these panes. The only thing missing is how to "wire" these panes to the dialog itself. As already mentioned above there exists something called a <i>Root Pane</i>.</p> <p>This special pane is the "mother of all panes". If the window is resized, this pane is automatically resized to the new client area and thus all siblings update their layout, too.</p> <p>Moreover, if the siblings pose a constraint on minimum or maximum size of the window this is also taken into account (Note: You have to add modifications to your <code>CMainFrame</code> if you want <code>ETSLayoutFormView</code> to do that. See Sample and/or header).</p> <p>The root pane also has an <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#orientation">orientation</a>. Create it with a call to:</p> <div class="SmallText" id="premain14" style="width: 100%; cursor: pointer;"><img preid="14" src="http://www.codeproject.com/images/minus.gif" id="preimg14" width="9" height="9" /><span preid="14" style="margin-bottom: 0pt;" id="precollapse14"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre14"> <span class="code-comment">//</span><span class="code-comment"> member of ETSLayoutMgr<br /></span><br /> CPane CreateRoot(layOrientation orientation,<br /> <span class="code-keyword">int</span> sizeBorder = nDefaultBorder,<br /> <span class="code-keyword">int</span> sizeExtraBorder = <span class="code-digit">0</span> );<br /></pre> <p>The arguments are the same as for <code><a href="http://www.codeproject.com/KB/dialog/%3Cspan" class="code-string">"<span class="code-string">#pane"</span>>Pane</a></code>. However, <code>sizeBorder</code> sets the border between the Window's border and the controls. If you want some items to stick close to the Window's border use <code><span class="code-digit">0</span></code> here. You will eventually need some fillers if you don't want all items to stick to the border, though.</p> <p>The Root Pane is accessed through the member <code>m_RootPane</code>, e.g.:</p> <div class="SmallText" id="premain15" style="width: 100%; cursor: pointer;"><img preid="15" src="http://www.codeproject.com/images/minus.gif" id="preimg15" width="9" height="9" /><span preid="15" style="margin-bottom: 0pt;" id="precollapse15"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre15"> m_RootPane-<span class="code-keyword">></span>addItem ( IDC_ITEM );<br /></pre> <h3>Sample</h3> <p>This is what you'll have to write to define the equivalent layout to the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#sample">sample above</a>:</p> <div class="SmallText" id="premain16" style="width: 100%; cursor: pointer;"><img preid="16" src="http://www.codeproject.com/images/minus.gif" id="preimg16" width="9" height="9" /><span preid="16" style="margin-bottom: 0pt;" id="precollapse16"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre16"> CPane newItemPane=new Pane ( <span class="code-keyword">this</span>, HORIZONTAL );<br /><br /> newItemPane-<span class="code-keyword">></span>addItem ( IDC_NEW_ITEM, GREEDY );<br /> newItemPane-<span class="code-keyword">></span>addItem ( IDC_ADD_ITEM, NORESIZE );<br /><br /><br /> CPane bottomPane=new Pane ( <span class="code-keyword">this</span>, HORIZONTAL );<br /> bottomPane-<span class="code-keyword">></span>addItem ( paneNull, GREEDY );<br /> bottomPane-<span class="code-keyword">></span>addItem ( IDOK, NORESIZE );<br /> bottomPane-<span class="code-keyword">></span>addItem ( IDCANCEL, NORESIZE );<br /><br /> CreateRoot( VERTICAL );<br /><br /> m_RootPane-<span class="code-keyword">></span>addItem ( IDC_NEW_ITEM_STATIC, NORESIZE );<br /> m_RootPane-<span class="code-keyword">></span>addPane ( newItemPane, ABSOLUTE_VERT );<br /> m_RootPane-<span class="code-keyword">></span>addItem ( IDC_ITEM_LIST_STATIC, NORESIZE );<br /> m_RootPane-<span class="code-keyword">></span>addItem ( IDC_ITEM_LIST, GREEDY );<br /> m_RootPane-<span class="code-keyword">></span>addPane ( bottomPane, ABSOLUTE_VERT );<br /><br /> UpdateLayout();<br /></pre> <h2><a name="stream">Stream Interface:</a></h2> <p>The Stream Interface adds a simple and natural access to the layout definition. Items/subpanes are added to other panes through the stream <code><span class="code-keyword">operator</span><span class="code-keyword"><</span><span class="code-keyword"><</span>()</code>. In contrast to the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#raw">Raw Interface</a> the definition is some sort of <i>Top-Down</i>:</p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr12.gif" alt="SampleTopDown" width="530" height="118" /></p> <h3>Root</h3> <p>The starting point is always the Root Pane. It is created exactly as with the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#root">Raw Interface</a>:</p> <div class="SmallText" id="premain17" style="width: 100%; cursor: pointer;"><img preid="17" src="http://www.codeproject.com/images/minus.gif" id="preimg17" width="9" height="9" /><span preid="17" style="margin-bottom: 0pt;" id="precollapse17"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre17"> <span class="code-comment">//</span><span class="code-comment"> members of ETSLayoutMgr<br /></span><br /> CPane CreateRoot(layOrientation orientation,<br /> <span class="code-keyword">int</span> sizeBorder = nDefaultBorder,<br /> <span class="code-keyword">int</span> sizeExtraBorder = <span class="code-digit">0</span> );<br /></pre> <p>You then may use <code>m_RootPane</code> as the destination for stream operations like this:</p> <div class="SmallText" id="premain18" style="width: 100%; cursor: pointer;"><img preid="18" src="http://www.codeproject.com/images/minus.gif" id="preimg18" width="9" height="9" /><span preid="18" style="margin-bottom: 0pt;" id="precollapse18"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre18"> m_RootPane <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_SOMETHING) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_WHATEVER);<br /></pre> <p>It is also possible to add Items directly after the <code>CreateRoot()</code> call:</p> <div class="SmallText" id="premain19" style="width: 100%; cursor: pointer;"><img preid="19" src="http://www.codeproject.com/images/minus.gif" id="preimg19" width="9" height="9" /><span preid="19" style="margin-bottom: 0pt;" id="precollapse19"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre19"> CreateRoot(VERTICAL)<br /> <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_SOMETHING) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_WHATEVER);<br /></pre> <p>Alternatively you may omit the call to <code>CreateRoot()</code> if you are using a special version of the <code>UpdateLayout()</code> call. The Pane you provide in the call is then used as the root pane</p> <div class="SmallText" id="premain20" style="width: 100%; cursor: pointer;"><img preid="20" src="http://www.codeproject.com/images/minus.gif" id="preimg20" width="9" height="9" /><span preid="20" style="margin-bottom: 0pt;" id="precollapse20"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre20"> <span class="code-comment">//</span><span class="code-comment"> members of ETSLayoutMgr<br /></span><br /> <span class="code-keyword">virtual</span> <span class="code-keyword">void</span> UpdateLayout(CPane p);<br /></pre> <p>You would use it like this to define the complete layout in a single line of code:</p> <div class="SmallText" id="premain21" style="width: 100%; cursor: pointer;"><img preid="21" src="http://www.codeproject.com/images/minus.gif" id="preimg21" width="9" height="9" /><span preid="21" style="margin-bottom: 0pt;" id="precollapse21"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre21"> <span class="code-comment">//</span><span class="code-comment"> in OnInitDialog()<br /></span><br /> UpdateLayout( pane(VERTICAL)<br /> <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_SOMETHING) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDC_WHATEVER) );<br /></pre> <h3>Items</h3> <p>You've already seen how items are created and added to panes with the Stream Interface:</p> <div class="SmallText" id="premain22" style="width: 100%; cursor: pointer;"><img preid="22" src="http://www.codeproject.com/images/minus.gif" id="preimg22" width="9" height="9" /><span preid="22" style="margin-bottom: 0pt;" id="precollapse22"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre22"> <span class="code-comment">//</span><span class="code-comment"> members of ETSLayoutMgr<br /></span><br /> CPaneBase item(UINT nID,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeX = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeY = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeXMin = -<span class="code-digit">1</span>,<br /> <span class="code-keyword">int</span> sizeYMin = -<span class="code-digit">1</span>);<br /> <br /> CPaneBase item(CWnd* pWnd,<br /> layResizeMode modeResize = GREEDY,<br /> <span class="code-keyword">int</span> sizeX = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeY = <span class="code-digit">0</span>,<br /> <span class="code-keyword">int</span> sizeXMin = -<span class="code-digit">1</span>,<br /> <span class="code-keyword">int</span> sizeYMin = -<span class="code-digit">1</span>);<br /></pre> <p>The parameters are the same as with the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#item">Raw Interface</a>.</p> <h3>Panes</h3> <p>Of course there is support for subpanes, too. It work exactly like in the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#pane">Raw Interface</a>. Panes are created like Items, but when you add items to the pane you should make sure to use braces around the pane and its items like this:</p> <div class="SmallText" id="premain23" style="width: 100%; cursor: pointer;"><img preid="23" src="http://www.codeproject.com/images/minus.gif" id="preimg23" width="9" height="9" /><span preid="23" style="margin-bottom: 0pt;" id="precollapse23"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre23"> m_RootPane <span class="code-keyword"><</span><span class="code-keyword"><</span> ( paneHorz (ABSOLUTE_VERT ) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( paneNull, GREEDY )<br /> <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDOK, NORESIZE ) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDCANCEL, NORESIZE ) );<br /></pre> <p>The above code adds a <code>HORIZONTAL</code> pane with 3 Items to the Root Pane. If you forget the braces like this...</p> <div class="SmallText" id="premain24" style="width: 100%; cursor: pointer;"><img preid="24" src="http://www.codeproject.com/images/minus.gif" id="preimg24" width="9" height="9" /><span preid="24" style="margin-bottom: 0pt;" id="precollapse24"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre24"> m_RootPane <span class="code-keyword"><</span><span class="code-keyword"><</span> paneHorz (ABSOLUTE_VERT ) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( paneNull, GREEDY )<br /> <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDOK, NORESIZE ) <span class="code-keyword"><</span><span class="code-keyword"><</span> item( IDCANCEL, NORESIZE );<br /></pre> <p>...you would add an <b>empty</b> <code>HORIZONTAL</code> pane <b>and</b> 3 Items to the Root Pane.</p> <p>We've already used the Stream Interface in the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#sample">sample above</a>, so we don't really need another one here :) For more samples have a look at the demo sourcecode.</p> <h2>Extras:</h2> <p>There are some useful extra features included. I will not describe them all here, but you should have a look at the headerfile. Here are some of the function you should have a look at:</p> <div class="SmallText" id="premain25" style="width: 100%; cursor: pointer;"><img preid="25" src="http://www.codeproject.com/images/minus.gif" id="preimg25" width="9" height="9" /><span preid="25" style="margin-bottom: 0pt;" id="precollapse25"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre25"> <span class="code-comment">//</span><span class="code-comment"> members of Pane<br /></span><br /> <br /> <span class="code-comment">/*</span><span class="code-comment">*<br /> * Add a whitespace Item (paneNull) of variable size with<br /> * a minimum size of 0<br /> */</span><br /> <span class="code-keyword">bool</span> addGrowing();<br /> <br /> <span class="code-comment">/*</span><span class="code-comment">*<br /> * Add a whitespace Item (paneNull) of fixed size based on the<br /> * current layout (as in the dialog template). Based on the layout<br /> * of the pane vertical or horizontal spacing is considered<br /> *<br /> * First argument is the left (top) item for a HORIZONTAL<br /> * (VERTICAL) pane<br /> */</span><br /> <span class="code-keyword">bool</span> addItemSpaceBetween( CWnd* pWndFirst,<br /> CWnd* pWndSecond );<br /> <br /> <span class="code-keyword">bool</span> addItemSpaceBetween( UINT nIDFirst,<br /> UINT nIDSecond );<br /> <br /> <br /> <span class="code-comment">/*</span><span class="code-comment">*<br /> * Add a whitespace Item (paneNull) of fixed size based on the<br /> * size of another item<br /> */</span><br /> <span class="code-keyword">bool</span> addItemSpaceLike( CWnd* pWnd );<br /> <span class="code-keyword">bool</span> addItemSpaceLike( UINT nID );<br /></pre> <p>For the <a href="http://www.codeproject.com/KB/dialog/layoutmgr.aspx#stream">Stream Interface</a> there are equivalent functions:</p> <div class="SmallText" id="premain26" style="width: 100%; cursor: pointer;"><img preid="26" src="http://www.codeproject.com/images/minus.gif" id="preimg26" width="9" height="9" /><span preid="26" style="margin-bottom: 0pt;" id="precollapse26"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre26"> <span class="code-comment">//</span><span class="code-comment"> members of ETSLayoutMgr<br /></span><br /> <br /> <span class="code-comment">/*</span><span class="code-comment">*<br /> * Add a whitespace Item (paneNull) of variable size with<br /> * a minimum size of 0<br /> */</span><br /> CPaneBase itemGrowing(layOrientation orientation);<br /><br /> <span class="code-comment">/*</span><span class="code-comment">*<br /> * Add a whitespace Item (paneNull) with fixed size<br /> */</span><br /> CPaneBase itemFixed(<span class="code-keyword">int</span> sizePrimary);<br /><br /> <span class="code-comment">/*</span><span class="code-comment">*<br /> * Add a whitespace Item (paneNull) of fixed size based on the<br /> * current layout (as in the dialog template). Based on the layout<br /> * of the pane vertical or horizontal spacing is considered<br /> *<br /> * First argument is the left (top) item for a HORIZONTAL<br /> * (VERTICAL) pane<br /> */</span><br /> CPaneBase itemSpaceBetween( layOrientation orientation,<br /> CWnd* pWndFirst,<br /> CWnd* pWndSecond );<br /> <br /> CPaneBase itemSpaceBetween( layOrientation orientation,<br /> UINT nIDFirst,<br /> UINT nIDSecond );<br /><br /> <span class="code-comment">/*</span><span class="code-comment">*<br /> * Add a whitespace Item (paneNull) of fixed size based on the<br /> * size of another item<br /> */</span><br /> CPaneBase itemSpaceLike( layOrientation orientation,<br /> CWnd* pWnd );<br /> <br /> CPaneBase itemSpaceLike( layOrientation orientation,<br /> UINT nID );<br /></pre> <h2>PropertySheet</h2> Normally, you use <code>ETSLayoutPropertySheet</code> directly, as in: <div class="SmallText" id="premain27" style="width: 100%; cursor: pointer;"><img preid="27" src="http://www.codeproject.com/images/minus.gif" id="preimg27" width="9" height="9" /><span preid="27" style="margin-bottom: 0pt;" id="precollapse27"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre27"> ETSLayoutPropertySheet sheet(_T(<span class="code-string">"</span><span class="code-string">PropertySheet Test"</span>));<br /><br /> CPropPage1 page1;<br /> CPropPage2 page2;<br /><br /> sheet.AddPage(&page1);<br /> sheet.AddPage(&page2);<br /><br /> sheet.DoModal();<br /></pre> However, if you want to add additional controls to the sheet itself (i.e. not on PropertyPages), you will need to redefine the layout of the <code>ETSLayoutPropertySheet</code> itself. This framework provides you with two hooks for that: <h3><code><span class="code-keyword">virtual</span> <span class="code-keyword">void</span> AddMainArea(CPane paneRoot, CPaneBase itemTab)</code></h3> <p>Define the layout of the MainArea of the PropertySheet. Normally, the MainArea is covered by the TabControl only, thus the default is:</p> <div class="SmallText" id="premain28" style="width: 100%; cursor: pointer;"><img preid="28" src="http://www.codeproject.com/images/minus.gif" id="preimg28" width="9" height="9" /><span preid="28" style="margin-bottom: 0pt;" id="precollapse28"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre28"> <span class="code-keyword">void</span> ETSLayoutPropertySheet::AddMainArea(CPane paneRoot, CPaneBase itemTab)<br /> {<br /> <span class="code-comment">//</span><span class="code-comment"> the default is: Whole main Area is covered by the TabCtrl<br /></span><br /> paneRoot <span class="code-keyword"><</span><span class="code-keyword"><</span> itemTab;<br /> }<br /></pre> <h3><code><span class="code-keyword">virtual</span> <span class="code-keyword">void</span> AddButtons(CPane paneBottom)</code></h3> <p>To change the way the buttons at the bottom are displayed you may override this method. If you want to have the buttons at some totally different place just override this and do nothing here. But consider, that the horizontal line in WizardMode will be added below the MainArea nevertheless. </p> <h2>How it works:</h2> <p>You don't really <i>need</i> to know how all that works. If you skip this section you won't miss anything. But if you're interested in the layout algorithm I will try to describe it briefly. If you want to know more look at the source, it's pretty well documented.</p> <p>The idea is to split the dialog in Panes. Each pane has an orientation (horizontal or vertical) and may contain items and/or other (sub-)panes. It is necessary that all subpanes are of opposite orientation (a vertical pane may only contain horizontal subpanes and vice versa).</p> <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr9.gif" alt="Primary/Secondary" /></p> <p>When a pane is going to be resized it gets a certain space to consume. Lets say [1] (as in the picture above) gets a certain position assigned (this could be either because [1] is the Root Pane or because it gets its new position from its parent Pane). [1] is a horizontal Pane and has two items: An item [2] and a subpane [3]. </p><ol><li>If [1] has an associated Window (which is only the case if it's a CTabCtrl or a CStatic Groupbox) it is moved to the assigned position.</li><li>The secondary size of [2] and [3] (the height) is determined by the height of [1]. <p><img src="http://www.codeproject.com/KB/dialog/layoutmgr/layoutmgr8.gif" alt="Primary/Secondary" /></p> </li><li>The primary size of [2] and [3] has to be calculated. Therefore [1] "asks" its Items [2] and [3] how much of the available space they need.</li><li>As [2] is a simple item its needed size in primary direction can easily be calculated. If [2] is of fixed size then it's just the item's width. If the Item may grow it just "tells" that to [1]. Later [1] can assign all the remaining space to [2].</li><li>[3] is a Pane itself, so the needed primary size must be calculated. Therefore [3] has to query its items for their secondary size. If they all have fixed secondary size (in this case <i>width</i>) then [3] has to be at least as width as the biggest width of it's items. If one of them may grow in width <b>and</b> [3] itself may grow horizontally then a new width is calculated (based on the currently available space). BTW: This is where the height of [1] came from if [1] is not the root pane.</li><li>Now the items [2] and [3] can be repositioned based on the results of the steps before. In the case of [3] this process starts over (recursively) at Point 1.</li></ol> <p>Resizing the Dialog is now be as easy as requesting the root pane to fit in the current client area! Actually this is done automatically in the OnSize handler, so you just have to define the layout itself.</p> <h2>History</h2> <div class="SmallText" id="premain29" style="width: 100%; cursor: pointer;"><img preid="29" src="http://www.codeproject.com/images/minus.gif" id="preimg29" width="9" height="9" /><span preid="29" style="margin-bottom: 0pt;" id="precollapse29"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre29"><span class="code-comment">//</span><span class="code-comment"> Version: 1.0 [1999/12/04] Initial Article on CodeProject<br /></span><br /><span class="code-comment">//</span><span class="code-comment"><br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 1999/12/10 Erase Backgroung within TabCtrl was 'fixed' badly. Reverted to<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> old working code<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/02/02 When the Dialog is child of a View the class works correctly<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> now [Didier BULTIAUW]<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/02/15 Combo-Boxes were not working correctly (in all modes!)<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/02/17 aligned SpinButton Controls (with buddy) now handled<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> automatically<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> !! do not add such a control to the layout !! it is always<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> reattached to its buddy.<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/02/17 changed some cotrol class names to the defined constants<br /></span><br /><span class="code-comment">//</span><span class="code-comment"><br /></span><br /><span class="code-comment">//</span><span class="code-comment"> Version: 1.1 [2000/02/17]<br /></span><br /><span class="code-comment">//</span><span class="code-comment"><br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/02/25 fixed auto alignment of SpinButton Controls to only affect<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> visible ones<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/03/07 Fixed growing Dialog after minimizing and restoring<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/05/22 Whole Statusbar (Gripper) is not excluded anymore in EraseBkgnd()<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> instead only the triangular Gripper is excluded<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/05/31 Fix for PropertySheets with PSH_WIZARDHASFINISH [Th�mmi]<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/05/31 Fix for UpDown-Controls with EditCtrl Buddy in PropertyPages.<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> These were not repositioned every time the page is being show<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> until the first resize<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/07/28 Problems with resizing ActiveX Controls fixed [Micheal Chapman]<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/07/28 Some strings were not properly wrapped with _T()<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/08/03 Check for BS_GROUPBOX was not correct as BS_GROUPBOX is more<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> than one Bit<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/08/03 New override AddMainArea added to ETSLayoutPropertySheet in order<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> to have a hook for additional controls in a PropertySheet<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> (besides the Tab)<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> 2000/08/03 New override AddButtons added to ETSLayoutPropertySheet in order to<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> have a hook for additional controls in the bottem pane of a<br /></span><br /><span class="code-comment">//</span><span class="code-comment"> PropertySheet<br /></span><br /><span class="code-comment">//</span><span class="code-comment"><br /></span><br /><span class="code-comment">//</span><span class="code-comment"> Version: 1.2 [2000/08/05]<br /></span><br /></pre> <h2>Copyright</h2> <p>This Article and all accompanying material is �1998-1999 Erwin Tratar. All rights reserved.</p> <p>The source code may be used in compiled form in any way you desire (including usage in commercial applications), providing that your application adds essential code (i.e. it is not only a wrapper) to the functionality found here</p> <p>Redistribution of the sourcecode itself, publication in any media or inclusion in a library requires the authors expressed written consent. You may not sale this code for profit.</p> <b><div class="SmallText" id="premain30" style="width: 100%; cursor: pointer;"><img preid="30" src="http://www.codeproject.com/images/minus.gif" id="preimg30" width="9" height="9" /><span preid="30" style="margin-bottom: 0pt;" id="precollapse30"> Collapse</span></div><pre style="margin-top: 0pt;" id="pre30">THIS SOFTWARE IS PROVIDED <span class="code-string">"</span><span class="code-string">AS IS"</span> WITHOUT EXPRESS OR IMPLIED WARRANTY. USE IT<br />AT YOUR OWN RISK! THE AUTHOR ACCEPTS NO LIABILITY FOR ANY DAMAGE/LOSS OF<br />BUSINESS THAT THIS PRODUCT MAY CAUSE.</pre></b> <!-- Main Page Contents End --> <div> <input name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTAyMTMzODg1Ng9kFgJmD2QWBAILD2QWBgIDDw8WAh4HVmlzaWJsZWdkZAIJDw8WAh8AZ2RkAgwPDxYCHwBnZGQCDA9kFgoCBw9kFg4CAQ9kFgJmDxYCHgtfIUl0ZW1Db3VudGZkAgMPZBYKZg8PFgIeC05hdmlnYXRlVXJsBScvS0IvZGlhbG9nL2xheW91dG1nci5hc3B4P2Rpc3BsYXk9UHJpbnRkZAIBDw8WAh8CBSQvc2NyaXB0L0FydGljbGVzL1JlcG9ydC5hc3B4P2FpZD0xMTZkZAICDw8WAh8AaGRkAgMPDxYCHwBoZGQCBQ8PFgIfAgUvL3NjcmlwdC9jb21tb24vVGVsbEZyaWVuZC5hc3B4P29idGlkPTImb2JpZD0xMTZkZAIFD2QWBAIBD2QWAgIBDw8WAh4EVGV4dAUbMTc0IHZvdGVzIGZvciB0aGlzIGFydGljbGUuZGQCBw9kFgJmD2QWBAIBDw8WBB8DBRFQb3B1bGFyaXR5OiAxMC43MR8CBSkvc2NyaXB0L0FydGljbGVzL1RvcEFydGljbGVzLmFzcHg/dGFfc289MWRkAgUPFgIfAwUcUmF0aW5nOiA8Yj40Ljc4PC9iPiBvdXQgb2YgNWQCGw9kFgoCAQ9kFgQCAQ8WAh4JaW5uZXJodG1sBbECPHA+VGhpcyBhcnRpY2xlIGhhcyBubyBleHBsaWNpdCBsaWNlbnNlIGF0dGFjaGVkIHRvIGl0IGJ1dCBtYXkgY29udGFpbiB1c2FnZSB0ZXJtcyBpbiB0aGUgYXJ0aWNsZSB0ZXh0IG9yIHRoZSBkb3dubG9hZCBmaWxlcyB0aGVtc2VsdmVzLiBJZiBpbiBkb3VidCBwbGVhc2UgY29udGFjdCB0aGUgYXV0aG9yIHZpYSB0aGUgZGlzY3Vzc2lvbiBib2FyZCBiZWxvdy48L3A+PHA+QSBsaXN0IG9mIGxpY2Vuc2VzIGF1dGhvcnMgbWlnaHQgdXNlIGNhbiBiZSBmb3VuZCA8YSBocmVmPSIvaW5mby9MaWNlbnNlcy5hc3B4Ij5oZXJlPC9hPjwvcD5kAgIPZBYCAgEPEGRkFgBkAgUPFgIfAQIBZAIHDxYCHwMFwQg8aDI+T3RoZXIgcG9wdWxhciBEaWFsb2dzIGFuZCBXaW5kb3dzIGFydGljbGVzOjwvaDI+PHVsPjxsaT48YSBocmVmPSIvS0IvZGlhbG9nL2RpYWxvZ2FwcHR1dGUuYXNweCI+QSBCZWdpbm5lcnMgR3VpZGUgdG8gRGlhbG9nIEJhc2VkIEFwcGxpY2F0aW9ucyAtIFBhcnQgT25lPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+QSBzdGVwIGJ5IHN0ZXAgdHV0b3JpYWwgc2hvd2luZyBob3cgdG8gY3JlYXRlIHlvdXIgZmlyc3Qgd2luZG93cyBwcm9ncmFtIHVzaW5nIE1GQzwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9kaWFsb2cvbGF5b3V0bWdyLmFzcHgiPkxheW91dCBNYW5hZ2VyIGZvciBEaWFsb2dzLCBGb3Jtdmlld3MsIERpYWxvZ0JhcnMgYW5kIFByb3BlcnR5UGFnZXM8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5BIGZyYW1ld29yayB0byBwcm92aWRlIGF1dG9tYXRpYyBsYXlvdXQgY29udHJvbCBmb3IgZGlhbG9ncyBhbmQgZm9ybXM8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0IvZGlhbG9nL2Vhc3lzaXplLmFzcHgiPkVhc3lTaXplIC0gRGlhbG9nIHJlc2l6aW5nIGluIG5vIHRpbWUhPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+QW4gZWFzeSB3YXkgdG8gcG9zaXRpb24gY29udHJvbHMgaW4gcmVzaXphYmxlIGRpYWxvZ3Mgb3IgcHJvcGVydHkgcGFnZXMgdXNpbmcganVzdCBhIGZldyBtYWNyb3M8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0IvZGlhbG9nL3htZXNzYWdlYm94LmFzcHgiPlhNZXNzYWdlQm94IC0gQSByZXZlcnNlLWVuZ2luZWVyZWQgTWVzc2FnZUJveCgpPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+QSByZXZlcnNlLWVuZ2luZWVyZWQgbm9uLU1GQyBNZXNzYWdlQm94KCkgdGhhdCBpbmNsdWRlcyBjdXN0b20gY2hlY2tib3hlcy48L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0IvZGlhbG9nL3Zpc3VhbGZ4LmFzcHgiPkEgVmlzdWFsIEZyYW1ld29yayAoVmlld3MsIFRhYnMgYW5kIFNwbGl0dGVycyk8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5DcmVhdGluZyBTREkvTURJIGFwcGxpY2F0aW9ucyB3aXRoIHNwbGl0dGVyIGFuZCB0YWIgd2luZG93czwvZGl2PjwvbGk+PC91bD5kAgkPDxYCHwBnZGQCDQ9kFgJmD2QWAgIBD2QWAmYPZBYCAgkPFgIfAGgWAgIBDxBkZBYAZAIdDw8WAh8AZ2RkAh8PDxYCHwBnZGQCJw8WAh8AaGQCCw8PFgIfAgUlL3NjcmlwdC9BcnRpY2xlcy9BcnRpY2xlLmFzcHg/YWlkPTExNmRkAhEPFgIfAwUKNCBBdWcgMjAwMGQCEw8PFgQfAwUMQW5kcmV3IFBlYWNlHwIFIy9zY3JpcHQvTWVtYmVyc2hpcC9WaWV3LmFzcHg/bWlkPTIxZGQCFQ8WAh8DBR5Db3B5cmlnaHQgMTk5OSBieSBFcndpbiBUcmF0YXJkZNTXvMuwerJnLolsAu3+7iHGbL8C" type="hidden"> </div> <h2>License</h2> <p>This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.</p><input id="gwProxy" type="hidden"><!--Session data--><input onclick="jsCall();" id="jsProxy" type="hidden"><div id="refHTML"></div>Linuxhttp://www.blogger.com/profile/01020619507546589145noreply@blogger.com0