Home Tutorials Training Consulting Books Company Contact us


Get more...

This tutorial describes the usage of SWT for building user interfaces.

1. SWT overview

1.1. Using SWT and JFace

The Standard Widget Toolkit (SWT) is a Java-based user interface library for developing desktop applications. SWT supports Windows, Linux, and macOS.

It provides many standard widgets, such as buttons and text fields, as well as the option to create custom widgets.

SWT uses the native widgets of the platform whenever possible. The native widgets of the operating system are accessed by the SWT framework via the Java Native Interface (JNI). If a widget is not natively available on a platform, SWT emulates this widget on that platform.

JFace adds additional functionality on top of SWT, making it easier to use. In this description, we use the JFace builder API on top of the SWT API to simplify the creation of SWT-based user interfaces.

1.2. Display and Shell

The Display and Shell classes are key components of SWT applications.

An org.eclipse.swt.widgets.Shell class represents a window.

The org.eclipse.swt.widgets.Display class is responsible for managing event loops, fonts, and colors. It also controls communication between the user interface thread and other threads. Display is therefore the basis for all SWT capabilities.

Every SWT application requires at least one Display and one or more Shell instances.

1.3. Event loop

An event loop transfers user input events from the underlying native operating system widgets to the SWT event system.

The programmer explicitly starts and checks the event loop to update the user interface. The loop calls the readAndDispatch() method, which retrieves events from the native operating system event queue and dispatches them to the SWT event system. Without this loop, the application will terminate immediately. The loop is executed until the main shell is closed.

For example, the following creates an SWT application that sets up and executes the event loop.

Display display = new Display();
Shell shell = new Shell(display);
shell.open();

while (!shell.isDisposed()) { (1)
    if (!display.readAndDispatch()) (2)
     { display.sleep();} (3)
}

// disposes all associated windows and their components
display.dispose();
1 run the event loop as long as the window is open
2 read the next OS event queue and transfer it to an SWT event
3 if there are currently no other OS events to process, sleep until the next OS event is available

If SWT is used for an Eclipse IDE plug-in or an Eclipse RCP application, the event loop is provided by the Eclipse framework.

1.4. Using SWT in a Java project

The SWT and JFace libraries are provided as JAR files and are also available via Maven Central for Maven and Gradle builds. The SWT library can be found at https://mvnrepository.com/artifact/org.eclipse.platform/org.eclipse.swt.

You must specify the osgi.platform property in your POM file to use the correct version of the SWT library for your operating system.

To use the dependency in your Maven project, add the following to your POM file.

<properties>
    <osgi.platform>gtk.linux.x86_64</osgi.platform>
    <maven.compiler.release>21</maven.compiler.release>
</properties>
<dependencies>
    <dependency>
        <groupId>org.eclipse.platform</groupId>
        <artifactId>org.eclipse.swt</artifactId>
        <version>3.129.0</version> (1)
    </dependency>
</dependencies>
1 Use the latest version of the SWT library available at https://mvnrepository.com/artifact/org.eclipse.platform/org.eclipse.swt.

The supported values for the osgi.platform are listed in the following table.

osgi.platform Description

win32.win32.x86_64

Windows 64-bit

linux.gtk.x86_64

Linux 64-bit with GTK

linux.gtk.aarch64

Linux ARM 64-bit with GTK

macosx.cocoa.x86_64

macOS 64-bit (Intel) with Cocoa

macosx.cocoa.aarch64

macOS ARM 64-bit (Apple Silicon) with Cocoa

For correct dependency resolution, you need to specify the osgi.platform during the build process.

$ mvn clean verify -Dosgi.platform=gtk.linux.x86_64

1.5. Using SWT in an Eclipse plug-in

The SWT JAR files contain OSGi metadata and therefore can also be used for Eclipse plug-in development. To use SWT in your Eclipse plug-in, add a dependency on org.eclipse.swt in the manifest file.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Swt
Bundle-SymbolicName: com.vogella.swt
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: VOGELLA
Automatic-Module-Name: com.vogella.swt
Bundle-RequiredExecutionEnvironment: JavaSE-21
Require-Bundle: org.eclipse.swt,
 org.eclipse.jface

In the above example, adding org.eclipse.jface would also make SWT available, as JFace re-exports SWT.

2. Exercise: Use the SWT library in a Java project

Create a new Java project named com.example.swt.widgets. Create a new lib folder in your project.

Download the SWT library from the Eclipse download page. Navigate to the download page of the latest stable Eclipse release.

Eclipse Download Page - Latest Release

Scroll down to the SWT binaries and download the correct version for your Java and OS version.

SWT Binaries

Copy the swt.jar library and the src.zip file to the lib folder in your project.

Add the library to the classpath of the project. Attach the src.zip source zip file to the library. Use the Open Type dialog to open the 'Shell' class. If everything has been done correctly, you will see the source code of the 'Shell' class.

3. Exercise: Use the SWT library in a Maven project

This exercise shows how to use the SWT library in a Maven project.

Create the following pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vogella</groupId>
    <artifactId>swt.standardalone</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>swt.standardalone</name>
    <properties>
        <osgi.platform>gtk.linux.x86_64</osgi.platform>
        <maven.compiler.release>21</maven.compiler.release>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.platform</groupId>
            <artifactId>org.eclipse.swt</artifactId>
            <version>3.129.0</version>
        </dependency>
    </dependencies>
</project>

Create the src/main/java/com/vogella folder.

Copy the code snippet from https://github.com/eclipse-platform/eclipse.platform.swt/blob/master/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet1.java into your src/main/java/com/vogella folder. Run this snippet using the Run as menu.

Run the following command to create the JAR file.

$ mvn clean verify -Dosgi.platform=gtk.linux.x86_64

Replace the osgi.platform value with the one that matches your operating system.

To run the JAR file, use the following command.

mvn exec:java -Dexec.mainClass="com.vogella.Snippet1" -Dosgi.platform=gtk.linux.x86_64

4. SWT Widgets

4.1. Available widgets in the SWT library

SWT widgets are located in the packages org.eclipse.swt.widgets and org.eclipse.swt.custom. Widgets extend either the Widget or the Control class. Several of these widgets are depicted in the following screenshot of the SWT widget homepage.

Overview of the SWT widgets

The Composite class is a container for other widgets.

The Group class is another container that is able to contain other widgets. It additionally draws a border around itself and allows you to set a header for the grouped widgets.

4.2. Constructing and configuring widgets

SWT widgets, except for the Shell object, are always constructed with a parent widget that contains them.

The second parameter of the widget constructor contains the style bits. Depending on the provided style bits, the widget adjusts its look and feel as well as its behavior. Each widget documents the supported style bits in its Javadoc.

The possible style bits are predefined in the SWT class. If no special style is required, you can pass SWT.NONE.

For example, the following code snippet creates a push button or a checkbox, depending on the passed style flags.

Button b1 = new Button(shell, SWT.PUSH);

Button b2 = new Button(shell, SWT.CHECK);

After construction, the widget offers methods to configure its behavior.

Button b1 = new Button(parent, SWT.PUSH);
b1.setText("Press me");
b1.addSelectionListener(SelectionListener.widgetSelectedAdapter(e-> System.out.println("Pressed")));

JFace offers a builder API for multiple SWT widgets that simplifies the creation of widgets. The above example can be rewritten as follows:

WidgetFactory.button(SWT.PUSH).text("Press me").onSelect(e-> System.out.println("Pressed")).create(parent);

Or in case you use a static import for WidgetFactory.

import static org.eclipse.jface.widgets.WidgetFactory.button;
// more code
button(SWT.PUSH).text("Press me").onSelect(e-> System.out.println("Pressed")).create(parent);

4.3. Custom widgets and native widgets

SWT provides custom-drawn widgets in org.eclipse.swt.custom package for cases in which the native widgets are not sufficient for the needs of SWT. For example, the CCombo class allows you to set the height of the widget, which the Combo class does not support. Custom-drawn widgets usually start with the additional prefix C to indicate that they are custom widgets, e.g., CCombo.

Another example is StyledText, a class that provides advanced features for displaying text, e.g., drawing a background.

Widgets in org.eclipse.swt.widgets are implemented with platform-specific code. On the other hand, widgets from the package org.eclipse.swt.custom are implemented in pure Java. Custom widgets are not supposed to use the internal classes of SWT as these classes may be different on the various platforms. Every custom widget should extend the Composite or Canvas class. API compliance is guaranteed only for these base classes.

If the new custom widget is supposed to contain other widgets, it should extend Composite. Otherwise, it should extend the Canvas class.

4.4. Memory management

SWT widgets retain a reference to the native widget. Such references are not automatically released by the system.

When a container, such as a Shell, is disposed of, it automatically releases all its children.

For certain widgets, you must explicitly call their dispose() method when they are no longer needed. These are the following widgets:

  • Cursor

  • Display

  • Font

  • GC

  • Image

  • Printer

  • Region

JFace provides a way to dispose of such objects based on another widget, via the LocalResourceManager class.

4.5. Event Listener

You can register listeners for specific events on SWT controls. For example, a ModifyListener to listen to changes in a Text widget or a SelectionListener for selection (click) events on a Button widget. The pure SWT implementation uses add followed by the type of event. For example:

Button button =  new Button(shell, SWT.PUSH);
button.setText("Press me");

//register listener for the selection event
button.addSelectionListener(new SelectionAdapter() {
    @Override
    public void widgetSelected(SelectionEvent e) {
        System.out.println("Called!");
    }
});

FocusListener is another example for such a listener interface.

The Listener interfaces contain several methods, and therefore, Eclipse provides empty default implementations for these interfaces. This allows you to implement only the methods you are interested in. These implementations follow the naming convention:

Name*Listener  Name*Adapter

For example, the SelectionListener interface has an abstract class, SelectionAdapter, that provides default implementations of its methods.

The JFace builder API simplifies event registration by providing methods that accept a lambda for certain events.

import static org.eclipse.jface.widgets.WidgetFactory.button;
// more code
button(SWT.PUSH).text("Press me").onSelect(e-> System.out.println("Pressed")).create(parent);

If you want to add a listener to the whole application, you can use the Display class. For example, to add a global mouse listener use Display.addFilter(SWT.MouseMove, listener). If you add filters to the Display you may interfere with existing listeners. Ensure that you test your code accordingly.

4.6. Colors in SWT

Colors can be defined in SWT or system colors can be reused.

Device device = Display.getCurrent ();
Color red = new Color (device, 255, 0, 0);

// Using system colors

Display display = Display.getCurrent();
Color blue = display.getSystemColor(SWT.COLOR_BLUE);
Color listBackground = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);

If you create colors, you do NOT need to call dispose() since the Eclipse 2020-06 release.

5. Optional exercise: Use SWT in a standalone Java application

In this exercise, you create a plug-in that allows you to create small standalone Java applications using SWT. This can be useful, for example, for testing SWT widgets.

5.1. Create new plug-in and add dependencies

Create a new plug-in project called com.example.swt.widgets via File  New  Other…​  Plug-in Development  New Plug-in Project.

Enter the data in the wizard similar to the screenshot below. Make sure you deselect the following options:

  • Select No for Would you like to create a rich client application?

  • Uncheck This plug-in will make contributions to the UI

  • Uncheck Generate an activator, a Java class that controls the plug-in’s lifecycle

New Plug-in Project Wizard Page 1
New Plug-in Project Wizard Page 2

Press the Finish button on the second page of the wizard.

Open the MANIFEST.MF file in the META-INF folder and select the Dependencies tab.

Press the Add…​ button in the Required Plug-ins part and enter org.eclipse.swt as a dependency.

Adding the dependency to SWT in the Plug-in project

5.2. Create a standalone SWT application

Create the following class for a simple SWT application.

package com.example.swt.widgets;

import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class FirstSWTApplication {

    public static void main(String[] args) {
        Display display = new Display();

        Shell shell = new Shell(display);

        // the layout manager handle the layout
        // of the widgets in the container
        shell.setLayout(new FillLayout());

        //TODO add some widgets to the Shell
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }
}

To start your application, right-click on your Java class, and select Run-As  Java Application. You start your application and it shows you an empty window.

Change the TODO in the code to the following.

package com.example.swt.widgets;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class FirstSWTApplication {

    public static void main(String[] args) {
        Display display = new Display();

        Shell shell = new Shell(display);

        // the layout manager handle the layout
        // of the widgets in the container
        shell.setLayout(new FillLayout());


        Label label = new Label(shell, SWT.BORDER);
        label.setText("This is a label:");
        label.setToolTipText("This is the tooltip of this label");

        Text text = new Text(shell, SWT.NONE);
        text.setText("This is the text in the text widget");
        text.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
        text.setForeground(display.getSystemColor(SWT.COLOR_WHITE));

        // set widgets size to their preferred size
        text.pack();
        label.pack();


        (1)
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }
}
1 This is where the TODO comment was

Make sure you use org.eclipse.swt and not java.awt when adding the missing imports.

If you now start the application you will get a Shell with two Widgets included.

First running SWT application

5.3. Add an SWT Button

Add a Button widget to your application and assign a SelectionListener to it. If the button is pressed, write "Called!" to the console.

Button button =  new Button(shell, SWT.PUSH);
button.setText("Press me");

//register listener for the selection event
button.addSelectionListener(new SelectionAdapter() {
    @Override
    public void widgetSelected(SelectionEvent e) {
        System.out.println("Called!");
    }
});

6. Positioning widgets

6.1. Manually placing widgets on a Composite

Controls must be placed inside their container. You can manually define their position and size using the setBounds method. This method allows you to specify the starting position, width, and height. The coordinates start at the top-left corner of the containing Composite.

SWT widget positioning
package com.vogella.swt.widgets.layout;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class SWTLayoutPositionTracker {

    static String newLine = System.getProperty("line.separator");
    private static Label positionLabel;
    private static Shell shell;
    public static void main(String[] args) {
        Display display = new Display();
        shell = new Shell(display);

        positionLabel = new Label(shell, SWT.BORDER);
        
        int x= 60;
        int y=20;
        int width =400;
        int height=200;
    
        positionLabel.setBounds(x, y, width, height);
        int toolbarSize = 30;

        shell.setBounds(200, 400, width+2*x , height + 2*y +toolbarSize);
        shell.open();
        
        
        
        shell.addMouseMoveListener(e -> showSize(e));
        positionLabel.addMouseMoveListener(e -> showSize(e));
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
    
    public static void showSize(MouseEvent e) {
        int x = e.x;
        int y = e.y;
        String s = "Bounds for Label: " + positionLabel.getBounds() + newLine;
        s+= "Bounds for Shell: " + shell.getBounds()  + newLine;
        s+= "Mouse pointer: " + x + " " + y;
        positionLabel.setText(s);
        
    }
}

setBounds defines both the position and size. You can also use setLocation and setSize to define the position and size separately.

6.2. The role of a layout manager

A layout manager is responsible for arranging the widgets within a container, such as a Composite. SWT offers several standard layout managers. The following table provides an overview of them.

Table 1. Layout Manager
Layout Manager Description

AbsoluteLayout

Allows you to specify the exact position, width, and height of components. As user interfaces may be used on screens with different sizes, this layout manager should generally be avoided.

FillLayout

Arranges equal-sized widgets in a single row or column.

RowLayout

Arranges the widgets in rows or columns and allows you to control the layout with options such as wrap, spacing, and fill.

GridLayout

Arranges widgets in a grid.

BorderLayout

Allows to arrange the widgets in different regions, SWT.TOP, SWT.CENTER, SWT.LEFT, SWT.RIGHT, SWT.BOTTOM

FormLayout

Arranges the widgets with the help of the associated attachments.

StackLayout

This layout stacks all the controls on top of another and resizes all controls to have the same size and location. The control specified in topControl is visible and all other controls are not visible.

If you assign a layout manager to a control, you no longer need to call pack. You can call the pack() method if a control has no layout. You typically call pack() on a container to make it resize to fit its contents, regardless of whether layout managers are used.

6.3. Layout Data

Each SWT widget can have a layout specific settings class assigned to it, e.g., GridData for a GridLayout. This allows the developer to control the arrangement of the widgets within the layout.

In the following example, you specify that a widget should span two columns in a GridLayout.

button = new Button(parent, SWT.PUSH);
GridData gridData = new GridData();
gridData.horizontalSpan = 2;
button.setLayoutData(gridData);
The used layout data must match the layout manager, otherwise an exception is thrown at runtime.

The layout will be automatically calculated when the container is displayed. You can tell a Composite to recalculate its layout with the composite.requestLayout() method.

Layout data objects should not be reused as the layout manager expects that every user interface element has a unique layout data object.

6.4. FillLayout

FillLayout divides the available space provided by the container equally to all widgets. It can arrange the widgets either horizontally (SWT.HORIZONTAL) or vertically (SWT.VERTICAL). It also allows you to set the space between the widgets (attribute spacing) and the margins of the widgets to the container via the marginWidth and marginHeight attributes.

6.5. RowLayout

RowLayout orders UI components in a row (SWT.HORIZONTAL) or in a column (SWT.VERTICAL). RowLayout supports wrapping of widgets (property wrap) by default. Via the pack property, you can define if widgets have their preferred size (default) or if they grab the available space. It is also possible to set margins at the top, bottom, left, and right. If you set justify, the widgets will be spread throughout the available space.

Each element can specify its height and width using a RowData element.

6.6. GridLayout

GridLayout allows you to arrange the user interface components in a Grid with a certain number of columns. It is also possible to specify column and row spanning.

You can use new GridData() and assign properties to the new object. Alternatively, you can use one of its richer constructors to define certain attributes during construction. For example, via the following constructor:

new GridData(horizontalAlignment,
    verticalAlignment,
    grabExcessHorizontalSpace, 
    grabExcessVerticalSpace, 
    horizontalSpan,
    verticalSpan)

The most important attributes are defined in the following table.

Table 2. GridData
Parameter Description

horizontalAlignment

Defines how the control is positioned horizontally within a cell (one of: SWT.LEFT, SWT.CENTER, SWT.RIGHT, or SWT.FILL ).

verticalAlignment

Defines how the control is positioned vertically within a cell (one of: SWT.TOP, SWT.CENTER, SWT.END, SWT.BOTTOM (treated the same as SWT.END), or SWT.FILL ).

grabExcessHorizontalSpace

Defines whether the control is extended by the layout manager to take all the remaining horizontal space.

grabExcessVerticalSpace

Defines whether the control grabs any remaining vertical space.

horizontalSpan

Defines the number of column cells that the control takes.

verticalSpan

Defines the number of row cells that the control will take up.

heightHint

Defines the preferred height in pixels.

widthHint

Defines the preferred width in pixels.

If the widget has the grabExcessHorizontalSpace attribute set to true, it will grab available space in its container. SWT.FILL tells the widget to fill the available space. Therefore, grabExcessHorizontalSpace and SWT.FILL are often used together.

6.7. Using GridDataFactory

The GridDataFactory class can be used to create GridData objects. This class provides a convenient shorthand for creating and initializing these objects. The following listing demonstrates its usage and compares it with the direct usage of GridData.

// listBox is an SWT widget

// GridDataFactory version
GridDataFactory.fillDefaults().grab(true, true).hint(150, 150).applyTo(listBox);
 
// Equivalent SWT version
GridData listBoxData = new GridData(GridData.FILL_BOTH);
listBoxData.widthHint = 150;
listBoxData.heightHint = 150;
listBoxData.minimumWidth = 1;
listBoxData.minimumHeight = 1;
listBox.setLayoutData(listBoxData);

The Javadoc of this class contains several examples for it.

6.8. BorderLayout

BorderLayout allows you to place widgets in different regions via the BorderData#region.

  • SWT.TOP

  • SWT.CENTER

  • SWT.LEFT

  • SWT.RIGHT

  • SWT.BOTTOM

The top, left, right, and bottom widgets get their necessary space; the rest is available for the widgets placed in the center.

The usage is demonstrated here, in which a given Composite uses this layout.

      var layoutManager = new BorderLayout();
      parent.setLayout(layoutManager);
      // TOP
      var topLabel = new Label(parent, SWT.NONE);
      topLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
      topLabel.setLayoutData(new BorderData(SWT.TOP));


      // CENTER
      var centerLabel = new Label(parent, SWT.NONE);
      centerLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GREEN));
      centerLabel.setLayoutData(new BorderData(SWT.CENTER));

      // BOTTOM
      var bottomLabel = new Label(parent, SWT.NONE);
      bottomLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE));
      bottomLabel.setLayoutData(new BorderData(SWT.BOTTOM));


      // LEFT
      var leftLabel = new Label(parent, SWT.NONE);
      leftLabel.setText("LEFT");
      leftLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_YELLOW));
      leftLabel.setLayoutData(new BorderData(SWT.LEFT));


      // RIGHT we have two widgets
      var rightLabel1 = new Label(parent, SWT.NONE);
      rightLabel1.setText("RIGHT");
      rightLabel1.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_CYAN));
      rightLabel1.setLayoutData(new BorderData(SWT.RIGHT));


      var rightLabel2 = new Label(parent, SWT.NONE);

      rightLabel2.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
      rightLabel2.setLayoutData(new BorderData(SWT.RIGHT));

The result looks similar to the following screenshot.

borderlayout

6.9. FormLayout

FormLayout works by creating FormAttachments for each side of the widget, and storing them in the layout data. The specific side of the widget is attached either to a position in the parent Composite or to another widget within the layout. This allows you to control on a detailed level the placement of individual widgets within the layout.

6.10. Adding and removing children from a Composite

You can add children at runtime to a Composite. By default, they are placed after the existing controls, but you can reposition them via the moveAbove and moveBelow method calls.

To remove a child from a layout, call its dispose method. To update the parent composite after you removed or added children, call its requestLayout method.

The following is an example of how to dynamically create new rows in an existing layout and how to remove these rows.

package com.vogella.swt.widgets.layout;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;

public class SWTDynamicLayoutChanges {

    static int number = 0;
    private static List<Color> colors;
    private static int colorIndex;

    public static void main(String[] args) {
        
        Display display = new Display();
        Shell shell = new Shell(display);
        colorIndex = 0;
        colors = new ArrayList<>();
        colors.add(Display.getDefault().getSystemColor(SWT.COLOR_RED));
        colors.add(Display.getDefault().getSystemColor(SWT.COLOR_GREEN));
        colors.add(Display.getDefault().getSystemColor(SWT.COLOR_YELLOW));
        colors.add(Display.getDefault().getSystemColor(SWT.COLOR_CYAN));
        colors.add(new Color (Display.getDefault(), 122, 122, 122));
        colors.add(new Color (Display.getDefault(), 255, 51, 227));
        colors.add(new Color (Display.getDefault(), 27, 82, 255));
        colors.add(new Color (Display.getDefault(), 240, 201, 27));
        colors.add(new Color (Display.getDefault(), 188, 188, 188));
        colors.add(Display.getDefault().getSystemColor(SWT.COLOR_DARK_MAGENTA));
        

        GridLayout gridLayout = new GridLayout(1, false);
        gridLayout.marginWidth = 0;
        gridLayout.marginHeight = 0;
        gridLayout.verticalSpacing = 0;
        gridLayout.horizontalSpacing = 0;
        shell.setLayout(gridLayout);
        
        Composite top = new Composite(shell, SWT.NONE);
        GridData d1 = new GridData(SWT.FILL, SWT.FILL, true, true);
        top.setLayoutData(d1);
        top.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GREEN));
        
        createLayer(shell);
        createLayer(shell);
        createLayer(shell);
        
        shell.setBounds(100, 100, 800, 600);
        shell.open();       
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
    
    private static Composite createLayer(Composite parent) {
        
        Composite layer = new Composite(parent, SWT.NONE);
        layer.setLayout(new FillLayout());
        for (int i = 0; i < 10; i++) {
            Label label = new Label(layer, SWT.NONE);
            label.setText("I go \u26F7");
            label.addMouseListener(new MouseAdapter() {
                
                @Override
                public void mouseDown(MouseEvent e) {
                    Shell shell =Display.getDefault().getActiveShell();
                    MessageBox dialog =
                            new MessageBox(shell, SWT.ICON_QUESTION | SWT.OK| SWT.CANCEL);
                    dialog.setText("My info");
                    dialog.setMessage("Do you want to do this?");
                    dialog.open();

                }
                
            });
        }
        Button removeButton = new Button(layer, SWT.PUSH);
        removeButton.setText("Remove");
        removeButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                layer.dispose();
                parent.requestLayout();
            }
        });
        
        Button addButton = new Button(layer, SWT.PUSH);
        addButton.setText("Add");
        addButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Composite composite = createLayer(parent);
                composite.moveAbove(addButton.getParent());
                parent.requestLayout();
                
            }
        });

        
        GridData d2 = new GridData(SWT.FILL, SWT.TOP, true, false);
        layer.setLayoutData(d2);
        if (colorIndex > colors.size()-1 ) {
            colorIndex = 0;
        }
        layer.setBackground(colors.get(colorIndex++));
        return layer;
    }
}

6.11. Triggering a re-layout of a Composite

As of Eclipse 4.7 you should use the requestLayout() method call on the Composite class, as this triggers an asynchronous layout call.

The Composite widget also defines the layout() method which triggers a synchronous layout. The layout() method will recursively call layout() on child composites as well. Prefer using requestLayout() on the individual composites if necessary, as this is faster. The layout() method also accepts child widgets and flags.

Table 3. Layout flags
Flag Description

SWT.ALL

Flag forces all descendants to be marked for layout. As far as I know, there is no good reason to ever use this flag. If it is actually doing something, it could be replaced by a series of calls to requestLayout.

SWT.CHANGED

The flag causes subsequent calls to Layout.layout(…​) to receive true for the second argument, which forces the layout to recursively flush all caches. Avoid doing this, as this is performance intensive. If something has changed, the layout should be notified via Layout.flushCache(control), which is automatically done when you invoke requestLayout. This is either a brute-force workaround for a stale layout bug or was just unnecessary. The usage of SWT.CHANGED should not be necessary in client code if the rest of the layout is correctly defined.

6.12. Example: Using GridLayout manager

The following example demonstrates the usage of the GridLayout class in the com.example.swt.widgets project.

package com.example.swt.widgets.layouts;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;

public class GridLayoutSWT {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);

        // create a new GridLayout with two columns
        // of different size
        GridLayout layout = new GridLayout(2, false);

        // set the layout to the shell
        shell.setLayout(layout);
        
        // create a label and a button
        Label label = new Label(shell, SWT.NONE);
        label.setText("A label");
        Button button = new Button(shell, SWT.PUSH);
        button.setText("Press Me");

        // create a new label that will span two columns
        label = new Label(shell, SWT.BORDER);
        label.setText("This is a label");
        // create new layout data
        GridData data = new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1);
        label.setLayoutData(data);

        // create a new label which is used as a separator
        label = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
        
        // create new layout data
        data = new GridData(SWT.FILL, SWT.TOP, true, false);
        data.horizontalSpan = 2;
        label.setLayoutData(data);

        // creates a push button
        Button b = new Button(shell, SWT.PUSH);
        b.setText("New Button");

        data = new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1);
        b.setLayoutData(data);
        
         // create a spinner with min value 0 and max value 1000
        Spinner spinner = new Spinner(shell, SWT.READ_ONLY);
        spinner.setMinimum(0);
        spinner.setMaximum(1000);
        spinner.setSelection(500);
        spinner.setIncrement(1);
        spinner.setPageIncrement(100);
        GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        gridData.widthHint = SWT.DEFAULT;
        gridData.heightHint = SWT.DEFAULT;
        gridData.horizontalSpan = 2;
        spinner.setLayoutData(gridData);

        Composite composite = new Composite(shell, SWT.BORDER);
        gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        gridData.horizontalSpan = 2;
        composite.setLayoutData(gridData);
        composite.setLayout(new GridLayout(1, false));

        Text txtTest = new Text(composite, SWT.NONE);
        txtTest.setText("Testing");
        gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        txtTest.setLayoutData(gridData);

        Text txtMoreTests = new Text(composite, SWT.NONE);
        txtMoreTests.setText("Another test");
        
        Group group = new Group(shell, SWT.NONE);
        group.setText("This is my group");
        gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        gridData.horizontalSpan = 2;
        group.setLayoutData(gridData);
        group.setLayout(new RowLayout(SWT.VERTICAL));
        Text txtAnotherTest = new Text(group, SWT.NONE);
        txtAnotherTest.setText("Another test");

        // Children of this widget should get a fixed size
        Composite fixedElements = new Composite(shell, SWT.BORDER);
        gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        gridData.horizontalSpan = 2;
        fixedElements.setLayoutData(gridData);
        fixedElements.setLayout(new GridLayout(2, false));
        Label label2 = new Label(fixedElements, SWT.BORDER);
        GridData layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false);
        layoutData.widthHint=200;
        label2.setLayoutData(layoutData);
        label2.setText("Fixed");
        Label label3 = new Label(fixedElements, SWT.BORDER);
        GridData layoutData2 = new GridData(SWT.BEGINNING, SWT.CENTER, false, false);
        layoutData2.widthHint=20;
        label3.setLayoutData(layoutData2);
        label3.setText("Small but still fixed");
        
        
        
        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }

}

Start your application. The expected output is shown in the screenshot below.

gridswtlayout

Resize the window and observe how the arrangement of the widgets changes.

6.13. Example: Using GridLayout to assign a fixed ratio to its children

The following example shows how the first child of the grid layout receives 25% of the available space, while the other receives 75%. Since GridLayout only supports fixed sizes, you must register a resize listener on its container.

package com.example.swt.widgets.layouts;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class GridLayoutWithFixedColumnDistribution {
    public static void main(String[] args)
    {
        Display display = Display.getDefault();
        Shell shell = new Shell(display);
        shell.setLayout(new GridLayout(2, false));

        Composite left = new Composite(shell, SWT.BORDER);
        Composite right = new Composite(shell, SWT.BORDER);

        GridData leftData = new GridData(SWT.FILL, SWT.FILL, true, true);
        GridData rightData = new GridData(SWT.FILL, SWT.FILL, true, true);

        left.setLayoutData(leftData);
        right.setLayoutData(rightData);

        shell.addListener(SWT.Resize, arg0 -> {
            Point size = shell.getSize();

            leftData.widthHint = (int) (size.x * 0.75);
            rightData.widthHint = size.x - leftData.widthHint;

            System.out.println(leftData.widthHint + " + " + rightData.widthHint + " = " + size.x);
        });

        shell.open();
        shell.requestLayout();

        while (!shell.isDisposed())
        {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
}

7. Other SWT examples

The following code snippets provide examples of how to use SWT. You are not expected to read through all of them; they are provided as reference in case you need a code example while coding.

7.1. Tab order of elements

The tab order is the order in which elements are selected when switching between them with the Tab key. You can specify the tab order of controls via the setTabList() method of a Composite. For this, you provide an array of the controls, where the order of the controls in the array specifies the tab order.

package com.example.swt.widgets


import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class TabExample {
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Shell shell = new Shell(display);
        shell.setLayout(new RowLayout());
        Button b1 = new Button(shell, SWT.PUSH);
        b1.setText("Button1");
        Button b2 = new Button(shell, SWT.PUSH);
        b2.setText("Button2");
        Button b3 = new Button(shell, SWT.PUSH);
        b3.setText("Button3");

        Control[] controls = new Control[] { b2, b1, b3 };
        shell.setTabList(controls);
        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }
}
Defining a tab order for your controls is important to increase accessibility and to allow advanced users quick navigation.

7.2. DateTime widget

The following code demonstrates how to use the DateTime widget.

package de.vogella.swt.widgets;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class DateTimeExample {

    public static void main(String[] args) {

        // setup the SWT window
        Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new RowLayout());

        // initialize a parent composite with a grid layout manager
        Composite parent = new Composite(shell, SWT.NONE);
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 1;
        parent.setLayout(gridLayout);
        DateTime calendar = new DateTime(parent, SWT.CALENDAR);
        DateTime date = new DateTime(parent, SWT.DATE);
        DateTime time = new DateTime(parent, SWT.TIME);
        // Date Selection as a drop-down
        DateTime dateD = new DateTime(parent, SWT.DATE | SWT.DROP_DOWN);

        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        // tear down the SWT window
        display.dispose();
    }
}
swtdatetime10

7.3. Image

Images can be displayed using labels. The following class demonstrates this using some system images.

package de.vogella.swt.widgets;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class Photo {

    public static void main(String[] args) {

        // setup the SWT window
        Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new RowLayout());
        shell.setText("Photo Application");

        // initialize a parent composite with a grid layout manager
        // with 5x columns
        Composite parent = new Composite(shell, SWT.NONE);
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 5;
        parent.setLayout(gridLayout);

        // Get the Display default icons
        List<Image> imageList = new ArrayList<Image>();

        imageList.add(Display.getDefault().getSystemImage(SWT.ICON_WARNING));
        imageList.add(Display.getDefault().getSystemImage(SWT.ICON_WORKING));
        imageList.add(Display.getDefault().getSystemImage(SWT.ICON_QUESTION));
        imageList.add(Display.getDefault().getSystemImage(SWT.ICON_INFORMATION));
        imageList.add(Display.getDefault().getSystemImage(SWT.ICON_ERROR));

        for (Image image : imageList) {
            Label label = new Label(parent, SWT.NONE);
            label.setImage(image);
        }
        // show the SWT window

        shell.pack();
        shell.open();

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        // tear down the SWT window
        display.dispose();
        // if you do not use system images you would have to release them
        // not necessary in this example
        // for (Image image : imageList) {
        //    if (image != null) {
        //     image.dispose();
        //    }
        //    }
    }
}

The expected output is shown in the screenshot below.

swtimages10

You can also load your own images from disk; just remember to dispose of them later. The code assumes that you have a file named my_image.png in a subfolder of your current package called images.

new Image(getDisplay(), getClass().getResourceAsStream("images/my_image.png"));

7.4. Table

Create the following class.

package de.vogella.swt.table;

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.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

public class SWTTable {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        
        shell.setLayout(new GridLayout());


        Table table = new Table(shell, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
        table.setLinesVisible(true);
        table.setHeaderVisible(true);
        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        data.heightHint = 200;
        table.setLayoutData(data);

        String[] titles = { "First Name", "Last Name", "Age" };
        for (int i = 0; i < titles.length; i++) {
            TableColumn column = new TableColumn(table, SWT.NONE);
            column.setText(titles[i]);
            table.getColumn(i).pack();
        }
        
        for (int i = 0 ; i<= 50 ; i++){
            TableItem item = new TableItem(table, SWT.NONE);
            item.setText (0, "Person " +i );
            item.setText (1, "LastName " +i );
            item.setText (2, String.valueOf(i));
        }
        
        for (int i=0; i<titles.length; i++) {
            table.getColumn (i).pack ();
        }    
        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }
}

If you run this application, it displays a table.

7.5. Tree and Menu

Create the following class.

package de.vogella.swt.widgets;

import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

public class TreeMenuTest {
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        final Tree tree = new Tree(shell, SWT.V_SCROLL);
        for (int i = 0; i < 5; i++) {
            TreeItem item = new TreeItem(tree, SWT.NONE);
            item.setText(String.valueOf(i));
            for (int j = 0; j < 3; j++) {
                TreeItem subItem = new TreeItem(item, SWT.NONE);
                subItem.setText(String.valueOf(i) + " " + String.valueOf(j));
            }
        }
        tree.pack();
        Menu menu = new Menu(tree);
        MenuItem menuItem = new MenuItem(menu, SWT.NONE);
        menuItem.setText("Print Element");
        
        menuItem.addSelectionListener(widgetSelectedAdapter( e->  System.out.println(tree.getSelection()[0].getText())));
                
        tree.setMenu(menu);
        shell.setSize(400, 200);
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }
}

If you run this application, it displays a tree. Right-click any item to display the context menu.

swt tree menu

If you select the menu, the text of the selected item will be printed to the console.

7.6. CTabFolder

CTabFolder and CTabItem let you create a tabbed container where each page is accessible through a tab. This widget supports background colors, which the TabFolder and TabItem widget do not support.

package com.vogella.swt.widgets.ctabfolder;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class CTabFolderExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);

        shell.setLayout(new GridLayout());
        // SWT.BOTTOM to show at the bottom
        CTabFolder folder = new CTabFolder(shell, SWT.BOTTOM);
        GridData data = new GridData(SWT.FILL, 
                SWT.FILL, true, true,
                2, 1);
        folder.setLayoutData(data);
        folder.setSelectionForeground(display.getSystemColor(SWT.COLOR_RED));
        CTabItem cTabItem1 = new CTabItem(folder, SWT.NONE);
        cTabItem1.setText("Tab1");
        CTabItem cTabItem2 = new CTabItem(folder, SWT.NONE);
        cTabItem2.setText("Tab2");
        CTabItem cTabItem3 = new CTabItem(folder, SWT.NONE);
        cTabItem3.setText("Tab3");

        Text text = new Text(folder, SWT.BORDER);
        text.setText("Hello");
        cTabItem1.setControl(text);

        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }
}

If you run this application, you will see several tabbed cards with tabs on them. The SWT.BOTTOM style bit on the folder widget, makes the tab appear at the bottom.

ctabfolder10

7.7. Key bindings for SWT widgets

You can add KeyListener to an SWT widget via the addKeyListener method. This method receives a KeyEvent object. The e object provides for example:

  • e.character: which char was pressed

  • e.stateMask: which modifier keys were pressed (CTRL, ALT, SHIFT, COMMAND, ALT_GR)

  • keyCode: integer representation of the key based on constants defined in the SWT class.

The following source code demonstrates how to register a KeyListener with an SWT widget and how to evaluate the event.

package com.vogella.swt.widgets;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class SWTKeyEvent {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("KeyListener Example");

        shell.setLayout(new GridLayout());

        Button button = new Button(shell, SWT.CENTER);

        button.setText("Type here and use optionally meta keys");

        button.addKeyListener(KeyListener.keyPressedAdapter(e-> handleKeyEvent(e)));

        shell.pack();
        shell.open();

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }

    private static void handleKeyEvent(KeyEvent e) {
        String string = "";

        // check click together?
        if ((e.stateMask & SWT.ALT) != 0)
            string += "ALT ";
        if ((e.stateMask & SWT.CTRL) != 0)
            string += "CTRL ";
        if ((e.stateMask & SWT.SHIFT) != 0)
            string += "SHIFT ";

        if (e.keyCode == SWT.BS) {
            string += "BACKSPACE ";
        }

        if (e.keyCode == SWT.ESC) {
            string += "ESCAPE ";
        }

        // check characters (digits are from 48 to 57)
        if ((e.keyCode >= 97 && e.keyCode <= 122) || (e.keyCode >= 48 && e.keyCode <= 57)) {
            string += " " + e.character + " - keyCode = " + e.keyCode;
        }

        if (!string.equals("")) {
            System.out.println(string);
        }
    }

}

If you run this application, move the cursor over the button widget and type, you should see the output in the Console view.

swt keylistener

7.8. Global filtering of user interface events

You can use the addFilter method from the Display class to filter globally for events as long as your application has focus. The following code demonstrates this.

package de.vogella.swt.listener;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

public class GlobalListener {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.open();
        display.addFilter(SWT.KeyDown, new Listener() {
            @Override
            public void handleEvent(Event event) {
                char c = event.character;
                System.out.println(c);
            }
        });

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
    }
}

7.9. Fonts in SWT

You can change the font of text in SWT. You do this by creating a Font and then applying it to the desired control.

Label label = new Label(parent, SWT.NONE);
Font font = new Font(label.getDisplay(), new FontData("Mono", 10, SWT.ITALIC));
label.setFont(font);
label.setText("Some text");

To modify the current font you can retrieve the FontData, change it and create a new Font from it.

Label label = new Label(parent, SWT.NONE);
FontData fontData = label.getFont().getFontData()[0];
// we can change this since getFontData() creates a new FontData instance
fontData.setStyle(SWT.ITALIC);
label.setFont(new Font(label.getDisplay(), fontData));

You can roll out and use custom fonts for your application. To use a custom font you have to load it with the Display.

boolean fontLoaded = Display.getDefault().loadFont("fonts/CustomFont.ttf");
if (fontLoaded) {
    Font font = new Font(Display.getDefault(), "Custom Font", 12, SWT.NORMAL);
    label.setFont(font);
}
Please remember that fonts do not get automatically disposed with the widget that uses them.

7.10. Unicode in SWT

SWT supports the display of Unicode characters. Depending on your OS and default font you might have to change the font of your control to a font that supports Unicode characters.

Label label = new Label(parent, SWT.NONE);
label.setFont(new Font(Display.getCurrent(), "Arial Unicode MS", 12, SWT.NORMAL));
label.setText("Follow your \u2764!");

8. SWT builder API via JFace

The JFace library adds a builder API to SWT widgets, providing a concise and modern way to build SWT-based user interfaces.

The following example shows how to use the ButtonFactory to create a new button.

import static org.eclipse.jface.widgets.ButtonFactory.newButton;
....

newButton(SWT.PUSH).text("Press me").onSelect(e-> System.out.print("Testing")).create(shell);

9. SWT snippets and examples

The SWT Snippets are examples of stand-alone SWT applications using various SWT widgets.

You can copy these snippets and paste them directly into a project with an SWT dependency inside the Eclipse IDE. Each snippet contains a main method, allowing it to be started directly.

You can paste classes from the clipboard onto a project or package. Eclipse automatically creates the Java class based on the content of the clipboard for you.

The SWT Examples page provides test programs for widgets and custom-drawn SWT widgets.

10. The Nebula widgets

The Eclipse Nebula project provides additional widgets for SWT. For example, it offers several visualization widgets, as shown in the following screenshot.

Nebula visualization widgets

See https://github.com/EclipseNebula/nebula/blob/master/docs/Widgets.md for an overview of the available widgets.

To use these widgets in your application, add their update site to your target platform.

11. Learn more and get support

This tutorial continues on Eclipse RCP online training or Eclipse IDE extensions with lots of video material, additional exercises and much more content.

12. SWT resources

SWT Widgets - Webpage showing all SWT widgets with links to examples and Javadoc

SWT Snippets - Short examples demonstrating the usage of the SWT API

SWT Development Tools - Tools include Sleak (analyze memory leaks in SWT graphics resources) and the SWT Spy plug-in, which prints out information about the SWT widget under the cursor.