|  | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> | 
|  | <html> | 
|  |  | 
|  | <head> | 
|  | <meta http-equiv="Content-Type" | 
|  | content="text/html; charset=windows-1252"> | 
|  | <title>Understanding Layouts in SWT</title> | 
|  | <link rel="stylesheet" href="../article.css" type="text/css" /> | 
|  | </head> | 
|  | <body> | 
|  | <h1>Understanding Layouts in SWT</h1> | 
|  |  | 
|  | <div class="summary"> | 
|  | <h2>Summary</h2> | 
|  | <p>When writing applications in SWT, you may need to use <i>layouts</i> | 
|  | to give your windows a specific look. A layout controls the position and | 
|  | size of children in a <code>Composite</code>. Layout classes are | 
|  | subclasses of the abstract class <code>Layout</code>. This article shows | 
|  | you how to work with standard layouts, and write your own custom layout | 
|  | class.</p> | 
|  |  | 
|  | <div class="author">By Carolyn MacLeod, OTI</div> | 
|  | <div class="copyright">Copyright © 2001, 2002 Object | 
|  | Technology International, Inc.</div> | 
|  | <div class="date">March 22, 2001</div> | 
|  |  | 
|  | <div class="author">Revised by Shantha Ramachandran, OTI</div> | 
|  | <div class="date">May 02, 2002</div> | 
|  |  | 
|  | <div class="author">Revised by Wayne Beaton, The Eclipse | 
|  | Foundation</div> | 
|  | <div class="copyright">Copyright © 2008 The Eclipse | 
|  | Foundation, Inc.</div> | 
|  | <div class="date">May 30, 2008</div> | 
|  | </div> | 
|  |  | 
|  | <div class="content"> | 
|  |  | 
|  | <h2>Overview</h2> | 
|  |  | 
|  | <p>When writing applications in the <a | 
|  | href="http://www.eclipse.org/swt">Standard Widget Toolkit</a> (SWT), | 
|  | you may need to use <i>layouts</i> to give your windows a specific look. | 
|  | A layout controls the position and size of children in a <code>Composite</code>. | 
|  | Layout classes are subclasses of the abstract class <code>Layout</code>. | 
|  | SWT provides several standard layout classes, and you can write custom | 
|  | layout classes.</p> | 
|  |  | 
|  | <p>In SWT, positioning and sizing does not happen automatically. | 
|  | Applications can decide to size and place a <code>Composite</code>'s | 
|  | children initially, or in a resize listener. Another option is to | 
|  | specify a layout class to position and size the children. If children | 
|  | are not given a size, they will have zero size and they cannot be seen.</p> | 
|  |  | 
|  | <p>The diagram below illustrates a few general terms that are used | 
|  | when discussing layouts. The <code>Composite</code> (in this case, a <code>TabFolder</code>) | 
|  | has a <i>location</i>, <i>clientArea</i> and <i>trim</i>. The size of | 
|  | the <code>Composite</code> is the size of the <i>clientArea</i> plus the | 
|  | size of the <code>trim</code>. This <code>Composite</code> has two | 
|  | children that are laid out side by side. A <code>Layout</code> is | 
|  | managing the size and position of the children. This <code>Layout</code> | 
|  | allows <code>spacing</code> between the children, and a <i>margin</i> | 
|  | between the children and the edges of the <code>Layout</code>. The size | 
|  | of the <code>Layout</code> is the same as the size of the <code>Composite</code>'s | 
|  | <i>clientArea</i>.</p> | 
|  |  | 
|  | <img src="images/GeneralTerms.jpg" /> | 
|  |  | 
|  | <p>The <i>preferred size</i> of a widget is the minimum size needed | 
|  | to show its content. In the case of a <code>Composite</code>, the | 
|  | preferred size is the smallest rectangle that contains all of its | 
|  | children. If children have been positioned by the application, the <code>Composite</code> | 
|  | computes its own preferred size based on the size and position of the | 
|  | children. If a <code>Composite</code> is using a layout class to | 
|  | position its children, it asks the <code>Layout</code> to compute the | 
|  | size of its <code>clientArea</code>, and then it adds in the <code>trim</code> | 
|  | to determine its preferred size.</p> | 
|  |  | 
|  | <h3>Standard Layouts</h3> | 
|  |  | 
|  | <p>The standard layout classes in the SWT library are:</p> | 
|  |  | 
|  | <ul> | 
|  | <li><code>FillLayout</code> lays out equal-sized widgets in a | 
|  | single row or column</li> | 
|  | <li><code>RowLayout</code> lays out widgets in a row or rows, with | 
|  | fill, wrap, and spacing options</li> | 
|  | <li><code>GridLayout</code> lays out widgets in a grid</li> | 
|  | <li><code>FormLayout</code> lays out widgets by creating | 
|  | attachments for each of their sides</li> | 
|  | </ul> | 
|  |  | 
|  | <p>To use the standard layouts, you need to import the SWT layout | 
|  | package:</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.layout.*;</pre> | 
|  |  | 
|  | <p>Layouts are pluggable. To set a <code>Composite</code> widget's | 
|  | layout, you use the widget's <code>setLayout(Layout)</code> method. In | 
|  | the following code, a <code>Shell</code> (a subclass of <code>Composite</code>) | 
|  | is told to position its children using a <code>RowLayout</code>:</p> | 
|  |  | 
|  | <pre>Shell shell = new Shell(); | 
|  | shell.setLayout(new RowLayout());</pre> | 
|  |  | 
|  | <p>A layout class may have a corresponding layout data class: a | 
|  | subclass of <code>Object</code> that contains layout data for a specific | 
|  | child. By convention, layout data classes are identified by substituting | 
|  | "Data" for "Layout" in the class name. For example, | 
|  | the standard layout class <code>RowLayout</code> has a layout data class | 
|  | called <code>RowData</code>, the layout class <code>GridLayout</code> | 
|  | uses a layout data class called <code>GridData</code>, and the layout | 
|  | class <code>FormLayout</code> has a layout data class called <code>FormData</code>. | 
|  | A widget's layout data class is set as follows:</p> | 
|  |  | 
|  | <pre>Button button = new Button(shell, SWT.PUSH); | 
|  | button.setLayoutData(new RowData(50, 40));</pre> | 
|  |  | 
|  | <h3>Examples in this Document</h3> | 
|  |  | 
|  | <p>Most of the snapshots in this document were taken by running | 
|  | variations on the following example code. We may change the type of | 
|  | layout, the options used, or the type or number of children.</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.SWT; | 
|  | import org.eclipse.swt.layout.RowLayout; | 
|  | import org.eclipse.swt.widgets.Button; | 
|  | import org.eclipse.swt.widgets.Display; | 
|  | import org.eclipse.swt.widgets.Shell; | 
|  |  | 
|  | public class LayoutExample { | 
|  | public static void main(String[] args) { | 
|  | Display display = new Display(); | 
|  | Shell shell = new Shell(display); | 
|  | // Create the layout. | 
|  | RowLayout layout = new RowLayout(); | 
|  | // Optionally set layout fields. | 
|  | layout.wrap = true; | 
|  | // Set the layout into the composite. | 
|  | shell.setLayout(layout); | 
|  | // Create the children of the composite. | 
|  | new Button(shell, SWT.PUSH).setText("B1"); | 
|  | new Button(shell, SWT.PUSH).setText("Wide Button 2"); | 
|  | new Button(shell, SWT.PUSH).setText("Button 3"); | 
|  | shell.pack(); | 
|  | shell.open(); | 
|  |  | 
|  | while (!shell.isDisposed()) { | 
|  | if (!display.readAndDispatch()) display.sleep(); | 
|  | } | 
|  | } | 
|  | }</pre> | 
|  |  | 
|  | <p>Running the above code results in the following:</p> | 
|  |  | 
|  | <img src="images/LayoutExample.jpg" /> | 
|  |  | 
|  | <p>If the user resizes the shell so that there is no longer room for | 
|  | Button 3 on the right, the <code>RowLayout</code> wraps Button 3 to the | 
|  | next row, as follows:</p> | 
|  |  | 
|  | <img src="images/LayoutExampleResized.jpg" /> | 
|  |  | 
|  | <p>Using layouts is closely tied with resize, as we shall see. | 
|  | Consequently, most of the examples in this document show what would | 
|  | happen if the <code>Composite</code> becomes smaller or larger, in order | 
|  | to illustrate how the <code>Layout</code> works.</p> | 
|  |  | 
|  | <h2>FillLayout</h2> | 
|  |  | 
|  | <p><code>FillLayout</code> is the simplest layout class. It lays out | 
|  | widgets in a single row or column, forcing them to be the same size. | 
|  | Initially, the widgets will all be as tall as the tallest widget, and as | 
|  | wide as the widest. <code>FillLayout</code> does not wrap, and you | 
|  | cannot specify margins or spacing. You might use it to lay out buttons | 
|  | in a task bar or tool bar, or to stack checkboxes in a <code>Group</code>. | 
|  | <code>FillLayout</code> can also be used when a <code>Composite</code> | 
|  | only has one child. For example, if a <code>Shell</code> has a single <code>Group</code> | 
|  | child, <code>FillLayout</code> will cause the <code>Group</code> to | 
|  | completely fill the <code>Shell</code>.</p> | 
|  |  | 
|  | <p>Here is the relevant portion of the example code. First we create | 
|  | a <code>FillLayout</code>, then (if we want vertical) we set its <code>type</code> | 
|  | field to <code>SWT.VERTICAL</code>, and set it into the <code>Composite</code> | 
|  | (a <code>Shell</code>). The <code>Shell</code> has three push button | 
|  | children, "B1", "Wide Button 2", and "Button | 
|  | 3". Note that in a <code>FillLayout</code>, children are always the | 
|  | same size, and they fill all available space.</p> | 
|  |  | 
|  | <pre>FillLayout fillLayout = new FillLayout(); | 
|  | fillLayout.type = SWT.VERTICAL; | 
|  | shell.setLayout(fillLayout); | 
|  | new Button(shell, SWT.PUSH).setText("B1"); | 
|  | new Button(shell, SWT.PUSH).setText("Wide Button 2"); | 
|  | new Button(shell, SWT.PUSH).setText("Button 3");</pre> | 
|  |  | 
|  | <p>The following table shows the differences between a horizontal | 
|  | and vertical <code>FillLayout</code>, initially and after the parent has | 
|  | grown.</p> | 
|  |  | 
|  | <table> | 
|  | <tr> | 
|  | <td> </td> | 
|  | <td> | 
|  | <p>Initial</p> | 
|  | </td> | 
|  | <td> | 
|  | <p>After resize</p> | 
|  | </td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><code>fillLayout.type = SWT.HORIZONTAL</code> | 
|  | <p>(default)</p> | 
|  | </td> | 
|  | <td><img src="images/FillLayoutSampleHorizontal.jpg" /></td> | 
|  | <td><img src="images/FillLayoutSampleHorizontalResized.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><code>fillLayout.type = SWT.VERTICAL</code></td> | 
|  | <td><img src="images/FillLayoutSampleVertical.jpg" /></td> | 
|  | <td><img src="images/FillLayoutSampleVerticalResized.jpg" /></td> | 
|  | </tr> | 
|  | </table> | 
|  |  | 
|  | <h2>RowLayout</h2> | 
|  |  | 
|  | <p><code>RowLayout</code> is more commonly used than <code>FillLayout</code> | 
|  | because of its ability to wrap, and because it provides configurable | 
|  | margins and spacing. <code>RowLayout</code> has a number of | 
|  | configuration fields. In addition, the height and width of each widget | 
|  | in a <code>RowLayout</code> can be specified by setting the widget's <code>RowData</code> | 
|  | object using <code>setLayoutData</code>.</p> | 
|  |  | 
|  | <h3>RowLayoutConfiguration Fields</h3> | 
|  |  | 
|  | <p>The <code>type</code> field controls whether the <code>RowLayout</code> | 
|  | lays out widgets in horizontal rows, or vertical columns. <code>RowLayouts</code> | 
|  | are horizontal by default.</p> | 
|  |  | 
|  | <p>The <code>wrap</code> field controls whether or not the <code>RowLayout</code> | 
|  | will wrap widgets into the next row if there isn't enough space in the | 
|  | current row. <code>RowLayouts</code> wrap by default.</p> | 
|  |  | 
|  | <p>If the <code>pack</code> field is true, widgets in a <code>RowLayout</code> | 
|  | will take their natural size ("natural size" varies by widget; | 
|  | the natural size for a label or push button, for example, is large enough to | 
|  | display its textual contents), and they will be aligned as far to the | 
|  | left as possible. If pack is false, widgets will fill the available | 
|  | space, similar to the widgets in a <code>FillLayout</code>. <code>RowLayouts</code> | 
|  | pack by default.</p> | 
|  |  | 
|  | <p>If the <code>justify</code> field is true, widgets in a <code>RowLayout</code> | 
|  | are spread across the available space from left to right. If the parent | 
|  | <code>Composite</code> grows wider, the extra space is distributed | 
|  | evenly among the widgets. If both <code>pack</code> and <code>justify</code> | 
|  | are true, widgets take their natural size, and the extra space is placed | 
|  | between the widgets in order to keep them fully justified. By default, <code>RowLayouts</code> | 
|  | do not justify.</p> | 
|  |  | 
|  | <p>The <code>marginLeft</code>, <code>marginTop</code>, <code>marginRight</code>, | 
|  | <code>marginBottom</code> and <code>spacing</code> fields control the | 
|  | number of pixels between widgets (<code>spacing</code>) and the number | 
|  | of pixels between a widget and the side of the parent <code>Composite</code> | 
|  | (margin). By default, <code>RowLayouts</code> leave 3 pixels for margins | 
|  | and spacing. The margin and spacing fields are shown in the following | 
|  | diagram.</p> | 
|  |  | 
|  | <img src="images/RowLayoutMargins.jpg" /> | 
|  |  | 
|  | <h3>RowLayout Examples</h3> | 
|  |  | 
|  | <p>The following example code creates a <code>RowLayout</code>, sets | 
|  | all of its fields to non-default values, and then sets it into a <code>Shell</code>.</p> | 
|  |  | 
|  | <pre>RowLayout rowLayout = new RowLayout(); | 
|  | rowLayout.wrap = false; | 
|  | rowLayout.pack = false; | 
|  | rowLayout.justify = true; | 
|  | rowLayout.type = SWT.VERTICAL; | 
|  | rowLayout.marginLeft = 5; | 
|  | rowLayout.marginTop = 5; | 
|  | rowLayout.marginRight = 5; | 
|  | rowLayout.marginBottom = 5; | 
|  | rowLayout.spacing = 0; | 
|  | shell.setLayout(rowLayout);</pre> | 
|  |  | 
|  | <p>If you are using the default field values, you only need one line | 
|  | of code:</p> | 
|  |  | 
|  | <pre>shell.setLayout(new RowLayout());</pre> | 
|  |  | 
|  | <p>The results of setting specific fields is shown below:</p> | 
|  |  | 
|  | <table> | 
|  | <tr> | 
|  | <td width="150"> </td> | 
|  | <td> | 
|  | <p>Initial</p> | 
|  | </td> | 
|  | <td> | 
|  | <p>After resize</p> | 
|  | </td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>rowLayout.wrap = true; | 
|  | rowLayout.pack = true; | 
|  | rowLayout.justify = false; | 
|  | rowLayout.type = SWT.HORIZONTAL;</pre> | 
|  | <p>(defaults)</p> | 
|  | </td> | 
|  | <td><img src="images/RowLayoutSample01.jpg" /></td> | 
|  | <td><img src="images/RowLayoutSample01Resized.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>wrap = false</pre> | 
|  | <p>(clips if not enough space)</p> | 
|  | </td> | 
|  | <td><img src="images/RowLayoutSample02.jpg" /></td> | 
|  | <td><img src="images/RowLayoutSample02Resized.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>pack = false</pre> | 
|  | <p>(all widgets are the same size)</p> | 
|  | </td> | 
|  | <td><img src="images/RowLayoutSample03.jpg" /></td> | 
|  | <td><img src="images/RowLayoutSample03Resized.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>justify = true</pre> | 
|  | <p>(widgets are spread across the available space)</p> | 
|  | </td> | 
|  | <td><img src="images/RowLayoutSample04.jpg" /></td> | 
|  | <td><img src="images/RowLayoutSample04Resized.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>type = SWT.VERTICAL</pre> | 
|  | <p>(widgets are arranged vertically in columns)</p> | 
|  | </td> | 
|  | <td><img src="images/RowLayoutSample05.jpg" /></td> | 
|  | <td><img src="images/RowLayoutSample05Resized.jpg" /></td> | 
|  | </tr> | 
|  | </table> | 
|  |  | 
|  | <h3>Using RowData Objects with RowLayout</h3> | 
|  |  | 
|  | <p>Each widget controlled by a <code>RowLayout</code> can have its | 
|  | initial width and height specified by setting its <code>RowData</code> | 
|  | object. The following code uses <code>RowData</code> objects to change | 
|  | the initial size of the <code>Buttons</code> in a <code>Shell</code>.</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.*; | 
|  | import org.eclipse.swt.widgets.*; | 
|  | import org.eclipse.swt.layout.*; | 
|  |  | 
|  | public class RowDataExample { | 
|  |  | 
|  |    public static void main(String[] args) { | 
|  |        Display display = new Display(); | 
|  |        Shell shell = new Shell(display); | 
|  |        shell.setLayout(new RowLayout()); | 
|  |        Button button1 = new Button(shell, SWT.PUSH); | 
|  |        button1.setText("Button 1"); | 
|  |        button1.setLayoutData(new RowData(50, 40)); | 
|  |        Button button2 = new Button(shell, SWT.PUSH); | 
|  |        button2.setText("Button 2"); | 
|  |        button2.setLayoutData(new RowData(50, 30)); | 
|  |        Button button3 = new Button(shell, SWT.PUSH); | 
|  |        button3.setText("Button 3"); | 
|  |        button3.setLayoutData(new RowData(50, 20)); | 
|  |        shell.pack(); | 
|  |        shell.open(); | 
|  |  | 
|  |        while (!shell.isDisposed()) { | 
|  |           if (!display.readAndDispatch()) display.sleep(); | 
|  |        } | 
|  |    } | 
|  | }</pre> | 
|  |  | 
|  | <p>Here is what you see when you run this code.</p> | 
|  |  | 
|  | <img src="images/RowDataExample.jpg" /> | 
|  |  | 
|  | <h2>GridLayout</h2> | 
|  |  | 
|  | <p>With a <code>GridLayout</code>, | 
|  | the widget children of a <code>Composite</code> are laid out in a grid. | 
|  | <code>GridLayout</code> has a number of configuration fields, and—like | 
|  | <code>RowLayout</code>—the widgets it lays out can have an associated | 
|  | layout data object, called <code>GridData</code>. The power of <code>GridLayout</code> | 
|  | lies in the ability to configure <code>GridData</code> for each widget | 
|  | controlled by the <code>GridLayout</code>.</p> | 
|  |  | 
|  | <h3>GridLayout Configuration Fields</h3> | 
|  |  | 
|  | <p>The <code>numColumns</code> field is the most important field in | 
|  | a <code>GridLayout</code>, and it is usually the first field an | 
|  | application will set. Widgets are laid out in columns from left to | 
|  | right, and a new row is created when <code>numColumns</code> + 1 widgets | 
|  | are added to the <code>Composite</code>. The default is to have only 1 | 
|  | column. The following code creates a <code>Shell</code> with five <code>Button</code> | 
|  | children of various widths, managed by a <code>GridLayout</code>. The | 
|  | table below shows the grid when <code>numColumns</code> is set to one, two, | 
|  | or three.</p> | 
|  |  | 
|  | <pre>Display display = new Display(); | 
|  | Shell shell = new Shell(display); | 
|  | GridLayout gridLayout = new GridLayout(); | 
|  | gridLayout.numColumns = 3; | 
|  | shell.setLayout(gridLayout); | 
|  | new Button(shell, SWT.PUSH).setText("B1"); | 
|  | new Button(shell, SWT.PUSH).setText("Wide Button 2"); | 
|  | new Button(shell, SWT.PUSH).setText("Button 3"); | 
|  | new Button(shell, SWT.PUSH).setText("B4"); | 
|  | new Button(shell, SWT.PUSH).setText("Button 5"); | 
|  | shell.pack(); | 
|  | shell.open(); | 
|  |  | 
|  | while (!shell.isDisposed()) { | 
|  | if (!display.readAndDispatch()) display.sleep(); | 
|  | }</pre> | 
|  |  | 
|  | <table> | 
|  | <tr> | 
|  | <td><pre>numColumns = 1</pre></td> | 
|  | <td><pre>numColumns = 2</pre></td> | 
|  | <td><pre>numColumns = 3</pre></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><img src="images/GridLayoutSampleNumColumns1.jpg" /></td> | 
|  | <td><img src="images/GridLayoutSampleNumColumns2.jpg" /></td> | 
|  | <td><img src="images/GridLayoutSampleNumColumns3.jpg" /></td> | 
|  | </tr> | 
|  | </table> | 
|  |  | 
|  | <p>The <code>makeColumnsEqualWidth</code> field forces the columns | 
|  | to be the same width. The default is <code>false</code>. If we change the example | 
|  | above to have three columns of equal width, this is what we would get (note | 
|  | that in the absence of further instruction, widgets are left-justified | 
|  | in their columns).</p> | 
|  |  | 
|  | <img src="images/GridLayoutSampleEqualWidth.jpg" /> | 
|  |  | 
|  | <p>The <code>marginWidth</code>, <code>marginHeight</code>, <code>horizontalSpacing</code>, | 
|  | and <code>verticalSpacing</code> fields in a <code>GridLayout</code> are | 
|  | similar to those in a <code>RowLayout</code>. The difference is that the | 
|  | left and right margins are grouped into <code>marginWidth</code>, and | 
|  | the top and bottom margins are grouped into <code>marginHeight</code>. | 
|  | Also, in a <code>GridLayout</code> you can specify <code>horizontalSpacing</code> | 
|  | and <code>verticalSpacing</code> independently, whereas in a <code>RowLayout</code>, | 
|  | <code>spacing</code> applies to horizontal or vertical depending on the | 
|  | type of the <code>RowLayout</code>.</p> | 
|  |  | 
|  | <h3>GridData Object Fields</h3> | 
|  |  | 
|  | <p><code>GridData</code> is the layout data object associated with <code>GridLayout</code>. | 
|  | To set a widget's <code>GridData</code> object, you use the <code>setLayoutData</code> | 
|  | method. For example, to set the <code>GridData</code> for a <code>Button</code>, | 
|  | we could do the following:</p> | 
|  |  | 
|  | <pre>Button button1 = new Button(shell, SWT.PUSH); | 
|  | button1.setText("B1"); | 
|  | button1.setLayoutData(new GridData());</pre> | 
|  |  | 
|  | <p>Of course, this code just creates a <code>GridData</code> object | 
|  | with all of its fields set to their default values, which is the same as | 
|  | not setting the layout data at all. There are two ways to create a <code>GridData</code> | 
|  | object with certain fields set. The first is to set the fields directly:</p> | 
|  |  | 
|  | <pre>GridData gridData = new GridData(); | 
|  | gridData.horizontalAlignment = GridData.FILL; | 
|  | gridData.grabExcessHorizontalSpace = true; | 
|  | button1.setLayoutData(gridData);</pre> <img | 
|  | src="images/GridDataSampleHorizontalFill.jpg" /> | 
|  |  | 
|  | <p>The second is to take advantage of convenience API: style bits | 
|  | defined by <code>GridData</code>:</p> | 
|  |  | 
|  | <pre>button1.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));</pre> | 
|  |  | 
|  | <p>In fact, certain common style bit combinations are provided for | 
|  | further convenience:</p> | 
|  |  | 
|  | <pre>button1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));</pre> | 
|  |  | 
|  | <p>Note that <code>FILL_</code> convenience styles set both fill | 
|  | alignment <i>and</i> grab. <code>GridData</code> style bits can only be | 
|  | used for boolean and enumeration fields. Numeric fields must be set | 
|  | directly.</p> | 
|  |  | 
|  | <p>One final note about <code>GridData</code> objects before we get | 
|  | into their fields: do not reuse <code>GridData</code> objects. Every | 
|  | widget in a <code>Composite</code> that is managed by a <code>GridLayout</code> | 
|  | must have a unique <code>GridData</code> object. If the layout data for | 
|  | a widget in a <code>GridLayout</code> is null at layout time, a unique <code>GridData</code> | 
|  | object is created for it.</p> | 
|  |  | 
|  | <p>The <code>horizontalAlignment</code> and <code>verticalAlignment</code> | 
|  | fields specify where to place a widget horizontally and/or vertically | 
|  | within its grid cell. Each alignment field can have one of the following | 
|  | values:</p> | 
|  |  | 
|  | <ul> | 
|  | <li><code>BEGINNING</code></li> | 
|  | <li><code>CENTER</code></li> | 
|  | <li><code>END</code></li> | 
|  | <li><code>FILL</code></li> | 
|  | </ul> | 
|  |  | 
|  | <p>The default horizontalAlignment is BEGINNING (or left-aligned). | 
|  | The default verticalAlignment is CENTER.</p> | 
|  |  | 
|  | <p>Let's go back to our five-button example with three columns, and | 
|  | we will vary the <code>horizontalAlignment</code> of Button 5.</p> | 
|  |  | 
|  | <table> | 
|  | <tr> | 
|  | <td><pre>horizontalAlignment = GridData.BEGINNING</pre> | 
|  | <p>(default)</p> | 
|  | </td> | 
|  | <td><img src="images/GridDataSampleBeginning.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>horizontalAlignment = GridData.CENTER</pre></td> | 
|  | <td><img src="images/GridDataSampleCenter.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>horizontalAlignment = GridData.END</pre></td> | 
|  | <td><img src="images/GridDataSampleEnd.jpg" /></td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td><pre>horizontalAlignment = GridData.FILL</pre></td> | 
|  | <td><img src="images/GridDataSampleFill.jpg" /></td> | 
|  | </tr> | 
|  | </table> | 
|  |  | 
|  | <p>The <code>horizontalIndent</code> field allows you to move a | 
|  | widget to the right by a specified number of pixels. This field is | 
|  | typically only useful when the <code>horizontalAlignment</code> is <code>BEGINNING</code>. | 
|  | We cannot use a style bit to set the indent, so we will indent "Button 5" | 
|  | in our example by four pixels as follows:</p> | 
|  |  | 
|  | <pre>GridData gridData = new GridData(); | 
|  | gridData.horizontalIndent = 4; | 
|  | button5.setLayoutData(gridData);</pre> <img | 
|  | src="images/GridDataSampleIndent.jpg" /> | 
|  |  | 
|  | <p>The <code>horizontalSpan</code> and <code>verticalSpan</code> | 
|  | fields let widgets occupy more than one grid cell. They are often used | 
|  | in conjunction with <code>FILL</code> alignment. We can make "Button 5" in our example | 
|  | span the last two cells as follows:</p> | 
|  |  | 
|  | <pre>GridData gridData = new GridData(); | 
|  | gridData.horizontalAlignment = GridData.FILL; | 
|  | gridData.horizontalSpan = 2; | 
|  | button5.setLayoutData(gridData);</pre> <img | 
|  | src="images/GridDataSampleSpan01.jpg" /> | 
|  |  | 
|  | <p>If we decide to make "Wide Button 2" span two cells instead, we | 
|  | would end up with this:</p> | 
|  |  | 
|  | <pre>GridData gridData = new GridData(); | 
|  | gridData.horizontalAlignment = GridData.FILL; | 
|  | gridData.horizontalSpan = 2; | 
|  | button2.setLayoutData(gridData);</pre> <img | 
|  | src="images/GridDataSampleSpan02.jpg" /> | 
|  |  | 
|  | <p>Or we could make "Button 3" span two cells vertically:</p> | 
|  |  | 
|  | <pre>GridData gridData = new GridData(); | 
|  | gridData.verticalAlignment = GridData.FILL; | 
|  | gridData.verticalSpan = 2; | 
|  | button3.setLayoutData(gridData);</pre> <img | 
|  | src="images/GridDataSampleSpan03.jpg" /> | 
|  |  | 
|  | <p>The <code>grabExcessHorizontalSpace</code> and <code>grabExcessVerticalSpace</code> | 
|  | fields are typically used for larger widgets such as <code>Text,</code> | 
|  | <code>List</code> or <code>Canvas</code> to allow them to grow if their | 
|  | containing <code>Composite</code> grows. If a <code>Text</code> is | 
|  | grabbing excess horizontal space and the user resizes the <code>Shell</code> | 
|  | wider, then the <code>Text</code> will get all of the new horizontal | 
|  | space and other widgets in the same row will stay their original width. | 
|  | Of course, the widget that is grabbing excess space is also the first | 
|  | one to shrink when the <code>Shell</code> gets smaller. It is easiest to | 
|  | always think of the <b>grabExcessSpace</b> fields in the context of | 
|  | resizing. For a simple example, let's reuse the previous example where | 
|  | "Button 3" spanned two cells vertically. Here it is again:</p> | 
|  |  | 
|  | <img src="images/GridDataSampleSpan03.jpg" /> | 
|  |  | 
|  | <p>If we resize this window, the only thing that happens is that the | 
|  | window gets bigger:</p> | 
|  |  | 
|  | <img src="images/GridDataSampleSpan03Resized.jpg" /> | 
|  |  | 
|  | <p>Now we will tell "Button 3" to grab excess horizontal and vertical | 
|  | space, and "B1" and "B4" to fill vertically (without grabbing), and we | 
|  | resize the window again:</p> | 
|  |  | 
|  | <pre>Button button1 = new Button(shell, SWT.PUSH); | 
|  | button1.setText("B1"); | 
|  | GridData gridData = new GridData(); | 
|  | gridData.verticalAlignment = GridData.FILL; | 
|  | button1.setLayoutData(gridData); | 
|  |  | 
|  | new Button(shell, SWT.PUSH).setText("Wide Button 2"); | 
|  |  | 
|  | Button button3 = new Button(shell, SWT.PUSH); | 
|  | button3.setText("Button 3"); | 
|  | gridData = new GridData(); | 
|  | gridData.verticalAlignment = GridData.FILL; | 
|  | gridData.verticalSpan = 2; | 
|  | gridData.grabExcessVerticalSpace = true; | 
|  | gridData.horizontalAlignment = GridData.FILL; | 
|  | gridData.grabExcessHorizontalSpace = true; | 
|  | button3.setLayoutData(gridData); | 
|  |  | 
|  | Button button4 = new Button(shell, SWT.PUSH); | 
|  | button4.setText("B4"); | 
|  | gridData = new GridData(); | 
|  | gridData.verticalAlignment = GridData.FILL; | 
|  | button4.setLayoutData(gridData); | 
|  |  | 
|  | new Button(shell, SWT.PUSH).setText("Button 5");</pre> <img | 
|  | src="images/GridDataSampleGrab01.jpg" /> | 
|  |  | 
|  | <p>This time, "Button 3" grew in both directions, and "B4" grew | 
|  | vertically. The other buttons stayed their original sizes. Because | 
|  | "Button 3" was grabbing vertically and it spans two rows, the <i>last</i> | 
|  | row that it spans grew taller. Note that "B1" did not | 
|  | grow—although it is filling vertically—because its row did | 
|  | not grow. Since "Button 3" was grabbing horizontally, its column grew | 
|  | wider, and since it was filling horizontally, it grew wider to fill the | 
|  | column.</p> | 
|  |  | 
|  | <p>In a typical application window, you often want to have at least | 
|  | one widget that is grabbing. If more than one widget is trying to grab | 
|  | the same space, then the excess space is shared evenly among the | 
|  | grabbing widgets:</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.SWT; | 
|  | import org.eclipse.swt.layout.GridData; | 
|  | import org.eclipse.swt.layout.GridLayout; | 
|  | import org.eclipse.swt.widgets.Display; | 
|  | import org.eclipse.swt.widgets.Label; | 
|  | import org.eclipse.swt.widgets.List; | 
|  | import org.eclipse.swt.widgets.Shell; | 
|  | import org.eclipse.swt.widgets.Text; | 
|  |  | 
|  | public class SampleGrabExcess { | 
|  | public static void main(String[] args) { | 
|  | Display display = new Display(); | 
|  | Shell shell = new Shell(display); | 
|  | shell.setLayout(new GridLayout(2, false)); | 
|  |  | 
|  | Label nameLabel = new Label(shell, SWT.NONE); | 
|  | nameLabel.setText("Name:"); | 
|  |  | 
|  | Text nameText = new Text(shell, SWT.BORDER); | 
|  | GridData gridData = new GridData(); | 
|  | gridData.horizontalAlignment = SWT.FILL; | 
|  | gridData.grabExcessHorizontalSpace = true; | 
|  | nameText.setLayoutData(gridData); | 
|  | nameText.setText("Text grows horizontally"); | 
|  |  | 
|  | Label addressLabel = new Label(shell, SWT.NONE); | 
|  | addressLabel.setText("Address:"); | 
|  | gridData = new GridData(); | 
|  | gridData.verticalAlignment = SWT.TOP; | 
|  | addressLabel.setLayoutData(gridData); | 
|  |  | 
|  | Text addressText = new Text(shell, SWT.BORDER | SWT.WRAP | SWT.MULTI); | 
|  | gridData = new GridData(); | 
|  | gridData.horizontalAlignment = SWT.FILL; | 
|  | gridData.grabExcessHorizontalSpace = true; | 
|  | gridData.verticalAlignment = SWT.FILL; | 
|  | gridData.grabExcessVerticalSpace = true; | 
|  | addressText.setLayoutData(gridData); | 
|  | addressText.setText("This text field and the List\nbelow share any excess space."); | 
|  |  | 
|  | Label sportsLabel = new Label(shell, SWT.NONE); | 
|  | sportsLabel.setText("Sports played:"); | 
|  | gridData = new GridData(); | 
|  | gridData.horizontalSpan = 2; | 
|  | sportsLabel.setLayoutData(gridData); | 
|  |  | 
|  | List sportsList = new List(shell, SWT.BORDER | SWT.MULTI); | 
|  | gridData = new GridData(); | 
|  | gridData.horizontalSpan = 2; | 
|  | gridData.horizontalAlignment = SWT.FILL; | 
|  | gridData.grabExcessHorizontalSpace = true; | 
|  | gridData.verticalAlignment = SWT.FILL; | 
|  | gridData.grabExcessVerticalSpace = true; | 
|  | sportsList.setLayoutData(gridData); | 
|  | sportsList.add("Hockey"); | 
|  | sportsList.add("Street Hockey"); | 
|  |  | 
|  | shell.pack(); | 
|  | shell.open(); | 
|  |  | 
|  | while (!shell.isDisposed()) { | 
|  | if (!display.readAndDispatch()) | 
|  | display.sleep(); | 
|  | } | 
|  | } | 
|  | }</pre> <img src="images/GridLayoutGrabExcess.jpg" />      | 
|  | <p>When resized, the single line (top-most) <code>Text</code> grows | 
|  | to consume all available horizontal space, and the second <code>Text</code> | 
|  | and the <code>List</code> grow to consume all remaining space (both | 
|  | vertically and horizontally):</p> | 
|  |  | 
|  | <img src="images/GridLayoutGrabExcessResized.jpg" /> | 
|  |  | 
|  | <p>One final point to note about grabbing: if a widget is set to | 
|  | grab excess horizontal space and its parent <code>Composite</code> grows | 
|  | wider, then the entire <i>column</i> containing that widget grows wider. | 
|  | If a widget is grabbing excess vertical space and its parent <code>Composite</code> | 
|  | grows taller, then the entire <i>row</i> containing that widget grows | 
|  | taller. The implication of this is that if any other widget in the | 
|  | affected column or row has <i>fill</i> alignment, then it will stretch | 
|  | also. Widgets that have beginning, center, or end alignment will not | 
|  | stretch: they will stay at the beginning, center or end of the wider | 
|  | column or taller row.</p> | 
|  |  | 
|  | <p>The <code>widthHint</code> and <code>heightHint</code> fields | 
|  | indicate the number of pixels wide or tall that you would like a widget | 
|  | to be, assuming that it does not conflict with other requirements in the | 
|  | <code>GridLayout</code>'s constraint system. Looking back at the | 
|  | five-button, three-column example, say we want "Button 5" to be 70 pixels | 
|  | wide and 40 pixels tall. We code it as follows:</p> | 
|  |  | 
|  | <pre>GridData gridData = new GridData(); | 
|  | gridData.widthHint = 70; | 
|  | gridData.heightHint = 40; | 
|  | button5.setLayoutData(gridData);</pre> | 
|  |  | 
|  | <p>The natural size of "Button 5" is shown in the window on the left, | 
|  | below, and the 70-pixel wide, 40-pixel tall "Button 5" is on the right.</p> | 
|  |  | 
|  | <img src="images/GridLayoutSampleNumColumns3.jpg" /> <img | 
|  | src="images/GridDataSampleSpan04.jpg" /> | 
|  |  | 
|  | <p>Note, however, that if the <code>horizontalAlignment</code> of | 
|  | "Button 5" was <code>FILL</code>, then the <code>GridLayout</code> would not have been | 
|  | able to honor the request for a width of 70 pixels.</p> | 
|  |  | 
|  | <p>One final comment about using width and height hints: something | 
|  | that looks good on one platform may not look good on another. The | 
|  | variation between font sizes and natural widget sizes across platforms | 
|  | means that hard-coding pixel values is not usually the best way to lay | 
|  | out windows. So, keep the use of size hints to a minimum, if you use | 
|  | them at all.</p> | 
|  |  | 
|  | <h3>A Complex GridLayout Example</h3> | 
|  |  | 
|  | <p>So far, the <code>GridLayout</code> examples have been fairly | 
|  | simple, in order to show how each field works. Now, we will put them all | 
|  | together to create a more complicated example. We start by hand-drawing | 
|  | a rough sketch of the window we want to create, to determine things like | 
|  | how many columns the grid should contain, and whether or not any widgets | 
|  | need to span.</p> | 
|  | <img src="images/DogShowHandDrawn.gif" /> | 
|  |  | 
|  | <p>Then we start coding the example from the diagram. The code is | 
|  | below. Note that we have added a bit of logic to make the code more | 
|  | interesting, for example, "Browse..." opens a <code>FileDialog</code> | 
|  | to read an <code>Image</code> file which the <code>Canvas</code> | 
|  | displays in a paint listener, "Delete" deletes the <code>Image</code>, and | 
|  | Enter prints the current dog and owner info.</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.SWT; | 
|  | import org.eclipse.swt.events.DisposeEvent; | 
|  | import org.eclipse.swt.events.DisposeListener; | 
|  | import org.eclipse.swt.events.PaintEvent; | 
|  | import org.eclipse.swt.events.PaintListener; | 
|  | import org.eclipse.swt.events.SelectionAdapter; | 
|  | import org.eclipse.swt.events.SelectionEvent; | 
|  | import org.eclipse.swt.graphics.Image; | 
|  | import org.eclipse.swt.graphics.Rectangle; | 
|  | import org.eclipse.swt.layout.GridData; | 
|  | import org.eclipse.swt.layout.GridLayout; | 
|  | import org.eclipse.swt.widgets.Button; | 
|  | import org.eclipse.swt.widgets.Canvas; | 
|  | import org.eclipse.swt.widgets.Combo; | 
|  | import org.eclipse.swt.widgets.Display; | 
|  | import org.eclipse.swt.widgets.FileDialog; | 
|  | import org.eclipse.swt.widgets.Group; | 
|  | import org.eclipse.swt.widgets.Label; | 
|  | import org.eclipse.swt.widgets.List; | 
|  | import org.eclipse.swt.widgets.Shell; | 
|  | import org.eclipse.swt.widgets.Text; | 
|  |  | 
|  | public class DogShowRegistrationWindow { | 
|  | Text dogName; | 
|  | Combo dogBreed; | 
|  | Canvas dogPhoto; | 
|  | Image dogImage; | 
|  | List categories; | 
|  | Text ownerName; | 
|  | Text ownerPhone; | 
|  |  | 
|  | public static void main(String[] args) { | 
|  | Display display = new Display(); | 
|  | Shell shell = new DogShowRegistrationWindow().createShell(display); | 
|  | shell.open(); | 
|  | while (!shell.isDisposed()) { | 
|  | if (!display.readAndDispatch()) | 
|  | display.sleep(); | 
|  | } | 
|  | } | 
|  |  | 
|  | public Shell createShell(final Display display) { | 
|  | final Shell shell = new Shell(display); | 
|  | shell.setText("Dog Show Entry"); | 
|  | GridLayout gridLayout = new GridLayout(); | 
|  | gridLayout.numColumns = 3; | 
|  | shell.setLayout(gridLayout); | 
|  |  | 
|  | new Label(shell, SWT.NONE).setText("Dog's Name:"); | 
|  |  | 
|  | dogName = new Text(shell, SWT.SINGLE | SWT.BORDER); | 
|  | GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL); | 
|  | gridData.horizontalSpan = 2; | 
|  | dogName.setLayoutData(gridData); | 
|  |  | 
|  | new Label(shell, SWT.NONE).setText("Breed:"); | 
|  |  | 
|  | dogBreed = new Combo(shell, SWT.NONE); | 
|  | dogBreed.setItems(new String[] { "Collie", "Pitbull", "Poodle", | 
|  | "Scottie", "Black Lab" }); | 
|  | dogBreed.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); | 
|  |  | 
|  | Label label = new Label(shell, SWT.NONE); | 
|  | label.setText("Categories"); | 
|  | label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); | 
|  |  | 
|  | new Label(shell, SWT.NONE).setText("Photo:"); | 
|  | dogPhoto = new Canvas(shell, SWT.BORDER); | 
|  | gridData = new GridData(GridData.FILL_BOTH); | 
|  | gridData.widthHint = 80; | 
|  | gridData.heightHint = 80; | 
|  | gridData.verticalSpan = 3; | 
|  | dogPhoto.setLayoutData(gridData); | 
|  | dogPhoto.addPaintListener(new PaintListener() { | 
|  | public void paintControl(final PaintEvent event) { | 
|  | if (dogImage != null) { | 
|  | event.gc.drawImage(dogImage, 0, 0); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL); | 
|  | categories.setItems(new String[] { "Best of Breed", "Prettiest Female", | 
|  | "Handsomest Male", "Best Dressed", "Fluffiest Ears", | 
|  | "Most Colors", "Best Performer", "Loudest Bark", | 
|  | "Best Behaved", "Prettiest Eyes", "Most Hair", "Longest Tail", | 
|  | "Cutest Trick" }); | 
|  | gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | 
|  | | GridData.VERTICAL_ALIGN_FILL); | 
|  | gridData.verticalSpan = 4; | 
|  | int listHeight = categories.getItemHeight() * 12; | 
|  | Rectangle trim = categories.computeTrim(0, 0, 0, listHeight); | 
|  | gridData.heightHint = trim.height; | 
|  | categories.setLayoutData(gridData); | 
|  |  | 
|  | Button browse = new Button(shell, SWT.PUSH); | 
|  | browse.setText("Browse..."); | 
|  | gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL); | 
|  | gridData.horizontalIndent = 5; | 
|  | browse.setLayoutData(gridData); | 
|  | browse.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent event) { | 
|  | String fileName = new FileDialog(shell).open(); | 
|  | if (fileName != null) { | 
|  | dogImage = new Image(display, fileName); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | Button delete = new Button(shell, SWT.PUSH); | 
|  | delete.setText("Delete"); | 
|  | gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | 
|  | | GridData.VERTICAL_ALIGN_BEGINNING); | 
|  | gridData.horizontalIndent = 5; | 
|  | delete.setLayoutData(gridData); | 
|  | delete.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent event) { | 
|  | if (dogImage != null) { | 
|  | dogImage.dispose(); | 
|  | dogImage = null; | 
|  | dogPhoto.redraw(); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | Group ownerInfo = new Group(shell, SWT.NONE); | 
|  | ownerInfo.setText("Owner Info"); | 
|  | gridLayout = new GridLayout(); | 
|  | gridLayout.numColumns = 2; | 
|  | ownerInfo.setLayout(gridLayout); | 
|  | gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL); | 
|  | gridData.horizontalSpan = 2; | 
|  | ownerInfo.setLayoutData(gridData); | 
|  |  | 
|  | new Label(ownerInfo, SWT.NONE).setText("Name:"); | 
|  | ownerName = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER); | 
|  | ownerName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); | 
|  |  | 
|  | new Label(ownerInfo, SWT.NONE).setText("Phone:"); | 
|  | ownerPhone = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER); | 
|  | ownerPhone.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); | 
|  |  | 
|  | Button enter = new Button(shell, SWT.PUSH); | 
|  | enter.setText("Enter"); | 
|  | gridData = new GridData(GridData.HORIZONTAL_ALIGN_END); | 
|  | gridData.horizontalSpan = 3; | 
|  | enter.setLayoutData(gridData); | 
|  | enter.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent event) { | 
|  | System.out.println("\nDog Name: " + dogName.getText()); | 
|  | System.out.println("Dog Breed: " + dogBreed.getText()); | 
|  | System.out.println("Owner Name: " + ownerName.getText()); | 
|  | System.out.println("Owner Phone: " + ownerPhone.getText()); | 
|  | System.out.println("Categories:"); | 
|  | String cats[] = categories.getSelection(); | 
|  | for (int i = 0; i > cats.length; i++) { | 
|  | System.out.println("\t" + cats[i]); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | shell.addDisposeListener(new DisposeListener() { | 
|  | public void widgetDisposed(DisposeEvent arg0) { | 
|  | if (dogImage != null) { | 
|  | dogImage.dispose(); | 
|  | dogImage = null; | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | shell.pack(); | 
|  |  | 
|  | return shell; | 
|  | } | 
|  | }</pre> | 
|  |  | 
|  |  | 
|  | <p>Here is what the window looks like after Mary Smith enters | 
|  | Bifford in the dog show:</p> | 
|  | <img src="images/DogShowBiff.jpg" /> | 
|  |  | 
|  | <p>If this window is resized larger, the layout adjusts as follows:</p> | 
|  |  | 
|  | <img src="images/DogShowBiffResized.jpg" /> | 
|  |  | 
|  | <p>Notice the following:</p> | 
|  | <ul> | 
|  | <li>There are three columns and seven rows.</li> | 
|  | <li>The <code>dogPhoto</code> <code>Canvas</code> grew wider and | 
|  | taller because it is filling and grabbing horizontally and vertically | 
|  | (we did not resize the <code>Image</code>, but we could have).</li> | 
|  |  | 
|  | <li>The <code>dogBreed</code> <code>Combo</code> grew wider | 
|  | because it is filling horizontally, and it is in the same column as the | 
|  | <code>Canvas</code>.</li> | 
|  |  | 
|  | <li>The <code>dogName</code> <code>Text</code> grew wider because | 
|  | it is filling horizontally, and one of the columns it spans is the | 
|  | column containing the <code>Canvas</code>.</li> | 
|  |  | 
|  | <li>The <code>categories</code> <code>List</code> grew taller | 
|  | because it is filling vertically, and it spans the same rows that the <code>Canvas</code> | 
|  | does.</li> | 
|  |  | 
|  | <li>Because the <code>categories</code> <code>List</code> grew | 
|  | taller, its vertical scrollbar disappeared (it did not grow wider).</li> | 
|  |  | 
|  | <li>The <code>ownerInfo</code> <code>Group</code> grew wider | 
|  | because it is filling horizontally, and one of the columns it spans is | 
|  | the column containing the <code>Canvas</code>.</li> | 
|  |  | 
|  | <li>The <code>ownerInfo</code> <code>Group</code>, as a subclass | 
|  | of <code>Composite</code>, has its own <code>GridLayout</code> with 2 | 
|  | columns and 2 rows.</li> | 
|  |  | 
|  | <li>The <code>ownerName</code> and <code>ownerPhone</code> <code>Texts</code> | 
|  | grew wider because the <code>Group</code> grew wider, and they are | 
|  | filling and grabbing horizontally in the <code>Group</code>'s <code>GridLayout</code>.</li> | 
|  |  | 
|  | <li>The <code>browse</code> and <code>delete</code> <code>Buttons</code> | 
|  | are indented slightly, and because they both fill horizontally, they | 
|  | are the same width.</li> | 
|  |  | 
|  | <li>The <code>delete</code> <code>Button</code> is vertically | 
|  | aligned at the top of its row.</li> | 
|  |  | 
|  | <li>The "Categories" <code>Label</code> is centered over | 
|  | the <code>categories</code> <code>List</code>. | 
|  | </p> | 
|  | <li>The <code>enter</code> <code>Button</code> is horizontally | 
|  | aligned to the right of the 3 columns it spans.</li> | 
|  |  | 
|  | <li>The <code>dogPhoto</code> <code>Canvas</code> was created with | 
|  | width and height hints because we want the <code>Image</code> to be 80 | 
|  | pixels x 80 pixels, if possible.</li> | 
|  |  | 
|  | <li>The <code>categories</code> <code>List</code> was created with | 
|  | a height hint that was based on the <code>List</code>'s font times 12, | 
|  | because we want try to get the <code>List</code> to show 12 items | 
|  | initially.</li> | 
|  | </ul> | 
|  |  | 
|  | <h2>FormLayout</h2> | 
|  |  | 
|  | <p><code>FormLayout</code> works by creating <code>FormAttachment</code>s | 
|  | for each side of the widget, and storing them in the layout data. An | 
|  | attachment 'attaches' a specific side of the widget either to a position | 
|  | in the parent <code>Composite</code> or to another widget within the | 
|  | layout. This provides tremendous flexibility when laying out, as it | 
|  | allows you to specify the placement of individual widgets within the | 
|  | layout.</p> | 
|  |  | 
|  | <h3>FormLayout Configuration Fields</h3> | 
|  |  | 
|  | <p>The <code>marginWidth</code>, and <code>MarginHeight</code> | 
|  | fields in <code>FormLayout</code> are similar to those in <code>GridLayout</code>. | 
|  | Left and right margins are defined by <code>marginWidth</code>, and top | 
|  | and bottom margins are defined by <code>marginHeight</code>. Margins can | 
|  | also be defined on a per-widget basis in the attachments. <code>FormLayout</code> | 
|  | margins are zero by default.</p> | 
|  |  | 
|  | <p>To set the margins, we create a <code>FormLayout</code>, and set | 
|  | the margin fields. The following code will set a margin of five pixels | 
|  | around all four sides of the parent <code>Composite</code>:</p> | 
|  |  | 
|  | <pre>Display display = new Display (); | 
|  | Shell shell = new Shell (display); | 
|  | FormLayout layout= new FormLayout (); | 
|  | layout.marginHeight = 5; | 
|  | layout.marginWidth = 5; | 
|  | shell.setLayout(layout);</pre> | 
|  |  | 
|  | <h3>FormData Object Fields</h3> | 
|  |  | 
|  | <p><code>FormData</code> objects specify how each widget in a <code>FormLayout</code> | 
|  | will be laid out. Each <code>FormData</code> object defines the | 
|  | attachments for all four sides of the widget. These attachments tell | 
|  | where to position each side of the widget. To set a widget's <code>FormData</code> | 
|  | object, you use the <code>setLayoutData(Object)</code> method, for example:</p> | 
|  |  | 
|  | <pre>Button button1 = new Button(shell, SWT.PUSH); | 
|  | button1.setText("B1"); | 
|  | button1.setLayoutData(new FormData());</pre> | 
|  |  | 
|  | <p>This code creates a <code>FormData</code> object with no | 
|  | attachments. In this case, default attachments are defined, which | 
|  | defeats the whole purpose and utility of <code>FormLayout</code>. The | 
|  | default attachments attach the widget to the top and left edges of the | 
|  | parent <code>Composite</code>. If every widget in a <code>FormLayout</code> | 
|  | used the default attachments, they would all be laid out one on top of | 
|  | another in the top left corner of the parent <code>Composite</code>.</p> | 
|  |  | 
|  | <p>The <code>left</code>, <code>right</code>, <code>top</code>, and | 
|  | <code>bottom</code> fields of <code>FormData</code> specify the <code>FormAttachment</code> | 
|  | objects that are associated with the left, right, top and bottom sides | 
|  | of the widget, respectively. These fields are set in the following | 
|  | example:</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(); | 
|  | formData.top = new FormAttachment(0,60); | 
|  | formData.bottom = new FormAttachment(100,-5); | 
|  | formData.left = new FormAttachment(20,0); | 
|  | formData.right = new FormAttachment(100,-3); | 
|  | button1.setLayoutData(formData);</pre> <img | 
|  | src="images/FormLayoutSample01.jpg" /> | 
|  |  | 
|  | <p>A <code>FormAttachment</code> object defines the attachment of a | 
|  | specific side of a widget. There are many ways that a side can be | 
|  | attached: to a position in the parent <code>Composite</code>, to an edge | 
|  | of the <code>Composite</code>, to the adjacent side of another widget, | 
|  | to the opposite side of another widget, or centered on another widget. | 
|  | Attaching to a position places the side of the widget so that it is | 
|  | always at a percentage of the <code>Composite</code>. To attach to an | 
|  | edge of the <code>Composite</code>, the percentage is either 0% or 100%. | 
|  | Attaching to the adjacent side of another widget ensures that the | 
|  | specified side of the widget is always next to the closest side of the | 
|  | other widget. Attaching to the opposite side of another widget ensures | 
|  | that the specific side of the widget is aligned with the furthest side | 
|  | of the other widget. Finally, attaching to the center of another widget | 
|  | centers the widget on the other widget. Any of these ways can be done | 
|  | with or without an offset.</p> | 
|  |  | 
|  | <p>The <code>width</code> and <code>height</code> fields of <code>FormData</code> | 
|  | specify the requested width and the height of the widget. If a requested | 
|  | width or height conflicts with constraints set by the attachments, then | 
|  | that width or height will not be honored. Although setting attachments can | 
|  | also determine width and height, there are some cases when you do not | 
|  | want to define attachments for all sides of the widget. In this case, it | 
|  | may be useful to set the width and height of the widget as follows:</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(20,30); | 
|  | formData.top = new FormAttachment(0,60); | 
|  | formData.left = new FormAttachment(20,0); | 
|  | button1.setLayoutData(formData);</pre> | 
|  |  | 
|  | <p>If you wish to set only the width or the height, you can directly | 
|  | set the width or height field in the <code>FormData</code> object:</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(); | 
|  | formData.width = 30; | 
|  | formData.top = new FormAttachment(0,60); | 
|  | formData.bottom = new FormAttachment(100,-5); | 
|  | formData.left = new FormAttachment(20,0); | 
|  | button1.setLayoutData(formData);</pre> | 
|  |  | 
|  | <p>Note that if a button is attached to the parent <code>Composite</code> | 
|  | on both sides, when the <code>Composite</code> is resized, the button | 
|  | will grow or shrink along with it.</p> | 
|  |  | 
|  | <h3>FormAttachment Objects</h3> | 
|  |  | 
|  | <p>A <code>FormAttachment</code> is an object that defines the | 
|  | attachment for a specific side of a widget. It is not always necessary | 
|  | to set an attachment for all four sides of a widget. Often, specifying | 
|  | one or more sides of a widget can fully specify its placement in the | 
|  | layout. In order to properly place your widgets, you should define an | 
|  | attachment for at least one of <code>left</code> or <code>right</code> | 
|  | in the <code>FormData</code>, and at least one of <code>top</code> or <code>bottom</code>. | 
|  | If you only wish to attach the left side of a widget and not the right, | 
|  | then the widget will be positioned based on its left side, and the | 
|  | widget will take its natural size (or its requested size, if one was set | 
|  | for it). If you do not attach the left or the right, default positioning | 
|  | will attach your widget to the left side of the form. The same logic | 
|  | applies for the top and bottom sides.</p> | 
|  |  | 
|  | <h3>Attaching to a Position</h3> | 
|  | <p>There are many types of attachment. The first is to attach the | 
|  | widget to a position in the parent <code>Composite</code>. This can be | 
|  | done by defining a percentage value out of 100, for example:</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(); | 
|  | formData.top = new FormAttachment(50,0); | 
|  | button1.setLayoutData(formData);</pre> <img | 
|  | src="images/FormLayoutSamplePosition50.jpg" /> | 
|  |  | 
|  | <p>This sets the top of the <code>Button</code> to a position that | 
|  | represents 50% of the height of the parent <code>Composite</code> (a <code>Shell</code>), | 
|  | with an offset of 0. When the shell is resized, the top side of the <code>Button</code> | 
|  | will still be at 50%, like so:</p> | 
|  |  | 
|  | <img src="images/FormLayoutSamplePosition50Resized.jpg" /> | 
|  |  | 
|  | <p>If we chose to set an offset value, the top side of the <code>Button</code> | 
|  | would have been set to 50% of the <code>Composite</code> plus or minus | 
|  | the number of pixels set for the offset.</p> | 
|  |  | 
|  | <p>We can also define the position of the button using an arbitrary scale, for example:</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(); | 
|  | formData.top = new FormAttachment(30,70,10); | 
|  | button1.setLayoutData(formData);</pre> | 
|  |  | 
|  | <p>If the height of the <code>Composite</code> is defined as being | 
|  | 70 units, this sets the top of the <code>Button</code> to a position | 
|  | representing 30 units down from the top of the <code>Composite</code>, | 
|  | plus 10 pixels (i.e. 3/7ths of the height of the composite plus 10 pixels).</p> | 
|  |  | 
|  | <p>To attach a side of a widget to an edge of | 
|  | the parent <code>Composite</code>, set the position to either 0% or 100%. The 0 | 
|  | position is defined as the top of the <code>Composite</code> when going | 
|  | vertically, and the left when going horizontally. The right and bottom | 
|  | edges of the <code>Composite</code> are defined as the 100 position. | 
|  | Therefore, if we want to attach a widget to the right edge of the <code>Composite</code>, | 
|  | we simply have to create an attachment that sets the position to 100:</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(); | 
|  | formData.right = new FormAttachment(100,-5); | 
|  | button1.setLayoutData(formData);</pre> <img | 
|  | src="images/FormLayoutSampleParent100.jpg" /> | 
|  |  | 
|  | <p>This attaches the right side of the <code>Button</code> to the | 
|  | right edge of the parent (a <code>Shell</code>), with an offset of five | 
|  | pixels. Note that the offsets go in one direction only. If you want a | 
|  | widget offset down or to the right, the offset should be positive. For | 
|  | offsets that shift the widget up or to the left, the offset should be | 
|  | negative. When the <code>Shell</code> is resized, the <code>Button</code> | 
|  | will always be five pixels away from the right edge:</p> | 
|  |  | 
|  | <img src="images/FormLayoutSampleParent100Resized.jpg" /> | 
|  |  | 
|  | <h3>Attaching to Another Widget</h3> | 
|  | <p>The third type of attachment is to attach the side of the widget | 
|  | to another control within the parent <code>Composite</code>. The side | 
|  | can be attached to the adjacent side of the other control (the default), | 
|  | to the opposite side of the other control, or the widget can be centered | 
|  | on the other control, all with or without and offset.</p> | 
|  |  | 
|  | <p>The most common way to attach to another control is to attach to | 
|  | its adjacent side. For example, the following code:</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(); | 
|  | formData.top = new FormAttachment(20,0); | 
|  | button1.setLayoutData(formData); | 
|  |  | 
|  | FormData formData2 = new FormData(); | 
|  | formData2.top = new FormAttachment(button1,10); | 
|  | button2.setLayoutData(formData2);</pre> <img | 
|  | src="images/FormLayoutSampleAttachWidget01.jpg" /> | 
|  |  | 
|  | <p>This example attaches the top of button2 to the bottom of | 
|  | button1. Note that when the window is resized, button1 will move so that | 
|  | its top side is always positioned at 20% of the <code>Shell</code>, and | 
|  | button2 will move so that its top side is always 10 pixels below the | 
|  | adjacent (bottom) side of button1.</p> | 
|  |  | 
|  | <img src="images/FormLayoutSampleAttachWidget01Resized.jpg" /> | 
|  |  | 
|  | <p>While the default is to attach the side of a widget to the | 
|  | adjacent side of a control, <code>FormAttachment</code>s can also be | 
|  | created to attach to the opposite side of a control. This is useful when | 
|  | lining up widgets. In this case, you create the attachment to the other | 
|  | control using <code>TOP</code>, <code>BOTTOM</code>, <code>LEFT</code> | 
|  | or <code>RIGHT</code> alignment, for example:</p> | 
|  |  | 
|  | <pre>formData2.top = new FormAttachment(button1,0,SWT.TOP);</pre> | 
|  |  | 
|  | <p>In the following example, the top side of <code>button1</code> is positioned | 
|  | at 20% of the <code>Shell</code>. <code>button2</code>'s top side is aligned with | 
|  | <code>button1</code>'s top side, using <code>TOP</code> alignment. This means that the top side of | 
|  | <code>button2</code> is also positioned at 20% of the <code>Shell</code>. Note that | 
|  | when specifying the top attachment, only the vertical placement of the | 
|  | widget is being defined. It is still necessary to set the left | 
|  | attachment for <code>button2</code> so that the <code>Button</code>s are not stacked | 
|  | on top of each other.</p> | 
|  |  | 
|  | <pre>FormData formData = new FormData(50,50); | 
|  | formData.top = new FormAttachment(20,0); | 
|  | button1.setLayoutData(formData); | 
|  |  | 
|  | FormData formData2 = new FormData(); | 
|  | formData2.left = new FormAttachment(button1,5); | 
|  | formData2.top = new FormAttachment(button1,0,SWT.TOP); | 
|  | button2.setLayoutData(formData2);</pre> <img | 
|  | src="images/FormLayoutSampleAttachWidget02.jpg" /> | 
|  |  | 
|  | <p>The final way to attach a widget to another control is to center | 
|  | it on the other control. This is useful when the widgets are different | 
|  | sizes. In this case, you create the attachment to the other control with | 
|  | <code>CENTER</code> alignment, for example:</p> | 
|  |  | 
|  | <pre>formData.top = new FormAttachment(button1,0,SWT.CENTER);</pre> | 
|  |  | 
|  | <p>This will place the top of the widget in a position that will | 
|  | allow the widget to be centered on the other control, with an offset of | 
|  | 0. Setting only the top, or the bottom, or both as a center attachment | 
|  | will produce the same result. The top side of the widget is not | 
|  | centered, but the entire widget is centered, so this only needs to be | 
|  | specified once. Here is an example:</p> | 
|  |  | 
|  | <pre>FormData formData1 = new FormData (50,50); | 
|  | button1.setLayoutData(formData1); | 
|  |  | 
|  | FormData formData2 = new FormData (); | 
|  | formData2.left = new FormAttachment (button1,5); | 
|  | formData2.top = new FormAttachment (button1,0,SWT.CENTER); | 
|  | button2.setLayoutData(formData2);</pre> <img | 
|  | src="images/FormLayoutSampleAttachWidget03.jpg" /> | 
|  |  | 
|  | <p>Using the different types of <code>FormAttachment</code> allows | 
|  | layouts to be defined in many different ways. <code>FormLayout</code> | 
|  | covers certain cases that cannot be solved using <code>FillLayout</code>, | 
|  | <code>RowLayout</code> or <code>GridLayout</code>, making it a very | 
|  | useful class for defining layouts.</p> | 
|  |  | 
|  | <p><b>Important: </b>Do <b>not</b> define circular | 
|  | attachments. For example, do not attach the right edge of button1 | 
|  | to the left edge of button2 and then attach the left edge button2 to the | 
|  | right edge of button1. This will over-constrain the layout, causing | 
|  | undefined behavior. The algorithm will terminate, but the results | 
|  | are undefined. Therefore, make sure that you do not over-constrain your | 
|  | widgets. Only provide the attachments necessary to properly lay out the | 
|  | widgets.</p> | 
|  |  | 
|  | <h3>A FormLayout Example</h3> | 
|  |  | 
|  | <p>So far, all the examples using <code>FormLayout</code> have | 
|  | involved one or two <code>Button</code>s, to show how <code>FormAttachment</code>s | 
|  | work. Next, we will do a simple example using more <code>Button</code>s | 
|  | to show how a layout can be arranged using the attachments. We'll start | 
|  | by drawing a basic diagram outlining the attachments that we wish to | 
|  | create.</p> | 
|  |      <img src="images/FormExampleHandDrawn.jpg" /> | 
|  |  | 
|  | <pre>FormData data1 = new FormData(); | 
|  | data1.left = new FormAttachment(0,5); | 
|  | data1.right = new FormAttachment(25,0); | 
|  | button1.setLayoutData(data1); | 
|  |  | 
|  | FormData data2 = new FormData(); | 
|  | data2.left = new FormAttachment(button1,5); | 
|  | data2.right = new FormAttachment(100,-5); | 
|  | button2.setLayoutData(data2); | 
|  |  | 
|  | FormData data3 = new FormData(60,60); | 
|  | data3.top = new FormAttachment(button1,5); | 
|  | data3.left = new FormAttachment(50,-30); | 
|  | data3.right = new FormAttachment(50,30); | 
|  | button3.setLayoutData(data3); | 
|  |  | 
|  | FormData data4 = new FormData(); | 
|  | data4.top = new FormAttachment(button3,5); | 
|  | data4.bottom = new FormAttachment(100,-5); | 
|  | data4.left = new FormAttachment(25,0); | 
|  | button4.setLayoutData(data4); | 
|  |  | 
|  | FormData data5 = new FormData(); | 
|  | data5.bottom = new FormAttachment(100,-5); | 
|  | data5.left = new FormAttachment(button4,5); | 
|  | button5.setLayoutData(data5);</pre> | 
|  |  | 
|  | <p>In this case, since no top attachment was defined for <code>button1</code> or | 
|  | <code>button2</code>, they are attached to the top of the layout. <code>button3</code> is centred | 
|  | in the layout using percentages and offsets on the left and right sides. | 
|  | <code>button4</code> and <code>button5</code> are attached to the bottom of the layout with a five | 
|  | pixel offset.</p> | 
|  |  | 
|  | <img src="images/FormLayoutSample5Buttons01.jpg" /> | 
|  |  | 
|  | <p>When we resize, the attachments become more visible. <code>button1</code> is | 
|  | attached on the left and the right side, so when the window is resized, | 
|  | it grows. Note that the right side will always be at 25% of the window. | 
|  | The same resize results apply for <code>button2</code>, as both sides are attached. | 
|  | The left side is attached to <code>button1</code>, so it will always be at 25% plus five | 
|  | pixels. <code>button3</code> stays in the center of the window, horizontally. <code>button4</code> | 
|  | is attached at the top and the bottom, so it grows vertically when the | 
|  | window is resized, but it is only attached on the left and not the | 
|  | right, so it does not grow horizontally. <code>button5</code> will not grow or | 
|  | shrink, but it will always stay five pixels away from <code>button4</code> on the left, | 
|  | and five pixels away from the bottom of the window.</p> | 
|  |  | 
|  | <img src="images/FormLayoutSample5Buttons01Resized.jpg" /> | 
|  |  | 
|  | <h3>A Complex FormLayout Example</h3> | 
|  |  | 
|  | <p>To illustrate how <code>FormLayout</code> can be used for more | 
|  | complicated arrangements, the Dog Show Entry example done previously for | 
|  | <code>GridLayout</code> is redone using <code>FormLayout</code>. This | 
|  | code produces an identical layout, but uses different concepts to | 
|  | achieve it.</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.SWT; | 
|  | import org.eclipse.swt.events.PaintEvent; | 
|  | import org.eclipse.swt.events.PaintListener; | 
|  | import org.eclipse.swt.events.SelectionAdapter; | 
|  | import org.eclipse.swt.events.SelectionEvent; | 
|  | import org.eclipse.swt.graphics.Image; | 
|  | import org.eclipse.swt.layout.FormAttachment; | 
|  | import org.eclipse.swt.layout.FormData; | 
|  | import org.eclipse.swt.layout.FormLayout; | 
|  | import org.eclipse.swt.widgets.Button; | 
|  | import org.eclipse.swt.widgets.Canvas; | 
|  | import org.eclipse.swt.widgets.Combo; | 
|  | import org.eclipse.swt.widgets.Display; | 
|  | import org.eclipse.swt.widgets.FileDialog; | 
|  | import org.eclipse.swt.widgets.Group; | 
|  | import org.eclipse.swt.widgets.Label; | 
|  | import org.eclipse.swt.widgets.List; | 
|  | import org.eclipse.swt.widgets.Shell; | 
|  | import org.eclipse.swt.widgets.Text; | 
|  |  | 
|  | public class DogShowRegistrationWindowWithFormLayout { | 
|  | Image dogImage; | 
|  | Text dogNameText; | 
|  | Combo dogBreedCombo; | 
|  | Canvas dogPhoto; | 
|  | List categories; | 
|  | Text nameText; | 
|  | Text phoneText; | 
|  |  | 
|  | public static void main(String[] args) { | 
|  | Display display = new Display(); | 
|  | Shell shell = new DogShowRegistrationWindow().createShell(display); | 
|  | shell.open(); | 
|  | while (!shell.isDisposed()) { | 
|  | if (!display.readAndDispatch()) | 
|  | display.sleep(); | 
|  | } | 
|  | } | 
|  |  | 
|  | public Shell createShell(final Display display) { | 
|  | final Shell shell = new Shell(display); | 
|  | FormLayout layout = new FormLayout(); | 
|  | layout.marginWidth = 5; | 
|  | layout.marginHeight = 5; | 
|  | shell.setLayout(layout); | 
|  | shell.setText("Dog Show Entry"); | 
|  |  | 
|  | Group ownerInfo = new Group(shell, SWT.NONE); | 
|  | ownerInfo.setText("Owner Info"); | 
|  | FormLayout ownerLayout = new FormLayout(); | 
|  | ownerLayout.marginWidth = 5; | 
|  | ownerLayout.marginHeight = 5; | 
|  | ownerInfo.setLayout(ownerLayout); | 
|  |  | 
|  | Label dogName = new Label(shell, SWT.NONE); | 
|  | dogName.setText("Dog's Name:"); | 
|  | dogNameText = new Text(shell, SWT.SINGLE | SWT.BORDER); | 
|  |  | 
|  | Label dogBreed = new Label(shell, SWT.NONE); | 
|  | dogBreed.setText("Breed:"); | 
|  |  | 
|  | dogBreedCombo = new Combo(shell, SWT.NONE); | 
|  | dogBreedCombo.setItems(new String[] { "Collie", "Pitbull", "Poodle", | 
|  | "Scottie", "Black Lab" }); | 
|  |  | 
|  | Label photo = new Label(shell, SWT.NONE); | 
|  | photo.setText("Photo:"); | 
|  | dogPhoto = new Canvas(shell, SWT.BORDER); | 
|  |  | 
|  | Button browse = new Button(shell, SWT.PUSH); | 
|  | browse.setText("Browse..."); | 
|  |  | 
|  | Button delete = new Button(shell, SWT.PUSH); | 
|  | delete.setText("Delete"); | 
|  |  | 
|  | Label cats = new Label(shell, SWT.NONE); | 
|  | cats.setText("Categories"); | 
|  | categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | 
|  | | SWT.H_SCROLL); | 
|  | categories.setItems(new String[] { "Best of Breed", "Prettiest Female", | 
|  | "Handsomest Male", "Best Dressed", "Fluffiest Ears", | 
|  | "Most Colors", "Best Performer", "Loudest Bark", | 
|  | "Best Behaved", "Prettiest Eyes", "Most Hair", "Longest Tail", | 
|  | "Cutest Trick" }); | 
|  |  | 
|  | Button enter = new Button(shell, SWT.PUSH); | 
|  | enter.setText("Enter"); | 
|  | FormData data = new FormData(); | 
|  | data.top = new FormAttachment(dogNameText, 0, SWT.CENTER); | 
|  | dogName.setLayoutData(data); | 
|  | data = new FormData(); | 
|  | data.left = new FormAttachment(dogName, 5); | 
|  | data.right = new FormAttachment(100, 0); | 
|  | dogNameText.setLayoutData(data); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.top = new FormAttachment(dogBreedCombo, 0, SWT.CENTER); | 
|  | dogBreed.setLayoutData(data); | 
|  | data = new FormData(); | 
|  | data.top = new FormAttachment(dogNameText, 5); | 
|  | data.left = new FormAttachment(dogNameText, 0, SWT.LEFT); | 
|  | data.right = new FormAttachment(categories, -5); | 
|  | dogBreedCombo.setLayoutData(data); | 
|  |  | 
|  | data = new FormData(80, 80); | 
|  | data.top = new FormAttachment(dogBreedCombo, 5); | 
|  | data.left = new FormAttachment(dogNameText, 0, SWT.LEFT); | 
|  | data.right = new FormAttachment(categories, -5); | 
|  | data.bottom = new FormAttachment(ownerInfo, -5); | 
|  | dogPhoto.setLayoutData(data); | 
|  | dogPhoto.addPaintListener(new PaintListener() { | 
|  | public void paintControl(final PaintEvent event) { | 
|  | if (dogImage != null) { | 
|  | event.gc.drawImage(dogImage, 0, 0); | 
|  | } | 
|  | } | 
|  | }); | 
|  | data = new FormData(); | 
|  | data.top = new FormAttachment(dogPhoto, 0, SWT.TOP); | 
|  | photo.setLayoutData(data); | 
|  | data = new FormData(); | 
|  | data.top = new FormAttachment(photo, 5); | 
|  | data.right = new FormAttachment(dogPhoto, -5); | 
|  | browse.setLayoutData(data); | 
|  | browse.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent event) { | 
|  | String fileName = new FileDialog(shell).open(); | 
|  | if (fileName != null) { | 
|  | dogImage = new Image(display, fileName); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.left = new FormAttachment(browse, 0, SWT.LEFT); | 
|  | data.top = new FormAttachment(browse, 5); | 
|  | data.right = new FormAttachment(dogPhoto, -5); | 
|  | delete.setLayoutData(data); | 
|  | delete.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent event) { | 
|  | if (dogImage != null) { | 
|  | dogImage.dispose(); | 
|  | dogImage = null; | 
|  | dogPhoto.redraw(); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | data = new FormData(90, 140); | 
|  | data.top = new FormAttachment(dogPhoto, 0, SWT.TOP); | 
|  | data.right = new FormAttachment(100, 0); | 
|  | data.bottom = new FormAttachment(enter, -5); | 
|  | categories.setLayoutData(data); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.bottom = new FormAttachment(categories, -5); | 
|  | data.left = new FormAttachment(categories, 0, SWT.CENTER); | 
|  | cats.setLayoutData(data); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.right = new FormAttachment(100, 0); | 
|  | data.bottom = new FormAttachment(100, 0); | 
|  | enter.setLayoutData(data); | 
|  | enter.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent event) { | 
|  | System.out.println("\nDog Name: " + dogNameText.getText()); | 
|  | System.out.println("Dog Breed: " + dogBreedCombo.getText()); | 
|  | System.out.println("Owner Name: " + nameText.getText()); | 
|  | System.out.println("Owner Phone: " + phoneText.getText()); | 
|  | System.out.println("Categories:"); | 
|  | String cats[] = categories.getSelection(); | 
|  | for (int i = 0; i < cats.length; i++) { | 
|  | System.out.println("\t" + cats[i]); | 
|  | } | 
|  | } | 
|  | }); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.bottom = new FormAttachment(enter, -5); | 
|  | data.left = new FormAttachment(0, 0); | 
|  | data.right = new FormAttachment(categories, -5); | 
|  | ownerInfo.setLayoutData(data); | 
|  |  | 
|  | Label name = new Label(ownerInfo, SWT.NULL); | 
|  | name.setText("Name:"); | 
|  |  | 
|  | Label phone = new Label(ownerInfo, SWT.PUSH); | 
|  | phone.setText("Phone:"); | 
|  |  | 
|  | nameText = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER); | 
|  | phoneText = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.top = new FormAttachment(nameText, 0, SWT.CENTER); | 
|  | name.setLayoutData(data); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.top = new FormAttachment(phoneText, 0, SWT.CENTER); | 
|  | phone.setLayoutData(data); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.left = new FormAttachment(phone, 5); | 
|  | data.right = new FormAttachment(100, 0); | 
|  | nameText.setLayoutData(data); | 
|  |  | 
|  | data = new FormData(); | 
|  | data.left = new FormAttachment(nameText, 0, SWT.LEFT); | 
|  | data.right = new FormAttachment(100, 0); | 
|  | data.top = new FormAttachment(55, 0); | 
|  | phoneText.setLayoutData(data); | 
|  |  | 
|  | shell.pack(); | 
|  |  | 
|  | return shell; | 
|  | } | 
|  | }</pre> | 
|  |  | 
|  | <p>This is what the layout looks like after Mary Smith enters | 
|  | Bifford in the dog show:</p> | 
|  |  | 
|  | <img src="images/DogShowBiffWithFormLayout.jpg" /> | 
|  |  | 
|  | </p> | 
|  | <p>When the window is resized, the same controls are resized as in | 
|  | the <code>GridLayout</code> example.</p> | 
|  |  | 
|  | <img src="images/DogShowBiffWithFormLayoutResized.jpg" /> | 
|  |  | 
|  | <h2>Writing Your Own Layout Class</h2> | 
|  |  | 
|  | <p>Occasionally, you may want to write your own <code>Layout</code> | 
|  | class. Perhaps your layout needs are very complex. Maybe you have the | 
|  | same look in many places, and you want to take advantage of code reuse. | 
|  | Or you want to leverage domain knowledge to create a very efficient | 
|  | layout class. Whatever the reason, there are things to consider before | 
|  | writing a new class:</p> | 
|  |  | 
|  | <ul> | 
|  | <li>Can the layout be done using a <code>GridLayout</code> or <code>FormLayout</code>, | 
|  | with maybe a few nested layouts?</li> | 
|  | <li>Can the desired effect be more easily achieved with a resize | 
|  | listener?</li> | 
|  | <li>Are you defining a general layout algorithm or just | 
|  | positioning widgets?</li> | 
|  | </ul> | 
|  |  | 
|  | <p>Unless you are writing a very generic <code>Layout</code> type | 
|  | that will be used by several <code>Composite</code> widgets, it is often | 
|  | better and easier to simply calculate sizes and position children in a | 
|  | resize listener. Many of the SWT custom widgets were written this way. | 
|  | Although a new widget can be implemented as a <code>Composite</code>/<code>Layout</code> | 
|  | pair, implementing it as a <code>Composite</code> that does its layout | 
|  | in a resize listener and computes its preferred size in <code>computeSize</code> | 
|  | is clearer, and does not involve writing an extra class.</p> | 
|  |  | 
|  | <p>First, we will look at how layouts work, and then we will create | 
|  | a new <code>Layout</code> class. Another example of writing your own <code>Layout</code> | 
|  | can be found in the <i>Compound Widget Example</i> section of <a | 
|  | href="http://www.eclipse.org/articles/Article-Writing%20Your%20Own%20Widget/Writing%20Your%20Own%20Widget.htm">Creating | 
|  | Your Own Widgets Using SWT</a>, which shows how to achieve the same look | 
|  | using either a resize listener or a new <code>Layout</code> class.</p> | 
|  |  | 
|  | <h3>How Layouts Work</h3> | 
|  |  | 
|  | <p><code>Layout</code> is the abstract superclass of all layouts. It | 
|  | only has two methods: <code>computeSize</code> and <code>layout</code>. | 
|  | The class is defined as follows:</p> | 
|  |  | 
|  | <pre>public abstract class Layout { | 
|  | protected abstract Point computeSize(Composite composite, int widthHint, int heightHint, boolean flushCache); | 
|  | protected abstract void layout(Composite composite, boolean flushCache); | 
|  | }</pre> | 
|  |  | 
|  | <p>The <code>computeSize</code> method calculates the width and | 
|  | height of a rectangle that encloses all of the <code>Composite</code>'s | 
|  | children once they have been sized and placed according to the layout | 
|  | algorithm encoded in the <code>Layout</code> class. The hint parameters | 
|  | allow the width and/or height to be constrained. For example, a layout | 
|  | may choose to grow in one dimension if constrained in another. A hint of | 
|  | SWT.DEFAULT means to use the preferred size.</p> | 
|  |  | 
|  | <p>The <code>layout</code> method positions and sizes the <code>Composite</code>'s | 
|  | children. A <code>Layout</code> can choose to cache layout-related | 
|  | information, such as the preferred extent of each of the children. The <code>flushCache</code> | 
|  | parameter tells the <code>Layout</code> to flush cached data.</p> | 
|  |  | 
|  | <p>Since a <code>Layout</code> controls the size and placement of | 
|  | widgets in a <code>Composite</code>, there are several methods in <code>Composite</code> | 
|  | that are used with <code>Layout</code>s.</p> | 
|  |  | 
|  | <p>The first two methods allow setting and getting a <code>Layout</code> | 
|  | object in a <code>Composite</code>.</p> | 
|  |  | 
|  | <pre>public void setLayout(Layout layout); | 
|  | public Layout getLayout();</pre> | 
|  |  | 
|  | <p>An application can force a <code>Layout</code> to recalculate the | 
|  | sizes of and reposition children by sending <code>layout()</code> to the | 
|  | parent <code>Composite</code>.</p> | 
|  |  | 
|  | <pre>public void layout(boolean changed); | 
|  | public void layout(); | 
|  | // calls layout(true);</pre> | 
|  |  | 
|  | <p>You would do this after changing anything about the children that | 
|  | might affect their size or position, such as changing the font of a | 
|  | child, changing the text or image of a child, adding a new child, or | 
|  | adding children to a child (If the child can accommodate the change, | 
|  | then layout may not be necessary – for example, changing the font or | 
|  | text of a scrollable multi-line <code>Text</code>). Since these changes | 
|  | are done programmatically, they do not cause events to happen. | 
|  | Consequently, the parent doesn't know about the changes, and has to be | 
|  | told through the <code>layout</code> method. This strategy reduces flash | 
|  | because the application can make several changes and then tell the | 
|  | parent to layout, and the children are only redrawn once instead of once | 
|  | per change. If <code>layout()</code> is not called and changes are made | 
|  | after the shell is opened, then the children may not be correctly laid | 
|  | out until the shell is somehow resized. Note that <code>shell.open()</code> | 
|  | causes a layout to occur.</p> | 
|  |  | 
|  | <p>The <code>computeSize</code> methods of a <code>Composite</code> | 
|  | calculate the Composite's preferred size, which is the size of its | 
|  | client area as determined by the <code>Layout</code>, plus its trim.</p> | 
|  |  | 
|  | <pre>public Point computeSize(int widthHint, int heightHint, boolean changed); | 
|  | public Point computeSize(int widthHint, int heightHint); | 
|  | // calls computeSize(widthHint, heightHint, true);</pre> | 
|  |  | 
|  | <p>The <b>clientArea</b> of a <code>Composite</code> is the | 
|  | rectangle that will contain all of the children. A <code>Layout</code> | 
|  | positions the children inside the client area.</p> | 
|  |  | 
|  | <pre>public Rectangle getClientArea ();</pre> | 
|  |  | 
|  | <p>The <b>trim</b> of a <code>Composite</code> is the area outside | 
|  | the client area. For some composites, the size of the trim is zero. The | 
|  | trim can be computed by passing the dimensions of the client area into | 
|  | the method <code>computeTrim</code>.</p> | 
|  |  | 
|  | <pre>public Rectangle computeTrim (int x, int y, int width, int height);</pre> | 
|  |  | 
|  | <p>Sending <code>pack</code> to a <code>Composite</code> resizes it | 
|  | to its preferred size.</p> | 
|  |  | 
|  | <pre>public void pack(boolean changed); | 
|  | // calls setSize(computeSize(SWT.DEFAULT, SWT.DEFAULT, changed)); | 
|  | public void pack(); | 
|  | // calls pack(true);</pre> | 
|  |  | 
|  | <p>The boolean parameter to the <code>layout</code>, <code>computeSize</code>, | 
|  | and <code>pack</code> methods is the <code>changed</code> flag. If <code>true</code>, | 
|  | it indicates that the <code>Composite</code>'s contents have changed in | 
|  | some way that affects its preferred size, therefore any caches that the | 
|  | <code>Layout</code> may have been keeping need to be flushed. When a <code>Composite</code> | 
|  | is resized, it asks its <code>Layout</code> to lay out its children by | 
|  | calling layout(false); therefore widget content caches are <i>not</i> | 
|  | flushed. This lets the <code>Layout</code> perform any expensive | 
|  | calculations only when necessary.</p> | 
|  |  | 
|  | <p>Caching can increase performance, but it can also be tricky. You | 
|  | can choose not to cache at all: in fact, it is best not to try caching | 
|  | until your code is stable. When considering what to cache, be certain | 
|  | not to store any widget state, such as the text of a label, or the | 
|  | number of items in a list.</p> | 
|  |  | 
|  | <h3>Custom Layout Example</h3> | 
|  |  | 
|  | <p>If you have several vertically oriented <code>Composite</code> | 
|  | widgets in your application, you might choose to write <code>ColumnLayout</code>. | 
|  | We will show a simple version of a <code>Layout</code> class that lays | 
|  | out <code>Composite</code> children into a single column. The class has | 
|  | fixed margins and spacing. Children are given the same width, but they | 
|  | take their natural height. (Note that <code>RowLayout</code> will have <code>ColumnLayout</code> | 
|  | behaviour if its type is set to <code>SWT.VERTICAL</code>. This example is, | 
|  | therefore, just an example. In practice, if you need to lay widgets out | 
|  | in a column, you would use <code>RowLayout.</code>)</p> | 
|  |  | 
|  | <p>The code for the <code>ColumnLayout</code> class is below. Note | 
|  | that we cache the width of the widest child, and the sum of the child | 
|  | heights (plus spacing), and these values are used to compute the size | 
|  | and lie out the children. They are recalculated if <code>flushCache</code> | 
|  | is <code>true</code>.</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.*; | 
|  | import org.eclipse.swt.graphics.*; | 
|  | import org.eclipse.swt.widgets.*; | 
|  | import org.eclipse.swt.layout.*; | 
|  |  | 
|  | public class ColumnLayout extends Layout { | 
|  | // fixed margin and spacing | 
|  | public static final int MARGIN = 4; | 
|  | public static final int SPACING = 2; | 
|  | // cache | 
|  | Point[] sizes; | 
|  | int maxWidth, totalHeight; | 
|  |  | 
|  | protected Point computeSize(Composite composite, int wHint, int hHint, | 
|  | boolean flushCache) { | 
|  | Control children[] = composite.getChildren(); | 
|  | if (flushCache || sizes == null || sizes.length != children.length) { | 
|  | initialize(children); | 
|  | } | 
|  | int width = wHint, height = hHint; | 
|  | if (wHint == SWT.DEFAULT) | 
|  | width = maxWidth; | 
|  | if (hHint == SWT.DEFAULT) | 
|  | height = totalHeight; | 
|  | return new Point(width + 2 * MARGIN, height + 2 * MARGIN); | 
|  | } | 
|  |  | 
|  | protected void layout(Composite composite, boolean flushCache) { | 
|  | Control children[] = composite.getChildren(); | 
|  | if (flushCache || sizes == null || sizes.length != children.length) { | 
|  | initialize(children); | 
|  | } | 
|  | Rectangle rect = composite.getClientArea(); | 
|  | int x = MARGIN, y = MARGIN; | 
|  | int width = Math.max(rect.width - 2 * MARGIN, maxWidth); | 
|  | for (int i = 0; i < children.length; i++) { | 
|  | int height = sizes[i].y; | 
|  | children[i].setBounds(x, y, width, height); | 
|  | y += height + SPACING; | 
|  | } | 
|  | } | 
|  |  | 
|  | void initialize(Control children[]) { | 
|  | maxWidth = 0; | 
|  | totalHeight = 0; | 
|  | sizes = new Point[children.length]; | 
|  | for (int i = 0; i < children.length; i++) { | 
|  | sizes[i] = children[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, true); | 
|  | maxWidth = Math.max(maxWidth, sizes[i].x); | 
|  | totalHeight += sizes[i].y; | 
|  | } | 
|  | totalHeight += (children.length - 1) * SPACING; | 
|  | } | 
|  | }</pre> | 
|  |  | 
|  | <p>Here is some simple test code to test the <code>ColumnLayout</code>. | 
|  | The <b>grow</b> and <b>shrink</b> <code>Buttons</code> show a call to | 
|  | the <code>Shell</code>'s <code>layout()</code> method to force a | 
|  | re-layout after changing the width of one of the children. Calling <code>layout()</code> | 
|  | is the same as calling <code>layout(true</code>) which tells the <code>ColumnLayout</code> | 
|  | to flush its caches before setting the bounds of the children. The <code>Shell</code> | 
|  | is also told to <code>pack()</code> after laying out the children. This | 
|  | forces the <code>Shell</code> to take the new size.</p> | 
|  |  | 
|  | <pre>import org.eclipse.swt.*; | 
|  | import org.eclipse.swt.widgets.*; | 
|  | import org.eclipse.swt.layout.*; | 
|  | import org.eclipse.swt.events.*; | 
|  |  | 
|  | public class ColumnLayoutTest { | 
|  | static Shell shell; | 
|  | static Button button3; | 
|  |  | 
|  | public static void main(String[] args) { | 
|  | Display display = new Display(); | 
|  | shell = new Shell(display); | 
|  | shell.setLayout(new ColumnLayout()); | 
|  | new Button(shell, SWT.PUSH).setText("B1"); | 
|  | new Button(shell, SWT.PUSH).setText("Very Wide Button 2"); | 
|  | (button3 = new Button(shell, SWT.PUSH)).setText("Button 3"); | 
|  | Button grow = new Button(shell, SWT.PUSH); | 
|  | grow.setText("Grow Button 3"); | 
|  | grow.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent e) { | 
|  | button3.setText("Extreemely Wide Button 3"); | 
|  | shell.layout(); | 
|  | shell.pack(); | 
|  | } | 
|  | }); | 
|  | Button shrink = new Button(shell, SWT.PUSH); | 
|  | shrink.setText("Shrink Button 3"); | 
|  | shrink.addSelectionListener(new SelectionAdapter() { | 
|  | public void widgetSelected(SelectionEvent e) { | 
|  | button3.setText("Button 3"); | 
|  | shell.layout(); | 
|  | shell.pack(); | 
|  | } | 
|  | }); | 
|  | shell.pack(); | 
|  | shell.open(); | 
|  | while (!shell.isDisposed()) { | 
|  | if (!display.readAndDispatch()) | 
|  | display.sleep(); | 
|  | } | 
|  | } | 
|  | }</pre> | 
|  |  | 
|  | <p>If we run the test code, the window on the left appears. Pressing | 
|  | the Grow Button 3 button results in the window on the right. Resizing | 
|  | the window with the mouse will also make the buttons wider (or narrower) | 
|  | but they do not grow taller.</p> | 
|  |  | 
|  | <img src="images/CustomLayout.jpg" /> <img | 
|  | src="images/CustomLayoutResized.jpg" /> | 
|  |  | 
|  | <h3>Overriding Composite</h3> | 
|  |  | 
|  | <p>If you are writing your own widget, as outlined in <a | 
|  | href="http://www.eclipse.org/articles/Article-Writing%20Your%20Own%20Widget/Writing%20Your%20Own%20Widget.htm">Creating | 
|  | Your Own Widgets Using SWT</a>, and you subclass Composite, then here are a | 
|  | few points to consider for your implementation:</a></p> | 
|  |  | 
|  | <ul> | 
|  | <li>If you are providing trimmings in your new <code>Composite</code>, | 
|  | make sure to override both <code>computeTrim()</code> and <code>getClientArea()</code>.</li> | 
|  | <li>Never override <code>layout()</code>, but you may override <code>layout(boolean)</code>.</li> | 
|  | </ul> | 
|  |  | 
|  | <p>Sometimes you want your new <code>Composite</code> to have a | 
|  | specific look, and you don't want the application to be able to specify | 
|  | a layout. Your new <code>Composite</code> would either do its layout in | 
|  | a resize handler or using a private custom layout. In either case, you | 
|  | will probably want to do the following:</p> | 
|  |  | 
|  | <ul> | 
|  | <li>Override <code>setLayout()</code> to do nothing.</li> | 
|  | <li>Override <code>layout(boolean)</code> to call your layout | 
|  | code.</li> | 
|  | <li>Override <code>computeSize()</code> to correctly compute the | 
|  | size of your <code>Composite</code>.</li> | 
|  | </ul> | 
|  |  | 
|  |  | 
|  | <h2>Summary</h2> | 
|  |  | 
|  | <p>SWT provides several different ways to lay out widgets. The | 
|  | simplest method, and the one you will typically use, is to use one of | 
|  | the standard <code>Layout</code> classes: <code>FillLayout</code>, <code>RowLayout</code>, | 
|  | <code>GridLayout</code> or <code>FormLayout</code>.</p> | 
|  |  | 
|  |  | 
|  | <p>In certain cases you may want to write your own <code>Layout</code> | 
|  | class to provide a very specific look or to reuse very similar layout | 
|  | code, but often a resize listener on the parent widget will suffice.</p> | 
|  |  | 
|  |  | 
|  |  | 
|  | <p>For further assistance in understanding the standard SWT <code>Layout</code> | 
|  | classes, see the <a href="http://www.eclipse.org/swt/snippets">SWT Snippets</a>.</p> | 
|  | </div> | 
|  |  | 
|  | </body> | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | </html> |