Using the Sash Widget in Java SWT

This is the first in what will be a series of posts detailing some of the problems I ran into when developing an SWT-based GUI in the Eclipse development environment.  I hadn’t developed a GUI in Java since Swing was the new hotness, so SWT was new to me.

Sash Layout Overview

Layout Overview

The main window design called for a toolbar across the top, a table which lists entries from a database, a composite under the table which provides details on the selected entry, and a status bar on the bottom.  It was easy enough to position the widgets using a GridLayout, but I wanted the user to be able to adjust the relative sizes of the table and detail composite, giving either more or less screen real estate to whichever of the two widgets is of the most interest at the moment.  I suspected that a sash was the way to do this, but the SWT snippet library, which is very useful in most cases, contained surprisingly little information on the use of sashes.  After some experimentation, here is what I learned.

Part of the problem was that I was using a GridLayout for the main shell.  Once I switched to using a FormLayout, the sash became trivial to implement.  (This article on layouts is spectacular, by the way.) With the GridLayout, I instantiated the widgets in order from the top to the bottom of the shell, but when I switched to a FormLayout I needed to change the order in which the widgets were created.

The first step when laying out the widgets is to position the sash:

    final Sash sash = new Sash(shell, SWT.BORDER | SWT.HORIZONTAL);
    formData = new FormData();
    formData.top = new FormAttachment(30, 0);
    formData.left = new FormAttachment(0, 0);
    formData.right = new FormAttachment(100, 0);
    formData.height = 3;
    sash.setLayoutData(formData);

When the application is started, this sash is positioned in such a way that 30% of the window space is provided for the toolbar and table at the top of the window, and 70% is provided for the detail composite and status bar at the bottom.

At this point, the general idea is to place the widgets from the top of the shell down, until you reach the sash.  Then you place widgets from the bottom of the shell up, again until you reach the sash.  In my case, I instantiated the toolbar first and attached it to the top of the main shell.  Then I created the table and attached the top of it to the bottom of the toolbar, and the bottom of it to the top of the sash.  The next step was to start at the bottom of the shell by attaching a composite for the status bar to the bottom of the main shell.  Then I attached the bottom of the detail composite to the top of the status bar composite, and the top of the detail composite to the bottom of the sash.

With that updated layout, the selection listener for the sash became relatively simple:

    sash.addListener(SWT.Selection, new Listener () {
        public void handleEvent(Event e) {
            sash.setBounds(e.x, e.y, e.width, e.height);

            FormData formData = new FormData();
            formData.top = new FormAttachment(0, e.y);
            formData.left = new FormAttachment(0, 0);
            formData.right = new FormAttachment(100, 0);
            formData.height = 3;
            sash.setLayoutData(formData);
            shell.layout(true);
        }
    });

When the sash is moved, this listener causes its layout data to be replaced.  The top of the sash is set to the user-specified location, and the layout() method of the shell is invoked, which will cause the table and detail widgets to be resized to accommodate the new sash location (since they are attached to the sash).

Obviously, it’s easy to modify this layout strategy for vertical sashes.  It does get a bit more complex if you want to have multiple sashes in the same window, but even that is not too bad: if I had wanted a vertical sash in the detail composite, I could have simply used a form layout within that composite, building widgets from the left and right sides of the composite until they met the sash in the middle.

So there you go:  a quick summary of my experience with the elusive sash widget.

Advertisements

3 comments

  1. One thing that helped me was to change a line in your event listener from
    formData.top = new FormAttachment(0, e.y);
    to
    formData.top = new FormAttachment((e.y * 100) / shell.getBounds.width, 5);

    This allows the user to drastically resize the window without form elements disappearing. It makes more sense for me because I have a vertical sash, and if a user has the window maximized, moves the sash almost all the way to the right side, then unmaximizes the window, the sash and the elements to the right of the sash are no longer visible.

  2. Pingback: Progress Bar Strategies for Java SWT « Zombie Process


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s