Welcome!

Java IoT Authors: Yeshim Deniz, Zakia Bouachraoui, Liz McMillan, Elizabeth White, William Schmarzo

Related Topics: Java IoT

Java IoT: Article

SWT - A Native Widget Toolkit for Java Part 1 of 2

SWT - A Native Widget Toolkit for Java Part 1 of 2

The Standard Widget Toolkit (SWT) is a Java class library that allows you to create native user interfaces. It's designed to provide efficient, portable access to the underlying facilities of the operating system on which it's implemented. SWT uses native widgets wherever possible, giving an SWT program a native look and feel and a high level of integration with the desktop. In addition, SWT includes a rich set of controls such as tree, table, and tab folder. This article introduces SWT by describing some of the basic concepts and classes.

Hello World: A Simple SWT Program
The easiest way to learn SWT is to study a simple example. The following code shows a complete SWT program that creates and displays a new window on the desktop with "Hello World" in the title bar. Figure 1 shows the result of running this program on Windows XP.

1 import org.eclipse.swt.*;
2 import org.eclipse.swt.graphics.*;
3 import org.eclipse.swt.widgets.*;

4 public class HelloWorld {
5 public static void main(String[] args){
6 Display display = new Display();
7 Shell shell = new Shell(display);
8 shell.setText("Hello World");
9 shell.setSize(200,100);
10 shell.open ();
11 while (!shell.isDisposed()) {
12 if (!display.readAndDispatch())
13 display.sleep ();
14 }
15 display.dispose ();
16 }
17 }

Lines 1-3: SWT is divided into a number of packages, each modeling a different area of the user interface. All packages begin with the prefix org.eclipse.swt. The package org.eclipse.swt itself contains classes used by every package in SWT, such as constants and exceptions, while org.eclipse.swt.widgets contains only the widget classes. We didn't actually need to import org.eclipse.swt itself or org.eclipse.swt.graphics in this example because we didn't use any classes from these packages. However, any significant SWT program will use these three packages and this is a good place to introduce them.

Line 6: Every SWT program must create a Display. Typically, the first line of an SWT program creates a display, which SWT uses to establish the connection with the underlying platform window system. The class Display is very important in SWT. For readers familiar with the X Windows system, an SWT Display is equivalent to an X Windows Display.

Lines 7-9: These lines create a shell, and set the title and the size. Top-level windows are represented by the class Shell and are created on a Display. It's not necessary to set either the title or the size of a shell when it's created. A shell can have an empty title and the window system will assign the initial position and size using the standard algorithm of the desktop.

Line 10: A shell is invisible when it's created. The method open() makes the shell visible, brings it to the front on the desktop, and sets user input so when keys are typed, they go to the shell.

Lines 11-14: Like most modern window systems, SWT supports an event-driven user interface. This requires an explicit event loop that repeatedly reads and dispatches the next user interface event from the operating system. When there are no more events to dispatch, the program goes to sleep waiting for the next event, yielding the CPU to other programs on the desktop. The loop terminates when the programmer decides that the program has ended, typically when the application's main window, in our case the shell, closes. It's up to the application programmer to decide the exit condition for the event loop, as only he or she knows when the program is finished.

Line 15: This line disposes the Display. Strictly speaking, it's not necessary to dispose the Display as long as the program exits to the operating system. In all modern operating systems and on every platform SWT supports, exiting to the operating system releases any resources that were acquired by the process, including the resources acquired by SWT through the Display. So why include this line in the sample program? Not only is it good form to dispose of resources that you acquire, it can help you find places where you are not explicitly disposing resources, especially when using third-party or operating system-level tools that look for leaks.

As long as the window remains open, the event loop keeps Java alive and the SWT program keeps running.

Widgets: Shells and Controls
A Control is a user-interface element that's contained in a shell. Controls are common in all user interfaces. Buttons, labels, trees, and tables are all controls and users are familiar with these from other programs on the desktop.

Taking a bottom-up view of the world, every control has a parent and this parent can be another control, called a Composite. Shell is a subclass of Composite, so shells can have children. The parent of a shell is the display or another shell. Stated another way, this time from the top down, a display contains a list of top-level shells, where each shell is the root of a tree containing subtrees composed of composites and controls. Composites contain other composites, allowing the tree to have an arbitrary depth. When the child of a shell is another shell, the child is commonly called a dialog shell. A dialog shell floats on top of its parent shell.

It's important to understand the difference between the runtime and inheritance hierarchy of controls. The hierarchies constructed at runtime are containment hierarchies. A Shell is not a subclass of Display, but a display can contain a list of shells. Figure 2 shows the inheritance hierarchy of Display, Shell, Button, and Group, along with the containment hierarchy that's built at runtime from instances of these classes.

The concept of a containment hierarchy is an important one in SWT, so much so that it's reflected in the constructor of almost every object.

Controls are created using a constructor that takes the parent and a style. Styles are bit values used to represent operating system features that are create-only, such as multi- or single-line text edit capability, scroll bars, or borders. Because these operating-system features cannot be changed after creation, the style of a control cannot be altered after instantiation. Style bits provide a compact and efficient method of describing the create-only properties of a control. An alternative implementation would be a large number of constructors in each class containing an arbitrary list of boolean parameters, each parameter in an arbitrary order.

As expected, you can combine styles by using a bitwise-or operation. All styles are defined as constants in the class org.eclipse.swt.SWT. For example, the following code fragment creates a multiline text control that has a border and horizontal and vertical scroll bars:

new Text(composite, SWT.MULTI |
SWT.V_SCROLL | SWT.H_SCROLL |
SWT.BORDER);

To use the default style of a control, the style value SWT.NONE is specified in the constructor. The list of the style constants that correspond to each control is described in the documentation for the control.

A list of the basic SWT controls is shown in Table 1.

Events
So far we've described how to create controls and set various properties, configuring them either in the constructor or through methods that are public APIs. These are all operations performed on a control by the programmer. However, controls are also visual user-interface elements. What happens when the user presses a button or selects an item from a list?

We have already described the display and its role in the implementation of the event loop, reading and dispatching events from the operating system. In fact, without an event loop, an SWT program will terminate and return to the operating system when main() terminates. The event loop plays a critical role interacting with the user. Events are generated by the user, dispatched by the event loop, and application code is invoked in response. Application code registers interest in events by adding an event listener.

A final word about events: they are synchronous (note: don't confuse this term with the Java keyword "synchronized"). This means that your code will never be interrupted to handle an event. Events are only delivered when you call an SWT method. In the case of the event loop, calling readAndDispatch() allows any events that the user has generated to be delivered to your program. If you don't call readAndDispatch(), you'll never see events from the user; your program will appear hung, and the user will eventually kill it.

Listeners: Typed and Untyped
SWT has two ways to listen for events: typed and untyped.

A typed listener is exactly the same as a JavaBean listener. Typed listeners and their events are found in the package org.eclipse.swt.events. For example, to listen for a selection event in a push button, application code uses addSelectionListener(SelectionListener listener). When the user selects the button, widgetSelected(SelectionEvent event) is called from the event loop. SelectionListener is an interface. If there's more than one method defined in the listener interface, an adapter class exists that provides default no-op implementations of the listener methods. This means that you could use a SelectionAdapter to determine when a button has been selected instead of a SelectionListener. Listing 1 adds two typed listeners to a button, listening for selection and a change in focus, respectively.

Untyped listeners provide a generic, low-level mechanism to listen for any event. There are only two classes involved: a single generic interface called Listener and a single event class called Event. These two classes are found in org.eclipse.swt.widgets. Instead of following the JavaBeans pattern that requires a specific method to add each kind of listener, untyped listeners are added using only one method, addListener (int type, Listener listener). The type argument specifies the event you are interested in receiving. Type arguments are constants in the class SWT and are mixed case by convention. For example, SWT.Selection is an event type constant. All other constants in SWT are uppercase.

The Listener interface has a single method, handleEvent(Event event), that's called when the event occurs. One possible way to listen for untyped events is to implement a single listener and use the event argument to determine the type of event that occurred (see Listing 2).

The trade-off between the two listener models is one of speed and space. Using untyped listeners, it's possible to minimize the number of classes and methods used to listen for events.

As well as adding listeners, it's also possible to remove them, but this is generally unnecessary. Listeners are garbage-collected when a control is disposed, providing there are no other references to the listener in the application program.

Disposing Controls
An SWT control is explicitly disposed when it's no longer required. Sometimes the dispose operation is initiated by the user. For example, the user may click on the close box of a shell. More often, a control is no longer required by the programmer and can be given back to the operating system. Controls are disposed using the dispose() method.

When the dispose() method is called, the underlying window system resources are released, giving memory and other operating system resources, such as handles, back to the operating system. When the root of a control hierarchy is disposed, the children are automatically disposed. Therefore, disposing a shell disposes the children. Similarly, disposing the display, disposes all the shells that were created on the display.

When a control is disposed, either explicitly from dispose() or implicitly when an ancestor is disposed, a SWT.Dispose event is sent. The dispose event is a good place to dispose graphics resources that you have created for that control. If you try to access a control that has been disposed, the operating system won't crash. Instead, SWT will raise an exception because it's a programming error to access a disposed control.

If you never dispose a control, but instead hide it or never make it visible, eventually the operating system will run out of resources. In practice, it's hard to write code that does this by accident. For one thing, programmers generally don't lose track of their controls because they require them to present information to the user. Because controls are usually visible, it's obvious when there are too many on the screen.

Positioning and Sizing Controls
Each control is sized and positioned relative to its parent using the methods setLocation(int x, int y), setSize(int width, int height), and setBounds(int x, int y, int width, int height). The following code fragment positions and sizes three different controls:

control1.setLocation(12,23);
control2.setSize(100,100);
control3.setBounds(10,10,200,100);

Sizing and positioning of a control always refers to the entire control, not just the contents. For example, the size and position of a shell includes the window trim and the menu bar. The rectangle that contains the entire control is called the bounds of the control.

The client area of a control is the smaller rectangle within the bounds that the control uses to show its contents. For example, the client area of a text widget is the area where the lines of text are drawn, not including the scroll bars or borders. Child controls are always positioned relative to the client area of the parent, not its bounds. The client area of a control is never explicitly resized or positioned through API. Rather, setting the bounds of a control implicitly sets the client area. Figure 3 shows the bounds and client area of a text control.

Controls can compute their preferred size using the method computeSize(int wHint, int hHint). This method doesn't actually set the size of a control but rather returns a size that's a good default for the control. When the constant SWT.DEFAULT is used for both the width and height hint arguments, the control computes the smallest size necessary to completely show its contents. When a width or height value is used to compute the preferred size instead of the constant SWT.DEFAULT, the control computes its smallest size based on the hint arguments. For example, specifying a width of 100 and height of SWT.DEFAULT when computing the preferred size of a label that wraps is equivalent to asking the question: "If the label were to be resized to be 100 pixels wide, how tall would the label need to be to show the contents, wrapping lines of text as necessary?"

Use the pack() method of a control and set its bounds to the preferred size. Using pack() is equivalent to computing the preferred size and then using the result to set the size of the control.

As we've seen, the preferred size of a control depends on its contents. The preferred size can be queried from a control and used to position it within its parent. Writing code to explicitly size and position each control can be quite tedious and error prone. In addition, this code must almost always run when the parent is resized, so that the children will remain visible as the user resizes the window. SWT provides layout classes to compute the size of the controls and automate positioning of children when the parent is resized.

Layouts and Layout Data
Layouts are found in the package org.eclipse.swt.layout. Layouts are used to encode a positioning algorithm that's applied to the children of a composite whenever it's resized. The method setLayout(Layout layout) is used to set a layout into a composite. The details of the algorithm and API used to configure a layout are specific to each individual layout. Layout strategies are usually quite different and are built around different concepts, causing each layout to have a unique API. By convention, layout classes end with the suffix "Layout".

Some layouts allow each child to supply data that's specific to the positioning of the child, in addition to the preferred size, giving finer control over positioning and sizing. This is done using the method setLayoutData(Object layoutData) on each control. Layout data and its API are very specific to the layout used by the composite. For maximum flexibility, layout data can be of any type but must match the type that is expected by the layout class. By convention, layout data classes end with the suffix "Data".

It's important to note that layouts are set on the parent while layout data is set on the children.

Two of the simplest layouts are FillLayout and RowLayout. More advanced positioning can be achieved using GridLayout and FormLayout. These last two layouts are more complicated but offer increased flexibility. The following section provides a quick overview of these four layout algorithms. In some situations it may be necessary to provide a customized layout algorithm, which can be achieved by subclassing the abstract class org.eclipse.swt.widgets.Layout.

FillLayout
FillLayout is intended to position a single child so that the child fills up all the available client area of a composite. FillLayout has no corresponding layout data. Figure 4 shows a shell using FillLayout with a single text control. The text control occupies all the available space in the shell. Currently, FillLayout provides no margins or spacing between controls.

If more than one control is added, the space is divided evenly between each of the controls, either vertically or horizontally. Figure 5 shows a horizontal FillLayout in a shell with three controls where the size of each is the height of the shell's client area and each control takes up one-third of the width.

In practice, you typically don't add more than one child to a FillLayout because it's not really intended to be used this way. Instead, you might use a RowLayout.

RowLayout
RowLayout lays out controls in a single row, either horizontally or vertically. Details such as wrapping of controls, margins, and the spacing between controls can be configured.

RowLayout has a corresponding layout data that's rarely used, called RowData. Normally, RowLayout uses SWT.DEFAULT when calling computeSize() to get the preferred size of a control. This happens when no RowData is provided for the control. When RowData is provided, it's used to specify values in place of SWT.DEFAULT, allowing you to explicitly set the size of a control within a RowLayout.

Unlike FillLayout, RowLayout wraps controls by default. Figure 6 show a RowLayout that has three controls on it. Although the label and button fit on the same line, the progress bar is placed beneath them because the shell has been resized so there's not enough space to show all three controls on the same row.

RowLayout is more flexible than FillLayout and is generally used to lay out rows of buttons. In practice, most windows are a lot more complicated and require more flexible layout algorithms such as GridLayout.

GridLayout
GridLayout divides a composite into a grid of rectangular cells. The number of columns is critical and determines the final number of rows. This depends on the number of children in the composite. By default, controls are placed into cells in the order they are created. As each child control is created, it's placed in the next available column, which, depending on the number of columns and the span of the control, may be on a new row. By default each control occupies one column.

GridLayout has corresponding layout data, called GridData, that's almost always used by the programmer. Using a GridData, the programmer can control the number of columns to be spanned by a control, the anchoring, the alignment against the edges of the cell, and the width and height values to be passed to computeSize().

Figure 7 shows a GridLayout shell with two columns and three children that are two group boxes and a scale. The group boxes occupy the first and second columns, while the scale occupies both columns on the next line. The scale uses a GridData with a horizontal spanning of two, so the cell it will occupy will include both columns. To force the scale to fill the entire area of the cell, a horizontal fill property was also specified.

The "Gender" group box uses GridLayout with one column to place its two radio button children on separate lines. The "Likes" group box is using a GridLayout with two equal width columns. Its first two check buttons are placed in columns one and two on the first row, and the next two are placed on the second row. Because GridLayout's "makeColumnsEqualWidth" property is true, this makes "Music" and "Art" have the same width as the two wider buttons.

Using GridLayout, it's possible to construct sophisticated user interfaces and achieve just about any positioning and sizing requirement. Many user interfaces, especially those found in dialogs, are inherently grid-based, making GridLayout a good choice. For user interfaces that are not grid-based, FormLayout can be used.

FormLayout
A FormLayout allows you to specify the position of a control in terms of its edges. Edges of a control are attached to a position in the parent. This can be an absolute position, a fraction, or a percentage of the width or height of the parent. Edges can also be attached to the edge of another control, giving FormLayout maximum flexibility.

The corresponding layout data class FormData is almost always used by the programmer. Each FormData has fields that represent the top, left, right, and bottom edges of the control. Each field is an instance of a FormAttachment, which specifies the attachment to use for that edge.

The constructor FormAttachment(int numerator, int denominator, int offset) creates a new form attachment that's used to attach the edge of a control to a position in its parent. In Figure 8, the right edge of the list box is assigned the attachment new FormAttachment(4,5,3), attaching it to be 4/5 of the width of the parent plus an extra 3 pixels. Instead of fractions, percentages can be specified.

The constructor FormAttachment(Control control, int offset) creates a new form attachment that's used to attach the edge of a control to the edge of a sibling. In Figure 8, the combo box attaches its left edge to be 5 pixels from the right edge of the slider using the attachment FormAttachment(slider,5). By default, the opposite edge of a sibling is attached, although an alignment value can be provided to allow attachment to another edge. Under rare circumstances, it might make sense to attach the left edge of a control to the center or left edge of a sibling, potentially causing one control to be positioned on top of another.

Figure 8 shows a shell at its preferred size, while Figure 9 shows the same window resized. As the shell resizes, the controls are repositioned appropriately. The size of the list is automatically increased because of its attachments. The left, bottom, and right edges were expressed in terms of the parent, and the size of the parent has been increased. The slider and combo remain at their original positions. The combo, although attached to the slider, remains at the same location because the scale did not move.

As you can imagine, FormLayout is probably the most flexible layout of all. While it's possible to get almost any positioning imaginable using FormLayout, some user interfaces are more naturally expressed using the other layouts. Most SWT user interfaces are built from a combination of forms and grid layouts.

Forcing a Layout
When a composite is resized, its layout will automatically position and size the children based on the new size of the composite. There are times when the information that was used to calculate the position or size of a control can change without the layout being informed. For example, changing the text of a label will alter its preferred size. When this happens, the positioning and sizing calculations of the layout are no longer valid and children need to be repositioned even though the size of the parent has not changed. To force a layout to recalculate the position and size of its controls without resizing the composite, the layout() method is used.

Conclusion
This article has introduced some of the basic principles behind SWT and shows how to create simple windows and controls. One of the design goals of SWT was to create a UI toolkit that has a high level of integration with the operating system. This is achieved by using native widgets and operating system resources. SWT has been ported to a number of different operating systems, giving it wide coverage on the desktop. Part 2 of this article will show how to use the graphics capabilities of SWT, as well as menus, tab folders, trees, and tables.

Resources

  • Eclipse project home page allows you to download Eclipse, including swt.jar, swtsrc.zip, and the SWT shared library: www.eclipse.org
  • The SWT home page contains lots of code samples and on-line documentation: http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/ platform-swt-home/dev.html
  • Contains articles describing SWT, written by members of the SWT team: www.eclipse.org/articles/index.html
  • PDF documentation for the Eclipse project including SWT: www.eclipse.org/documentation/pdf/ org.eclipse.platform.doc.isv.pdf
  • Contains useful links for SWT including how to run it on a Pocket PC, a list of frequently asked questions, and how to use SWT with native Active-X integration: http://eclipsewiki.swiki.net/2
  • Gallery that shows many examples of SWT applications running on different operating systems and desktops: http://gallery.livemedia.com.au/

    SIDEBAR

    Obtaining SWT
    SWT was created as part of the IBM-led Eclipse open-source project whose members include Borland, Rational Software, RedHat, and TogetherSoft. Eclipse is an IDE that's implemented using SWT and is available at www.eclipse.org. On each platform, native widgets are used wherever possible. When a widget is not available, SWT provides an API-compatible emulated control.

    As well as the swt.jar that contains the Java code required to run SWT, there's also a shared library that allows SWT to make operating system calls. The name of the library varies between operating systems, and on Windows is named swt-xxx-nnnn.dll, where xxx is the operating system and nnnn is a version number. When you use the Java command to run a program that uses SWT, you need to specify the location of the shared library. Assuming that you've just installed the Eclipse 2.0.1 to run a class HelloWorld contained in helloworld.jar on Windows, the Java command would be:

    -classpath"helloworld.jar";C:
    \ECLIPSE\eclipse\plugins\
    org.eclipse.swt.win32_2.0.1\ws\win32\swt.jar
    Djava.library.path=C:\ECLIPSE\eclipse\plugins\
    org.eclipse.swt.win32_2.0.1\os\win32\x86
    HelloWorld

    The directory used in the VM argument is the one that contains the file swt-win32-2049.dll, although the exact name and location of the library varies between Eclipse versions and operating systems.

  • More Stories By Joe Winchester

    Joe Winchester, Editor-in-Chief of Java Developer's Journal, was formerly JDJ's longtime Desktop Technologies Editor and is a software developer working on development tools for IBM in Hursley, UK.

    Comments (32)

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


    IoT & Smart Cities Stories
    Dynatrace is an application performance management software company with products for the information technology departments and digital business owners of medium and large businesses. Building the Future of Monitoring with Artificial Intelligence. Today we can collect lots and lots of performance data. We build beautiful dashboards and even have fancy query languages to access and transform the data. Still performance data is a secret language only a couple of people understand. The more busine...
    Bill Schmarzo, author of "Big Data: Understanding How Data Powers Big Business" and "Big Data MBA: Driving Business Strategies with Data Science," is responsible for setting the strategy and defining the Big Data service offerings and capabilities for EMC Global Services Big Data Practice. As the CTO for the Big Data Practice, he is responsible for working with organizations to help them identify where and how to start their big data journeys. He's written several white papers, is an avid blogge...
    Nicolas Fierro is CEO of MIMIR Blockchain Solutions. He is a programmer, technologist, and operations dev who has worked with Ethereum and blockchain since 2014. His knowledge in blockchain dates to when he performed dev ops services to the Ethereum Foundation as one the privileged few developers to work with the original core team in Switzerland.
    René Bostic is the Technical VP of the IBM Cloud Unit in North America. Enjoying her career with IBM during the modern millennial technological era, she is an expert in cloud computing, DevOps and emerging cloud technologies such as Blockchain. Her strengths and core competencies include a proven record of accomplishments in consensus building at all levels to assess, plan, and implement enterprise and cloud computing solutions. René is a member of the Society of Women Engineers (SWE) and a m...
    Andrew Keys is Co-Founder of ConsenSys Enterprise. He comes to ConsenSys Enterprise with capital markets, technology and entrepreneurial experience. Previously, he worked for UBS investment bank in equities analysis. Later, he was responsible for the creation and distribution of life settlement products to hedge funds and investment banks. After, he co-founded a revenue cycle management company where he learned about Bitcoin and eventually Ethereal. Andrew's role at ConsenSys Enterprise is a mul...
    In his general session at 19th Cloud Expo, Manish Dixit, VP of Product and Engineering at Dice, discussed how Dice leverages data insights and tools to help both tech professionals and recruiters better understand how skills relate to each other and which skills are in high demand using interactive visualizations and salary indicator tools to maximize earning potential. Manish Dixit is VP of Product and Engineering at Dice. As the leader of the Product, Engineering and Data Sciences team at D...
    Whenever a new technology hits the high points of hype, everyone starts talking about it like it will solve all their business problems. Blockchain is one of those technologies. According to Gartner's latest report on the hype cycle of emerging technologies, blockchain has just passed the peak of their hype cycle curve. If you read the news articles about it, one would think it has taken over the technology world. No disruptive technology is without its challenges and potential impediments t...
    If a machine can invent, does this mean the end of the patent system as we know it? The patent system, both in the US and Europe, allows companies to protect their inventions and helps foster innovation. However, Artificial Intelligence (AI) could be set to disrupt the patent system as we know it. This talk will examine how AI may change the patent landscape in the years to come. Furthermore, ways in which companies can best protect their AI related inventions will be examined from both a US and...
    Bill Schmarzo, Tech Chair of "Big Data | Analytics" of upcoming CloudEXPO | DXWorldEXPO New York (November 12-13, 2018, New York City) today announced the outline and schedule of the track. "The track has been designed in experience/degree order," said Schmarzo. "So, that folks who attend the entire track can leave the conference with some of the skills necessary to get their work done when they get back to their offices. It actually ties back to some work that I'm doing at the University of San...
    When talking IoT we often focus on the devices, the sensors, the hardware itself. The new smart appliances, the new smart or self-driving cars (which are amalgamations of many ‘things'). When we are looking at the world of IoT, we should take a step back, look at the big picture. What value are these devices providing. IoT is not about the devices, its about the data consumed and generated. The devices are tools, mechanisms, conduits. This paper discusses the considerations when dealing with the...