Painting in Java SWT

In this part of the Java SWT tutorial, we do some painting.

Painting is performed on objects that implement the Drawable interface. This includes a Control, an Image, a Display device, or a Printer device.

The org.eclipse.swt.graphics.GC is a graphics context that encapsulates the drawing operations that can be performed. There are two common ways to use a GC; either by creating one using the Drawable instance as a constructor argument, or else using a GC that is provided as part of a paintEvent callback.

Colours

In the first example, we work with colours. A colour is an object representing a combination of Red, Green, and Blue (RGB) intensity values. In Java SWT, valid RGB values are in the range from 0 to 255.

ColoursEx.java
package com.zetcode;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;

/**
 * ZetCode Java SWT tutorial
 *
 * This program draws three rectangles.
 * The interiors are filled with
 * different colors.
 * 
 * Author: Jan Bodnar
 * Website: zetcode.com
 * Last modified: June 2015
 */

public class ColoursEx {

    private Shell shell;

    public ColoursEx(Display display) {

        initUI(display);
    }
    
    private void initUI(Display display) {

        shell = new Shell(display, SWT.SHELL_TRIM | SWT.CENTER);

        shell.addListener(SWT.Paint, event -> drawRectangles(event));
        
        shell.setText("Colours");
        shell.setSize(360, 120);
        shell.open();

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

    private void drawRectangles(Event e) {

        GC gc = e.gc;

        Color c1 = new Color(e.display, 50, 50, 200);
        gc.setBackground(c1);
        gc.fillRectangle(10, 15, 90, 60);

        Color c2 = new Color(e.display, 105, 90, 60);
        gc.setBackground(c2);
        gc.fillRectangle(130, 15, 90, 60);

        Color c3 = new Color(e.display, 33, 200, 100);
        gc.setBackground(c3);
        gc.fillRectangle(250, 15, 90, 60);

        c1.dispose();
        c2.dispose();
        c3.dispose();
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {

        Display display = new Display();
        ColoursEx ex = new ColoursEx(display);
        display.dispose();
    }
}

In our example, we draw three rectangles and fill them with three different colours.

shell.addListener(SWT.Paint, event -> drawRectangles(event));

We add a paint listener for paint events.

private void drawRectangles(Event e) {

    GC gc = e.gc;
...    
}        

The drawRectangles() method is invoked when a paint event is generated. We get a handle to the graphics context, which is an object on which we perform the painting operations.

Color c1 = new Color(e.display, 50, 50, 200);

We create a colour object.

gc.setBackground(c1);

The setBackground() method sets a colour for painting text and the interiors of shapes.

gc.fillRectangle(10, 15, 90, 60);

The fillRectangle() fills the specified rectangle with the background colour.

c1.dispose();
c2.dispose();
c3.dispose();

At the end of the painting, the colour resources are released.

Colours
Figure: Colours

Line styles

The drawLine() method draws a line on the drawable. The setLineStyle() method specifies the style of the line. The following are built-in SWT line styles:

It is also possible to create a custom line style with the SWT.LINE_CUSTOM option.

LineStylesEx.java
package com.zetcode;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;

/**
 * ZetCode Java SWT tutorial
 *
 * This program draws text on the window.
 *
 * Author: Jan Bodnar
 * Website: zetcode.com
 * Last modified: June 2015
 */

public class LineStylesEx {

    public LineStylesEx(Display display) {

        initUI(display);
    }
    
    private void initUI(Display display) {

        Shell shell = new Shell(display);

        shell.addListener(SWT.Paint, event -> drawLyrics(event));

        shell.setText("Line styles");
        shell.setSize(300, 330);
        shell.open();

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

    private void drawLyrics(Event e) {
        
        GC gc = e.gc;
        
        gc.setLineWidth(2);
        
        gc.setLineStyle(SWT.LINE_DASHDOT);
        gc.drawLine(20, 40, 250, 40);
        
        gc.setLineStyle(SWT.LINE_DASH);
        gc.drawLine(20, 80, 250, 80);

        gc.setLineStyle(SWT.LINE_DASHDOTDOT);
        gc.drawLine(20, 120, 250, 120);        
        
        gc.setLineStyle(SWT.LINE_SOLID);
        gc.drawLine(20, 160, 250, 160);
        
        gc.setLineStyle(SWT.LINE_DOT);
        gc.drawLine(20, 200, 250, 200);       
        
        gc.setLineStyle(SWT.LINE_CUSTOM);
        gc.setLineDash(new int[] {1, 4, 5, 4});
        gc.drawLine(20, 240, 250, 240);
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {

        Display display = new Display();
        LineStylesEx ex = new LineStylesEx(display);
        display.dispose();
    }
}

The example draws five standard style lines and one custom style.

gc.setLineWidth(2);

The setLineWidth() sets a width that is used when drawing lines.

gc.setLineStyle(SWT.LINE_DASHDOT);

The setLineStyle() sets the line style to SWT.LINE_DASHDOT. The line consists of a dash and dot pattern.

gc.drawLine(20, 40, 250, 40);

The drawLine() draws a line. The parameters are x and y coordinates of the beginning and ending points.

gc.setLineStyle(SWT.LINE_CUSTOM);
gc.setLineDash(new int[] {1, 4, 5, 4});
gc.drawLine(20, 240, 250, 240);

These lines create a custom line style pattern. The integer array specifies the widths of line spaces and dashes. In our case, the pattern is 1 px dash, 4 px space, 5 px dash, and 4 px space. This pattern is repeated for the whole line.

Line styles
Figure: Line styles

Basic shapes

The next example draws some basic shapes onto the window.

BasicShapesEx.java
package com.zetcode;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;

/**
 * ZetCode Java SWT tutorial
 *
 * In this program, we draw some
 * basic shapes.
 *
 * Author: Jan Bodnar
 * Website: zetcode.com
 * Last modified: June 2015
 */

public class BasicShapesEx {

    private Shell shell;

    public BasicShapesEx(Display display) {

        initUI(display);
    }
    
    private void initUI(Display display) {
        
        shell = new Shell(display, SWT.SHELL_TRIM | SWT.CENTER);

        shell.addListener(SWT.Paint, event -> drawShapes(event));

        shell.setText("Basic shapes");
        shell.setSize(430, 300);
        shell.open();

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

    private void drawShapes(Event e) {
        
        GC gc = e.gc;

        gc.setAntialias(SWT.ON);

        Color col = new Color(e.display, 150, 150, 150);
        gc.setBackground(col);

        gc.fillRectangle(20, 20, 120, 80);
        gc.fillRectangle(180, 20, 80, 80);
        gc.fillOval(290, 20, 120, 70);

        gc.fillOval(20, 150, 80, 80);
        gc.fillRoundRectangle(150, 150, 100, 80, 25, 25);
        gc.fillArc(280, 150, 100, 100, 0, 115);
        
        col.dispose();
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        
        Display display = new Display();
        BasicShapesEx ex = new BasicShapesEx(display);
        display.dispose();
    }
}

In this example, we will create a rectangle, a square, an ellipse, a circle, a rounded rectangle, and an arc.

gc.fillRectangle(20, 20, 120, 80);
gc.fillRectangle(180, 20, 80, 80);
gc.fillOval(290, 20, 120, 70);

These lines draw a rectangle, a square, and an ellipse.

gc.fillOval(20, 150, 80, 80);

Here the fillOval() method draws a circle.

gc.fillRoundRectangle(150, 150, 100, 80, 25, 25);
gc.fillArc(280, 150, 100, 100, 0, 115);

These two lines draw a rounded rectangle and an arc.

Basic shapes
Figure: Basic shapes

Polygon

Polygon is a two-dimensional plane shape with straight sides.

PolygonEx.java
package com.zetcode;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;

/**
 * ZetCode Java SWT tutorial
 *
 * This program draws a star.
 *
 * Author: Jan Bodnar
 * Website: zetcode.com
 * Last modified: June 2015
 */

public class PolygonEx {

    private final int points[] = { 0, 85, 75, 75, 100, 10, 
            125, 75, 200, 85, 150, 125, 160, 190, 100, 150, 
            40, 190, 50, 125, 0, 85 };

    public PolygonEx(Display display) {

        initUI(display);
    }

    private void initUI(Display display) {

        Shell shell = new Shell(display);

        shell.addListener(SWT.Paint, event -> drawPolygon(event));

        shell.setText("Polygon");
        shell.setSize(280, 280);
        shell.open();

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

    private void drawPolygon(Event e) {

        GC gc = e.gc;
        
        Color grayCol = new Color(e.display, 120, 120, 120);
        
        gc.setBackground(grayCol);
        gc.fillPolygon(points);

        grayCol.dispose();
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {

        Display display = new Display();
        PolygonEx ex = new PolygonEx(display);
        display.dispose();
    }
}

The example draws a start object.

private final int points[] = { 0, 85, 75, 75, 100, 10, 
        125, 75, 200, 85, 150, 125, 160, 190, 100, 150, 
        40, 190, 50, 125, 0, 85 };

These are the coordinates of the polygon. The array consists of pairs of x and y coordinates.

Color grayCol = new Color(e.display, 120, 120, 120);

The polygon is drawn in some gray colour.

gc.fillPolygon(points);

The fillPolygon() fills the interior of the closed polygon, which is defined by the specified array of integer coordinates.

Polygon
Figure: Polygon

Transparent rectangles

Transparency is the quality of being able to see through a material. The easiest way to understand transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the glass and this way we can see objects behind the glass.

In computer graphics, we can achieve transparency effects using alpha compositing. Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. The composition process uses an alpha channel. (wikipedia.org, answers.com)

TransparentRectanglesEx.java
package com.zetcode;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;

/**
 * ZetCode Java SWT tutorial
 *
 * This program draws ten rectangles with different
 * levels of transparency.
 *
 * Author: Jan Bodnar
 * Website: zetcode.com
 * Last modified: June 2015
 */

public class TrasparentRectanglesEx {

    public TrasparentRectanglesEx(Display display) {
        
        initUI(display);
    }

    private void initUI(Display display) {
        
        Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.CENTER);

        shell.addListener(SWT.Paint, event -> drawRectangles(event));

        shell.setText("Transparent rectangles");
        shell.setSize(590, 120);
        shell.open();

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

    private void drawRectangles(Event e) {
        
        GC gc = e.gc;

        Color blueCol = new Color(e.display, 0, 0, 255);
        gc.setBackground(blueCol);

        for (int i = 1; i < 11; i++) {
            gc.setAlpha(i * 25);
            gc.fillRectangle(50 * i, 20, 40, 40);
        }

        blueCol.dispose();
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        Display display = new Display();
        TrasparentRectanglesEx ex = new TrasparentRectanglesEx(display);
        display.dispose();
    }
}

In the example we draw ten rectangles with different levels of transparency.

gc.setAlpha(i * 25);

The setAlpha() method sets the aplha transparency value.

Transparent rectangles
Figure: Transparent rectangles

Donut

In the following example we create an complex shape by rotating a bunch of ellipses.

DonutEx.java
package com.zetcode;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;

/**
 * ZetCode Java SWT tutorial
 *
 * This program creates a donut shape.
 *
 * Author: Jan Bodnar
 * Website: zetcode.com
 * Last modified: June 2015
 */

public class DonutEx {

    public DonutEx(Display display) {
        
        initUI(display);
    }

    private void initUI(Display display) {
        
        Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.CENTER);

        shell.addListener(SWT.Paint, event -> drawDonut(event));

        shell.setText("Donut");
        shell.setSize(430, 300);
        shell.open();

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

    private void drawDonut(Event e) {
        
        GC gc = e.gc;
        
        int w = e.width;
        int h = e.height;

        gc.setAntialias(SWT.ON);

        Transform tr = new Transform(e.display);
        tr.translate(w / 2, h / 2);
        gc.setTransform(tr);

        for (int rot = 0; rot < 36; rot++) {
            
            tr.rotate(5f);
            gc.setTransform(tr);
            gc.drawOval(-125, -40, 250, 80);
        }
        
        tr.dispose();
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        
        Display display = new Display();
        DonutEx ex = new DonutEx(display);
        display.dispose();
    }
}

In this example, we create a donut. The shapes resembles a cookie, hence the name donut.

gc.setAntialias(SWT.ON);

We turn on the antialiasing with the setAntialias() method, which makes the painting more smooth.

Transform tr = new Transform(e.display);
tr.translate(w / 2, h / 2);
gc.setTransform(tr);

We move the middle of the axis to the center of the window.

for (int rot = 0; rot < 36; rot++) {
    
    tr.rotate(5f);
    gc.setTransform(tr);
    gc.drawOval(-125, -40, 250, 80);
}

In the for loop, we do a rotation operation and draw the ellipse.

Drawing text

In the next example, we draw some text on the window.

SoulmateEx.java
package com.zetcode;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;

/**
 * ZetCode Java SWT tutorial
 *
 * This program draws text
 * on the window.
 *
 * Author: Jan Bodnar
 * Website: zetcode.com
 * Last modified: June 2015
 */

public class LyricsEx {

    public LyricsEx(Display display) {
        
        initUI(display);
    }
    
    private void initUI(Display display) {

        Shell shell = new Shell(display);

        shell.addListener(SWT.Paint, event -> drawLyrics(event));

        shell.setText("Soulmate");
        shell.setSize(380, 300);
        shell.open();

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

    private void drawLyrics(Event e) {
        
        GC gc = e.gc;
        
        gc.setAntialias(SWT.ON);

        Font font = new Font(e.display, "Purisa", 10, SWT.NORMAL);
        Color col = new Color(e.display, 25, 25, 25);

        gc.setForeground(col);
        gc.setFont(font);

        gc.drawText("Most relationships seem so transitory", 20, 30);
        gc.drawText("They're good but not the permanent one", 20, 60);
        gc.drawText("Who doesn't long for someone to hold", 20, 120);
        gc.drawText("Who knows how to love without being told", 20, 150);
        gc.drawText("Somebody tell me why I'm on my own", 20, 180);
        gc.drawText("If there's a soulmate for everyone", 20, 210);

        col.dispose();
        font.dispose();
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        
        Display display = new Display();
        LyricsEx ex = new LyricsEx(display);
        display.dispose();
    }
}

We display part of the lyrics from the Natasha Bedingfields Soulmate song.

Font font = new Font(e.display, "Purisa", 10, SWT.NORMAL);

Here we specify the font that we use.

gc.drawText("Most relationships seem so transitory", 20, 30);

The drawText() method draws text onto the window.

Soulmate
Figure: Soulmate

In this chapter of the Java SWT tutorial, we did some painting.