Understanding Layouts in SWT

Understanding Layouts in SWT

Summary

When writing applications in SWT, you may need to use layouts to give your windows a specific look. A layout controls the position and size of children in aComposite. Layout classes are subclasses of the abstract class Layout. This article shows you how to work with standard layouts, and write your own custom layout class.

By Carolyn MacLeod, OTI
March 22, 2001
Revised by Shantha Ramachandran, OTI
May 02, 2002
Revised by Wayne Beaton, The Eclipse Foundation
May 30, 2008
Revised by Wayne Beaton, The Eclipse Foundation
May 13, 2009

Overview

When writing applications in the Standard Widget Toolkit (SWT), you may need to use layouts to give your windows a specific look. A layout controls the position and size of children in a Composite. Layout classes are subclasses of the abstract class Layout. SWT provides several standard layout classes, and you can write custom layout classes.

In SWT, positioning and sizing does not happen automatically. Applications can decide to size and place a Composite'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.

The diagram below illustrates a few general terms that are used when discussing layouts. The Composite (in this case, a TabFolder) has a locationclientArea and trim. The size of the Composite is the size of the clientArea plus the size of the trim. This Composite has two children that are laid out side by side. A Layout is managing the size and position of the children. This Layout allows spacing between the children, and a margin between the children and the edges of the Layout. The size of the Layout is the same as the size of theComposite's clientArea.

The preferred size of a widget is the minimum size needed to show its content. In the case of a Composite, the preferred size is the smallest rectangle that contains all of its children. If children have been positioned by the application, the Composite computes its own preferred size based on the size and position of the children. If a Composite is using a layout class to position its children, it asks the Layout to compute the size of its clientArea, and then it adds in the trim to determine its preferred size.

Standard Layouts

The standard layout classes in the SWT library are:

  • FillLayout lays out equal-sized widgets in a single row or column
  • RowLayout lays out widgets in a row or rows, with fill, wrap, and spacing options
  • GridLayout lays out widgets in a grid
  • FormLayout lays out widgets by creating attachments for each of their sides

To use the standard layouts, you need to import the SWT layout package:

import org.eclipse.swt.layout.*;

Layouts are pluggable. To set a Composite widget's layout, you use the widget's setLayout(Layout) method. In the following code, a Shell (a subclass of Composite) is told to position its children using a RowLayout:

Shell shell = new Shell();
shell.setLayout(new RowLayout());

A layout class may have a corresponding layout data class: a subclass of Object 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 RowLayout has a layout data class called RowData, the layout class GridLayout uses a layout data class called GridData, and the layout class FormLayout has a layout data class called FormData. A widget's layout data class is set as follows:

Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(new RowData(50, 40));

Examples in this Document

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.

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();
        }
    }
}

Running the above code results in the following:

If the user resizes the shell so that there is no longer room for Button 3 on the right, the RowLayout wraps Button 3 to the next row, as follows:

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 Composite becomes smaller or larger, in order to illustrate how the Layout works.

FillLayout

FillLayout 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. FillLayout 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 aGroupFillLayout can also be used when a Composite only has one child. For example, if a Shell has a single Group child, FillLayout will cause the Group to completely fill the Shell.

Here is the relevant portion of the example code. First we create a FillLayout, then (if we want vertical) we set its type field to SWT.VERTICAL, and set it into the Composite (aShell). The Shell has three push button children, "B1", "Wide Button 2", and "Button 3". Note that in a FillLayout, children are always the same size, and they fill all available space.

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");

The following table shows the differences between a horizontal and vertical FillLayout, initially and after the parent has grown.

 

Initial

After resize

fillLayout.type = SWT.HORIZONTAL

(default)

fillLayout.type = SWT.VERTICAL

RowLayout

RowLayout is more commonly used than FillLayout because of its ability to wrap, and because it provides configurable margins and spacing. RowLayout has a number of configuration fields. In addition, the height and width of each widget in a RowLayout can be specified by setting the widget's RowData object using setLayoutData.

RowLayoutConfiguration Fields

The type field controls whether the RowLayout lays out widgets in horizontal rows, or vertical columns. RowLayouts are horizontal by default.

The wrap field controls whether or not the RowLayout will wrap widgets into the next row if there isn't enough space in the current row. RowLayouts wrap by default.

If the pack field is true, widgets in a RowLayout 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 FillLayout.RowLayouts pack by default.

If the justify field is true, widgets in a RowLayout are spread across the available space from left to right. If the parent Composite grows wider, the extra space is distributed evenly among the widgets. If both pack and justify 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, RowLayouts do not justify.

The marginLeftmarginTopmarginRightmarginBottom and spacing fields control the number of pixels between widgets (spacing) and the number of pixels between a widget and the side of the parent Composite (margin). By default, RowLayouts leave 3 pixels for margins and spacing. The margin and spacing fields are shown in the following diagram.

RowLayout Examples

The following example code creates a RowLayout, sets all of its fields to non-default values, and then sets it into a Shell.

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);

If you are using the default field values, you only need one line of code:

shell.setLayout(new RowLayout());

The results of setting specific fields is shown below:

 

Initial

After resize

rowLayout.wrap = true;
rowLayout.pack = true;
rowLayout.justify = false;
rowLayout.type = SWT.HORIZONTAL;

(defaults)

and

wrap = false

(clips if not enough space)

pack = false

(all widgets are the same size)

justify = true

(widgets are spread across the available space)

type = SWT.VERTICAL

(widgets are arranged vertically in columns)

Using RowData Objects with RowLayout

Each widget controlled by a RowLayout can have its initial width and height specified by setting its RowData object. The following code uses RowData objects to change the initial size of the Buttons in a Shell.

package org.eclipse.articles.layouts.samples;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
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 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();
		}
	}
}

Here is what you see when you run this code.

GridLayout

With a GridLayout, the widget children of a Composite are laid out in a grid. GridLayout has a number of configuration fields, and—like RowLayout—the widgets it lays out can have an associated layout data object, called GridData. The power of GridLayout lies in the ability to configure GridData for each widget controlled by the GridLayout.

GridLayout Configuration Fields

The numColumns field is the most important field in a GridLayout, 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 numColumns + 1 widgets are added to the Composite. The default is to have only 1 column. The following code creates a Shell with five Button children of various widths, managed by a GridLayout. The table below shows the grid when numColumns is set to one, two, or three.

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();
}
numColumns = 1
numColumns = 2
numColumns = 3

The makeColumnsEqualWidth field forces the columns to be the same width. The default is false. 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).

The marginWidthmarginHeighthorizontalSpacing, and verticalSpacing fields in a GridLayout are similar to those in a RowLayout. The difference is that the left and right margins are grouped into marginWidth, and the top and bottom margins are grouped into marginHeight. Also, in a GridLayout you can specify horizontalSpacing and verticalSpacingindependently, whereas in a RowLayoutspacing applies to horizontal or vertical depending on the type of the RowLayout.

GridData Object Fields

GridData is the layout data object associated with font-style: normal; font-weight: normal; f

分享到:
评论

你可能感兴趣的:(eclipse,windows,F#)