Desktop Java

SWT ScrolledComposite Explained

Like a friend of mine once put it, SWTs ScrolledComposite is a nasty beast. And to some point I do agree. This is likely the reason why there are so many questions asked about how to use this widget.

But its not only the authors of the ScrolledComposite to blame. When a piece of software doesn’t work the way you expect it to work, then … you curse … and try a little different … and curse differently … and ask Google for help … and (hopefully) find this lovely little post. Which tells you: RTFM! – ups, ehm, I mean of course take a look at the documentation.

And if you read the JavaDoc you will learn that there are two ways to use the ScrolledComposite and see corresponding sample code.

Two in One

The first way, is suitable for fixed size content and will show scrollbars if the contained control cannot be fully seen and hide them otherwise.

Alternatively, if set up accordingly, the ScrolledComposite imitates the way a browser would work. The content will grow and shrink with the size of the ScrolledComposite – until the visible area is less than the specified minimum size. In the latter case scrollbars will be shown and the content is never decreased below the minimum size.

The video shows the different operation modes side by side:

On the left side, the size of content remains the same while the windows is enlarged and scrollbars vanish when no longer needed. On the right side however, the initial windows size is smaller than the specified minimum size and therefore scrollbars appear. As the window grows larger, the content grows with the window.

Scrolling Fixed Content

To Set up the ScrolledComposite to show fixed content is really simple:

scrolledComposite = new ScrolledComposite( parent, SWT.H_SCROLL | SWT.V_SCROLL );
Label label = new Label( scrolledComposite, SWT.NONE );
label.setBackground( display.getSystemColor( SWT.COLOR_DARK_GREEN ) );
label.setSize( 400, 400 );
scrolledComposite.setContent( label );

Note that you need to explicitly specify the H_SCROLL and V_SCROLL style flags. Otherwise no scrollbars are created and the ScrolledComposite is of little use (more on scrollbars later).

The other noteworthy part of the snippet is where the content – a 400 x 400 px green label here – is created. The parent of the content must be the ScrolledComposite itself. If not you will see funny results. And finally the ScrolledComposite must be told the content that it should manage with setContent().

The example demonstrates the simplest case in which the content is a single control. If however the content to scroll consist of multiple controls, they needs to be wrapped into a Composite with a suitable layout like shown in contact details example.

Fixed size content in this context does not mean that the content must or can not change its size. If that happens the ScrolledComposite will adapt to the new size and show or hide scrollbars accordingly. The content however does not change its size if the ScrolledComposite it resized.

Scrolling Expanding Content

With a few additional lines, the above snippet can be extended to expand its content:

scrolledComposite.setExpandHorizontal( true );
scrolledComposite.setExpandVertical( true );
scrolledComposite.setMinSize( 250, 250 );

Afterwards, the ScrolledComposite will expand the content when resized and only show scrollbars if its size is reduced so that it is smaller than the minimum size. The SWT API offers further ways to set the minimum size. Either for the minimum width and height independently with setMinWidth() and setMinHeight(), or with setMinSize(Point).

It is legal to set the minimum size to zero (the default value) when expanding content. As a result, the content will shrink with no lower limit and no scrollbars will ever be shown.

These are the two basic modes of the ScrolledComposite: managing content of fixed size or expanding and reducing content.

Scrolling Vertically Only

Another use case that I have come across is to have a list of yet unknown length of items. Think of a lengthy contact details form with many lines each consisting of a label and an input field. The width of each line occupies as much space as there is but if the number if lines exceed the available height, it should be scrollable.

With a little tweak, the above shown expanding ScrolledComposite can be extended to scroll only vertically. The key hereto is to set the minimum size dynamically. Whenever the ScrolledComposite changes its size, the minimum width of the content is set to the available width of the ScrolledComposite.

The code to accomplish the described behavior is rather simple:

scrollComposite.addListener( SWT.Resize, event -> {
  int width = scrollComposite.getClientArea().width;
  scrollComposite.setMinSize( parent.computeSize( width, SWT.DEFAULT ) );
} );

The resize listener queries the available space of the ScrolledComposite with getClientArea()
and computes the necessary size for the content given the client areas width. Finally the resulting size is set as the minimum size of the ScrolledComposite.

In this example, the appearance of the content is governed by a two-column layout. The label column is as wide as necessary to show the longest label and the input field column uses the remaining width. Each row in turn uses the optimal height (i.e. is as high as necessary to show a single-lined input field).

Even though I haven’t seen a real world use case, this very approach would also work when expanding horizontally.

Computing the Preferred Size for a ScrolledComposite

There is nothing more saddening than to see an application that was designed with a single screen resolution or font size or color scheme (or all of them) in mind. To avoid this, the contact details form uses an adaptive strategy to compute its initial size.

As the content consists of repeating items (labeled input fields here), the size of a single item is taken as measuring unit. The number of items here is a figure gained from evidence but could be the (limited) number of rows obtained from a data source in other cases.

The formula itself is simple:

numberOfItems = 10
initialHeight = numberOfItems * ( itemHeight + spacing )

A further refinement would be to check the resulting height against the screen size and reduce it if necessary.

The resulting layout scales well across different platforms, screen resolutions and font settings. If this caught your interest, you may also want to read Responsive UIs with Eclipse and SWT.

Vertical and Horizontal ScrollBar

To get hold of the scrollbars use getVerticalBar() and getHorizontalBar() respectively. As seen in the snippets, the V_SCROLL and H_SCROLL style flags need to be specified in order to have vertical and/or horizontal scrollbars created. If the respective style flag is omitted, no scrollbar is created and getVerticalBar() or getHorizontalBar() will return null.

Existing scrollbars however can be shown or hidden, enabled or disabled any time. By default the ScrolledComposite shows scrollbars only when necessary but with setAlwaysShowScrollBars() this behavior can be changed to always show scrollbars. Therefore, you would usually want to have both scrollbars created and let the ScrolledComposite decide when to show or hide individual bars.

In general, be aware that scrollbars are managed by the ScrolledComposite. Hence it is safe to query their state, but manipulating the properties will most likely interfere with the ScrolledComposite’s view of things.

To change the position of scrollbars in order to bring certain parts of the content into view, use the designated methods discussed below.

The only exception of the above said may be the enabled state of scrollbars. If this is truly desired, it should be safe to call setEnabled().

Scrolling into View

The ScrolledComposite has several methods to change the scrollbar position. The most basic is setOrigin(). It scrolls the content control so that the specified point in the content is in the top left corner. The desired position can be given as separate x and y coordinates or as a Point. And consequently there is a getOrigin() method that returns the point that currently appears in the top left corner.

To spare clients some coordinate mapping, there is showControl() which builds on setOrigin() and scrolls the content so that the given control is visible.

And if the focused control should always be visible, the ScrolledComposite can be advised with setShowFocusedControl() to automatically scroll the focused control into view.

Concluding SWT ScrolledComposite

Indeed, the ScrolledComposite isn’t the most intuitive widget in the SWT collection and I hope that the recipes presented here will help to get along with it better. The use cases discussed here are those that I came across mostly so far. However, I would be curious to learn further uses and if you would like to share yours please leave a comment.

And last but not least I would like to point out that all concepts and code shown here not only apply to SWT but equally well run in a browser with Eclipse RAP. You can even use this RAP online demo to change various flags and properties and see their effect immediately.

Reference: SWT ScrolledComposite Explained from our JCG partner Rudiger Herrmann at the Code Affine blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button