SWT (Standard Widget

snottybugbearΛογισμικό & κατασκευή λογ/κού

3 Νοε 2013 (πριν από 3 χρόνια και 10 μήνες)

75 εμφανίσεις

SWT (Standard Widget
Toolkit) TUTORIAL
By Kalman Hazins
(kalman@zikal.com)
Agenda

Brief History of Java GUI

Installing SWT

Creating widgets

SWT Layouts

Event Handling

Sample Application
History of Java GUI

AWT

Abstract Windowing Toolkit

First released in 1995 as part of JDK 1.0 by Sun

Heavyweight GUI components

a Java component creates a peer
component on the operating system and the peer draws itself.

Least Common Denominator problem

for simple GUI components
creating a peer works, what about the components that are only
available on some platforms and not others? If you want to write code
that’s truly portable

you have to use components that are available on
all platforms

The logic makes sense

but how do you develop a serious application
using just the basic components (available on all platforms)?

You don’t …

Enter
Swing
History of Java GUI (Cont.)

Swing (JFC

Java Foundation Classes)

Released in 1998 as part of JDK 1.1

Lightweight GUI components

no need for operating system
“peer”
-
based drawing. Let’s draw the components ourselves.
Lightweight

there is no actual weight (operating system
component) behind the Java component.

Nice toolkit with enhanced Model
-
View
-
Controller architecture
and superior graphics 2D library.

Portable? You bet. Any problems? Now that you are not actually
using the operating system components

you are just mimicking
the behavior of the operating system. Hence, the look and feel
as well as the response speed are not the same.

Swing got much better over time

Still, very few commercial applications are written in Swing.
History of Java GUI (Cont.)

SWT (Standard Widget Toolkit)

GUI toolkit released in November 2001

Was initially designed to write the now extremely famous and
popular Eclipse IDE

“Best of both worlds” approach

use native functionality when
available, and Java implementation when unavailable

Takes on the
appearance
and
behavior
of the native platform

Because of its close bond with the operating system, SWT
needs to be ported separately for every platform

Currently, implementations of SWT are already available for all
major desktop operating systems and some handheld devices

The code YOU write will be portable for all the platforms that
have SWT implementations for them (unless you decide to do
some platform specific stuff like OLE on windows)

http://www.eclipse.org/swt/
-
SWT home page
Installing SWT

To compile and run SWT applications you need
1.
SWT jars (usually just
swt.jar
)
2.
SWT native libraries

Detailed Instructions on obtaining and “installing”
1.
Go to
http://www.eclipse.org/swt
and follow one of the many
mirror links
2.
This will bring you to another page, where you want to follow the
“Latest Release” link
3.
This should bring you to a page which will say “Release Build: “ in
bold letters on the very top
4.
Scroll down to the bottom of the page till you see “SWT Binary and
Source” section
5.
Pick the platform you intend to develop on from the list (e.g.
Windows XP) and click on “(http)” to start downloading the zip file
6.
Extract the contents of the zip file into a directory and you are
ready for the final step(s) (let’s say our directory path is C:
\
SWT)
Installing SWT (Cont.)
7.
You need to include swt.jar (and possibly other jars) from the C:
\
SWT
folder in your classpath (for an example on setting classpath see
http://www.moreservlets.com/Using
-
Tomcat
-
4.html#Set
-
CLASSPATH
)
8.
You also need to include the native library files (e.g. *.dll) from
C:
\
SWT in your java.library.path.
a.
The easiest way to do this one is to execute the following
command from a regular java program
System.out.println(System.getProperty(“java.library.path”));
which will give you a list of the directories in your “library path”.
You can then copy the native library files from C:
\
SWT to one of
those directories.
-
OR
-
b.
Simply provide the path when running java
java

Djava.library.path=C:
\
SWT classname
Creating Widgets

SWT
Javadoc
-
http://www.jlab.net/eclipse/doc/3.1/index.html

Simplest SWT program (explained over the next few slides)
1.
import
org.eclipse.swt.widgets
.*;
2.
import
org.eclipse.swt.widgets.Shell
;
3.
public class
HelloWorld
{
4.
public static void main(String[]
args
) {
5.
Display
display
= new Display();
6.
Shell
shell
= new Shell(display);
7.
shell.setText
("Hello World");
8.
shell.setSize
(250, 100);
9.
10.
shell.open
();
11.
12.
while (!
shell.isDisposed
()) {
13.
if (!
display.readAndDispatch
()) {
14.
display.sleep
();
15.
}
16.
}
17.
display.dispose
();
18.
}
19.
}
Creating Widgets (Cont.)

Think of
Shell
object (line 6) being almost the same as a
JFrame
in
Swing, i.e. the highest
-
level container, which contains other widgets (e.g.
buttons, labels etc.) inside of it

Unlike Swing
1.
You need to create
Display
object (line 5), which represents the
underlying windowing system. This in turn serves as a parent to the
Shell.
(In SWT, every widget you create will always have its parent
passed into the widget’s constructor.)
2.
You need to keep the Shell open to listen for events with a while loop
(lines 12
-
16). Otherwise, the Shell will immediately close itself.
3.
Since you are not just writing some Java code (having the luxury of
garbage collector clean up after you), but are actually requesting some
heavyweight resources from the underlying platform

you need to
dispose of those resources when you are done with them(line 17).
(Luckily, disposing of the parent disposes of its child, so 99% of time you
will not be running around disposing of widgets right and left.)

If you are a Swing guy, and the above 3 things greatly bother you

you
can write a simple
SWTUtil
class to help you deal with it …
Homegrown SWT Utility

SWTUtil.java
import
org.eclipse.swt.widgets
.*;
public class
SWTUtil
{
private static Display
display
= new Display();
public static Shell
getShell
() {
Shell
shell
= new Shell(display);
return shell;
}
public static void
openShell
(Shell
shell
) {
shell.open
();
// This loop keeps the shell open constantly listening for events
while (!
shell.isDisposed
()) {
if (!
display.readAndDispatch
()) {
display.sleep
();
}
}
display.dispose
();
}
}
SWT Utility in Action

“Simplest SWT program” rewritten
using
SWTUtil
class
import
org.eclipse.swt.widgets
.*;
public class
HelloWorld
{
public static void main(String[]
args
) {
Shell
shell
=
SWTUtil.getShell
();
shell.setText
(“Still Hello World");
shell.setSize
(250, 100);
SWTUtil.openShell
(shell);
}
}
Widget creation explained

A widget in SWT is created by
1.
Specifying parent
2.
Specifying style

A parent is the container that the widget is created inside of (e.g.
Shell).

Style is any constant from the SWT class (SWT.PUSH,
SWT.BORDER, SWT.LEFT etc).

All styles applicable to the widget can be found in the
Javadoc
for
that widget (as well as its
superclasses
if any).

If more than one style is desired

separate them out with a “|”
bitwise operator (e.g. SWT.MULTI |
SWT.V_SCROLL|SWT.H_SCROLL| SWT.BORDER creates a multiline
textarea
that has vertical and horizontal scrollbars and a border
around it). If no specific style is desired

use SWT.NONE. The style
you are requesting is only a hint, so if the underlying platform
doesn’t support it

you are out of luck.
Label

Unselectable
,
uneditable
text

SWT.VERTICAL or SWT.HORIZONTAL can be used together with
SWT.SEPARATOR to create a label that is a horizontal/vertical separator

LabelWorld.java
1.
import
org.eclipse.swt.SWT
;
2.
import
org.eclipse.swt.layout.GridLayout
;
3.
import
org.eclipse.swt.widgets
.*;
4.
public class
LabelWorld
{
5.
public static void main(String[]
args
) {
6.
Shell
shell
=
SWTUtil.getShell
();
7.
shell.setText
("Label World");
8.
shell.setLayout
(new
GridLayout
()); // layouts are explained later
9.
10.
// Create labels
11.
new Label(shell, SWT.NONE).
setText
("Regular label");
12.
new Label(shell, SWT.SEPARATOR);
13.
new Label(shell, SWT.SEPARATOR|SWT.HORIZONTAL);
14.
15.
// pack and show
16.
shell.pack
();
17.
SWTUtil.openShell
(shell);
18.
}
19.
}
Button

Once a button

always a button. All types of buttons are created using the Button
class. Push buttons, radio buttons, check buttons, toggle buttons and even flat
buttons.

ButtonWorld.java
1.
import
org.eclipse.swt.SWT
;
2.
import
org.eclipse.swt.layout.GridLayout
;
3.
import
org.eclipse.swt.widgets
.*;
4.
public class
ButtonWorld
{
5.
public static void main(String[]
args
) {
6.
Shell
shell
=
SWTUtil.getShell
();
7.
shell.setText
("Button World");
8.
shell.setLayout
(new
GridLayout
(2, true)); // layouts are explained later
9.
10.
new Button(shell, SWT.PUSH | SWT.FLAT).
setText
("Flat Push Button");
11.
new Button(shell, SWT.CHECK).
setText
("Check Button");
12.
new Button(shell, SWT.TOGGLE).
setText
("Toggle Button");
13.
new Button(shell, SWT.RADIO).
setText
("Radio Button");
14.
15.
// pack and show
16.
shell.pack
();
17.
SWTUtil.openShell
(shell);
18.
}
19.
}
Text

Different types of text widgets are created using Text class by providing the
appropriate styles

TextWorld.java
1.
import
org.eclipse.swt.SWT
;
2.
import
org.eclipse.swt.layout.GridLayout
;
3.
import
org.eclipse.swt.widgets
.*;
4.
public class
TextWorld
{
5.
public static void main(String[]
args
) {
6.
Shell
shell
=
SWTUtil.getShell
();
7.
shell.setText
("Text World");
8.
shell.setLayout
(new
GridLayout
()); // layouts are explained later
9.
10.
new Text(shell, SWT.NONE).
setText
("Missing something ...");
11.
new Text(shell, SWT.BORDER); // regular
textfield
12.
new Text(shell, SWT.PASSWORD | SWT.BORDER).
setText
("password");
13.
new Text(shell, SWT.READ_ONLY | SWT.BORDER).
setText
("Can't type inside");
14.
new Text(shell, SWT.MULTI | SWT.V_SCROLL | SWT.WRAP
15.
| SWT.BORDER).
setText
("
\
n
\
n
\
n");
16.
17.
// pack and show
18.
shell.pack
();
19.
SWTUtil.openShell
(shell);
20.
}
21.
}
List

Pick from a list

single or multiple selection available

ListWorld.java
1.
import org.eclipse.swt.SWT;
2.
import org.eclipse.swt.layout.GridLayout;
3.
import org.eclipse.swt.widgets.*;
4.
public class ListWorld {
5.
public static void main(String[] args) {
6.
Shell shell = SWTUtil.getShell();
7.
shell.setText("List World");
8.
shell.setLayout(new GridLayout(2, true)); // layouts are explained later
9.
10.
String[] items = "One Two Three Four Five Six".split(" ");
11.
List one = new List(shell, SWT.SINGLE | SWT.BORDER);
12.
one.setItems(items);
13.
one.select(2);
14.
List two = new List(shell, SWT.MULTI | SWT.BORDER);
15.
two.setItems(items);
16.
two.setSelection(items);
17.
18.
// pack and show
19.
shell.pack();
20.
SWTUtil.openShell(shell);
21.
}
22.
}
Combo

Benefits of both Text and List widgets in one!

ComboWorld.java
1.
import
org.eclipse.swt.SWT
;
2.
import
org.eclipse.swt.layout.GridLayout
;
3.
import
org.eclipse.swt.widgets
.*;
4.
public class
ComboWorld
{
5.
public static void main(String[]
args
) {
6.
Shell
shell
=
SWTUtil.getShell
();
7.
shell.setText
("Combo World");
8.
shell.setLayout
(new
GridLayout
(3, true)); // layouts are explained later
9.
10.
String[] items = "One Two Three Four Five
Six".split
(" ");
11.
Combo one = new Combo(shell, SWT.DROP_DOWN);
12.
one.setItems
(items);
13.
Combo two = new Combo(shell, SWT.DROP_DOWN | SWT.READ_ONLY);
14.
two.setItems
(items);
15.
Combo three = new Combo(shell, SWT.SIMPLE);
16.
three.setItems
(items);
17.
18.
// pack and show
19.
shell.pack
();
20.
SWTUtil.openShell
(shell);
21.
}
22.
}
Group

Used to group widgets together. (Very similar to
JPanel
in Swing)

GroupWorld.java
1.
import
org.eclipse.swt.SWT
;
2.
import
org.eclipse.swt.layout.GridLayout
;
3.
import
org.eclipse.swt.widgets
.*;
4.
public class
GroupWorld
{
5.
public static void main(String[]
args
) {
6.
Shell
shell
=
SWTUtil.getShell
();
7.
shell.setText
("Group World");
8.
shell.setLayout
(new
GridLayout
()); // layouts are explained later
9.
10.
Group
buttonGroup
= new Group(shell, SWT.SHADOW_OUT);
11.
buttonGroup.setText
("Six buttons");
12.
buttonGroup.setLayout
(new
GridLayout
(3, true));
13.
for(
int
i
= 0;
i
< 6;
i
++) {
14.
new Button(
buttonGroup
, SWT.RADIO).
setText
("Bottle " + (
i
+ 1));
15.
}
16.
17.
// pack and show
18.
shell.pack
();
19.
SWTUtil.openShell
(shell);
20.
}
21.
}
Browser

One of the newer widgets of SWT for displaying web content.

Cool stuff!!! (See the sample application later)

BrowserWorld.java
1.
import
org.eclipse.swt.SWT
;
2.
import
org.eclipse.swt.browser.Browser
;
3.
import
org.eclipse.swt.layout.FillLayout
;
4.
import
org.eclipse.swt.widgets.Shell
;
5.
public class
BrowserWorld
{
6.
public static void main(String[]
args
) {
7.
Shell
shell
=
SWTUtil.getShell
();
8.
shell.setText
("Browser World");
9.
shell.setLayout
(new
FillLayout
());
10.
11.
Browser
browser
= new Browser(shell, SWT.BORDER);
12.
browser.setSize
(900, 500);
13.
browser.setUrl
("http://www.eclipse.org/swt/");
14.
15.
// pack and show
16.
shell.pack
();
17.
SWTUtil.openShell
(shell);
18.
}
19.
}
Browser in Action
SWT Layouts

Layouts first introduced in AWT

Ease burden of laying out components

Promote cross
-
platform GUI design

SWT offers 5 layouts:
1.
FillLayout
2.
RowLayout
3.
StackLayout
4.
GridLayout
5.
FormLayout

You set the composite’s layout by calling
setLayout
()

You don’t have to use a layout, but do you really want your widgets to
disappear when the user resizes the window?

More on layouts
http://www.eclipse.org/articles/Understanding%20Layouts/Understanding%20Layouts.htm
FillLayout

Places all widgets in either a single column or a single row depending on if
SWT.VERTICAL or SWT.HORIZONTAL is used

Makes all widgets the same size

FillLayoutExample.java
1.
import org.eclipse.swt.SWT;
2.
import org.eclipse.swt.layout.FillLayout;
3.
import org.eclipse.swt.widgets.*;
4.
public class FillLayoutExample {
5.
public static void main(String[] args) {
6.
Shell shell = SWTUtil.getShell();
7.
shell.setText("FillLayoutExample");
8.
shell.setLayout(new FillLayout(SWT.HORIZONTAL));
9.
10.
for(int i = 0; i < 3; i ++) {
11.
new Button(shell, (i % 2 == 0) ? SWT.RADIO : SWT.PUSH).setText("Button " + i);
12.
new Text(shell, SWT.BORDER).setText("same size");
13.
}
14.
15.
// pack and show
16.
shell.pack();
17.
SWTUtil.openShell(shell);
18.
}
19.
}
RowLayout

Similar to
FillLayout
-
places all widgets in either a single column or a single row depending on if SWT.VERTICAL
or SWT.HORIZONTAL is used

Doesn’t force all widgets to be the same size

Can wrap to a new row or column if it runs out of space

Can use
RowData
objects to determine initial heights/widths for controls

RowLayoutExample.java
1.
import org.eclipse.swt.SWT;
2.
import org.eclipse.swt.layout.RowData;
3.
import org.eclipse.swt.layout.RowLayout;
4.
import org.eclipse.swt.widgets.*;
5.
public class RowLayoutExample {
6.
public static void main(String[] args) {
7.
Shell shell = SWTUtil.getShell();
8.
shell.setText("RowLayoutExample");
9.
shell.setLayout(new RowLayout(SWT.HORIZONTAL));
10.
11.
for(int i = 0; i < 3; i ++) {
12.
new Button(shell, (i % 2 == 0) ? SWT.RADIO : SWT.PUSH).setText("Button " + i);
13.
new Text(shell, SWT.BORDER).setLayoutData(new RowData(5, 50));
14.
}
15.
16.
// pack and show
17.
shell.pack();
18.
SWTUtil.openShell(shell);
19.
}
20.
}
StackLayout

Similar to
CardLayout
in Swing. The basic idea is that all widgets are stacked on top of each other and you can
only see one at a time.

Need to set
topControl
attribute for the layout to show any widget on top

Need to call
layout()
on the Composite every time you reassign
topControl

StackLayoutExample.java
1.
import org.eclipse.swt.SWT;
2.
import org.eclipse.swt.custom.StackLayout;
3.
import org.eclipse.swt.events.*;
4.
import org.eclipse.swt.widgets.*;
5.
public class StackLayoutExample {
6.
public static void main(String[] args) {
7.
final Shell shell = SWTUtil.getShell();
8.
shell.setText("RowLayoutExample");
9.
shell.setLayout(new StackLayout());
10.
11.
final Button button1 = new Button(shell, SWT.PUSH);
12.
button1.setText("Button One");
13.
final Button button2 = new Button(shell, SWT.PUSH);
14.
button2.setText("Button Two");
15.
class StackLayoutAdapter extends SelectionAdapter {
16.
public void widgetSelected(SelectionEvent event) {
17.
((StackLayout)shell.getLayout()).topControl =
18.
(event.widget == button1) ? button2 : button1;
19.
shell.layout();
20.
}
21.
}
22.
button1.addSelectionListener(new StackLayoutAdapter());
23.
button2.addSelectionListener(new StackLayoutAdapter());
24.
25.
((StackLayout)shell.getLayout()).topControl = button1;
26.
shell.pack();
27.
SWTUtil.openShell(shell);
28.
}
29.
}

GridLayout

Lays out controls in a grid.

A lot of people love this powerful layout.

You can easily specify what you want to happen when the composite is
resized

6 attributes (defaults are preset):
1.
int horizontalSpacing

horizontal space in pixels between
adjacent cells
2.
int verticalSpacing

vertical space in pixels between adjacent
cells
3.
boolean makeColumnsEqualWidth

forces all columns to be
same width
4.
int marginWidth

margin in pixels along right and left edges
5.
int marginHeight

margin in pixels along top and bottom edges
6.
int numColumns

number of columns for the layout

GridLayout(int numColumns, boolean makeColumnsEqualWidth)

Uses GridData objects to provide for better control

Too many options to list …

Warning
for Swing programmers

DO NOT TRY TO REUSE GridData
objects

Instead, you need to create a new GridData object for every widget that
needs non
-
default behavior
GridLayoutExample.java
1.
import
org.eclipse.swt.SWT
;
2.
import
org.eclipse.swt.layout
.*;
3.
import
org.eclipse.swt.widgets
.*;
4.
public class
GridLayoutExample
{
5.
public static void main(String[]
args
) {
6.
Shell
shell
=
SWTUtil.getShell
();
7.
shell.setText
("
GridLayoutExample
");
8.
shell.setLayout
(new
GridLayout
(2, false)); // 2 columns, same width
9.
10.
// Username
11.
new Label(shell, SWT.RIGHT).
setText
("Username:");
12.
Combo
cmbUsername
= new Combo(shell, SWT.DROP_DOWN);
13.
cmbUsername.setLayoutData
(new
GridData
(
GridData.FILL_HORIZONTAL
));
14.
cmbUsername.setItems
(new String[]{"Howard", "Admin", "Kalman"});
15.
cmbUsername.setText
("Admin");
16.
17.
// Password
18.
new Label(shell, SWT.RIGHT).
setText
("Password:");
19.
new Text(shell, SWT.BORDER | SWT.PASSWORD).
GridData
(
GridData.FILL_HORIZONTAL
));
20.
21.
// Login Button
22.
Button
loginButton
= new Button(shell, SWT.PUSH | SWT.FLAT);
23.
loginButton.setText
("Proceed to your account");
24.
GridData
data = new
GridData
(
GridData.FILL_HORIZONTAL
);
25.
data.horizontalSpan
= 2; // span 2 columns
26.
loginButton.setLayoutData
(data);
27.
shell.pack
();
28.
SWTUtil.openShell
(shell);
29.
}
30.
}
FormLayout

Considered the most complex layout of SWT

Based on
y = ax + b
(not that most people who use it care)

MAXIMUM flexibility

People who understand it

love it


The basic idea is that you layout the widgets relative to each other or to the enclosing
composite

Needs a tutorial of its own and is therefore not covered here …
Event Handling

If you are familiar with Swing

this last part should be a joke.

SWT widgets can
listen
for events to happen.

If you would like to hear when and what they hear

you need to
attach a listener
to
the widget

Listener
is basically an interface that defines when certain behaviors happen

Sometimes, listener tries listening out for two many things, but you only care to listen
for one particular event

In such a case

you need an
adapter. Adapter
is a class that
implements
the
interface and from which you can just extend and override the method you are
interested in.

Some of the popular
listeners/adapters
are listed below

FocusListener/FocusAdapter

listens for focus gained and focus lost events

KeyListener/KeyAdapter

listens for key releases and key presses

ModifyListener
(only has 1 method)

listens for text modifications

VerifyListener

listens for (and potentially intercepts) text modifications

MouseListener/MouseAdapter

listens for mouse button presses

SelectionListener/SelectionAdapter

listens for selection events (similar to
ActionListener in Swing)
EventHandling.java
1.
import org.eclipse.swt.SWT;
2.
import org.eclipse.swt.events.*;
3.
import org.eclipse.swt.layout.*;
4.
import org.eclipse.swt.widgets.*;
5.
public class EventHandling {
6.
private static boolean numbersOnly;
7.
public static void main(String[] args) {
8.
Shell shell = SWTUtil.getShell();
9.
shell.setText("EventHandling");
10.
shell.setLayout(new GridLayout(2, false));
11.
12.
// input
13.
Label lblInput = new Label(shell, SWT.RIGHT);
14.
lblInput.setText("Type in here:");
15.
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END);
16.
lblInput.setLayoutData(data);
17.
Text input = new Text(shell, SWT.BORDER);
18.
input.addVerifyListener(new VerifyListener() {
19.
public void verifyText(VerifyEvent vEvent) {
20.
vEvent.doit = false; // don't allow anything but numbers
21.
if(!numbersOnly || vEvent.character == '
\
b') {
22.
vEvent.doit = true;
23.
}
24.
else if(Character.isDigit(vEvent.character) && numbersOnly) {
25.
vEvent.doit = true;
26.
}
27.
}
28.
});
EventHandling.java
29.
Button btnAllow = new Button(shell, SWT.CHECK);
30.
btnAllow.setText("Allow numbers only");
31.
data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
32.
data.horizontalSpan = 2;
33.
btnAllow.setLayoutData(data);
34.
btnAllow.addSelectionListener(new SelectionAdapter() {
35.
public void widgetSelected(SelectionEvent selectionEvent) {
36.
numbersOnly = ((Button)(selectionEvent.widget)).getSelection();
37.
}
38.
});
39.
shell.pack();
40.
SWTUtil.openShell(shell);
41.
}
42.
}
syncExec() / asyncExec()

You should only be updating user interfaces from the user interface thread.

For example, say you create a Label in your main thread. Then, you have a separate thread that
does some sort of a long computation. Then, you want to update your label with the result of the
second thread’s computation. You
CANNOT
just call label.setText(newValue) in your second
thread.

Instead, you have to call either syncExec(Runnable) or asyncExec(Runnable) methods on the
instance of Display
// Say you run a thread that calculates new time approximately every second
// and tries to update a label
new Thread(new Runnable() {
public void run() {
Display display = shell.getDisplay();
while(!shell.isDisposed()) {
try {
display.asyncExec(new Runnable() {
public void run() {
clock.setText((new Date()).toString());
}
});
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
Sample Application

Goal: Write a cute browser in SWT (under
300 lines) that handles most HTML

CuteBrowser.java
uses
SWTUtil.java

Run the
application
on Windows XP
computer that has java installed