YOUR FEEDBACK
Brian Vicente wrote: Where are listing 3 and listing 4?


2008 East
DIAMOND SPONSOR:
Data Direct
Frontiers in Data Access: The Coming Wave in Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
Intel
Virtualization – Path to Predictive Enterprise
Green Hills
IT Security in a Hostile World
JBoss / freedom oss
Practical SOA Approach
GOLD SPONSORS:
Software AG
The Art & Science of SOA: How Governance Enables Adoption
PlateSpin
Effective Planning for Virtual Infrastructure Growth
Fujitsu
Automated Business Process Discovery & Virtualization Service
Ceedo
Workspace Virtualization
Click For 2007 West
Event Webcasts

2008 East
PLATINUM SPONSORS:
Appcelerator
Think Fast: Accelerate AJAX Development with Appcelerator
GOLD SPONSORS:
DreamFace Interactive
The Ultimate Framework for Creating Personalized Web 2.0 Mashups
ICEsoft
AJAX and Social Computing for the Enterprise
Kaazing
Enterprise Comet: Real–Time, Real–Time, or Real–Time Web 2.0?
Nexaweb
Now Playing: Desktop Apps in the Browser!
Sun
jMaki as an AJAX Mashup Framework
POWER PANELS:
The Business Value
of RIAs
What Lies Beyond AJAX?
KEYNOTES:
Douglas Crockford
Can We Fix the Web?
Anthony Franco
2008: The Year of the RIA
Click For 2007 Event Webcasts
SYS-CON.TV
TOP THREE LINKS YOU MUST CLICK ON


Scrolling on Demand
A scrollable toolbar component

Modern GUI programs enable you to easily access status information and functionalities through various menus, toolbars, and information panels. However, as a program becomes more complex or when users have the possibility of configuring and extending these components, they tend to get overfilled. This leads to scrambled or even truncated components.

This article introduces a new container component called ScrollableBar that can be used as a wrapper for any Swing component. As long as there is enough space to lay out the contained component, ScrollableBar is completely transparent. As soon as the available space gets too small, ScrollableBar will fade in two small arrow buttons on the left and the right side (or on the top and the bottom if in vertical mode) that can be used to scroll the underlying component, thus avoiding the above mentioned problems.

ScrollableBar is a lightweight container derived from JComponent that uses the standard Swing classes JViewport and JButton to achieve its functionality. It fills a gap in the set of the standard Swing components and offers the possibility of creating more robust and intuitive user interfaces.

Introduction
Every professional application includes a fancy graphical user interface and with Swing, the standard widget set of Java, it's quite easy to create such applications. However, the design and implementation of a robust and user-friendly GUI is not a trivial task. One common problem is that the programmer has no knowledge about the client's desktop size. This may vary today from the standard notebook and flat panel resolution of 1024x768 to 1900x1200 for high-end displays. Even worse, Java applications can run on many other devices such as mobile phones, which have an even more restricted resolution.

Another challenge arises from the extensibility of applications. While the possibility of extending an application with various plugins may be a nice feature for the user, the fact that these plugins will populate the menus and toolbars in an unpredictable way presents new problems for the programmer.

One way to solve these problems is to limit the GUI components to a certain minimal size; however, this may impose unnecessary restrictions on the user. (Think, for example, of somebody who by default works with an application that needs a resolution of at least 1024x768 but who occasionally gives demo talks with a beamer that only supports an 800x600 resolution.) Furthermore, if an application with a graphical user interface pretends to be resizable by displaying a resizable frame, the user expects he will be able to resize it based on his needs, not the programmer's.

The second possibility is to do nothing and wait and see what happens. This is how most GUI applications are written today. Just compare Figure 1 with Figure 2 and see how parts of the status bars and toolbars are cut off if the window is shrunk beyond its optimal size. In the best case, the user could just reenlarge the application if this happens. In the worst case, if he or she is working on a device with a restricted resolution, it may be impossible to access the desired functionality. In any case such an application looks highly unprofessional.

Scrollable Menus and Toolbars
The solution for all of the above mentioned problems would be scrollable menus and toolbars. However, Swing, as many other widget sets, does not offer this type of component. Using the standard JScrollPane component as a container for menus and toolbars is not an option here as JScrollPane is too heavyweight; its scrollbars are simply too big. However, there is another Swing component that can serve as a template: since version 1.4, the JTabbedPane class offers the possibility of scrolling its panes instead of wrapping them on several lines if they don't fit on a single line. As shown in Figure 3, arrow buttons for moving the tabs have been added at the upper right part.

We now want to achieve the same behavior with menus, toolbars, and other status bars and information panels. To get a visual impression of how the modified components will look, compare Figures 1 and 4. They both show a screenshot of the Stylepad demo application shipping with every JDK, which has been extended by a vertical toolbar and a useful status bar (see Figure 2). While the menu, status bar, and toolbars are truncated and partially inaccessible in Figure 1, they can be scrolled and are fully functional in Figure 4 by using the arrow buttons that have been faded in.

The Implementation
I'll now describe how to implement a class called ScrollableBar, which can serve as a container for a java.awt.Container object or any other object derived from it. Most of the time ScrollableBar objects are completely transparent. If the place required by the wrapped component for layout becomes too small, the ScrollableBar object will fade in two arrow buttons at the left and right sides of the component (or on the top and the bottom if in vertical mode), which can be used to scroll the wrapped component. As soon as there is enough place for the layout of the enclosed component again, these arrow buttons will immediately disappear.

The Swing Architecture
For a better understanding of the ScrollableBar implementation, it's helpful to revisit the architecture of Swing. The Swing library is a modern widget set based on the Model-View-Controller (MVC) pattern. While the classical MVC pattern consists of three independent parts - model, view, and controller - Swing uses a simplified version of this pattern in which the view and the controller parts are combined in a so-called Delegate (see Figures 5 and 6).

As an example, Figure 6 shows how this Model-Delegate pattern applies to the JButton class. In Swing, all visible components are descendants of the JComponent class. They usually capsule a component-specific model with a delegate object, which is a descendant of the ComponentUI. These delegates are called user interface (UI) classes in Swing. They are look-and-feel specific, i.e., they're used to implement the different look and feel-dependent properties of a component, but they can also be used for other kinds of customization, for example, localization.

One of the main responsibilities of the UI delegate is to paint the component it's tied to. In contrast to the AWT library, in Swing it's not the paint() method of every component that does the work of painting itself. Instead, the component's paint() method just calls the paint() method of its delegate with a reference to itself.

The ScrollableBar Class
Figure 7 shows the class diagram of the ScrollableBar class. As already mentioned, it's derived from JComponent. It also implements the SwingConstants interface in order to easily access the constants HORIZONTAL and VERTICAL, which are defined there.

ScrollableBar has four properties. The two Boolean properties "horizontal" and "small" store the orientation of the component and the size of the arrows on the scroll buttons. The integer property "inc" stores the amount of pixels by which the enclosed component will be scrolled if one of the arrow buttons is being pressed. Smaller values lead to a smoother but slower scrolling. Finally, the wrapped component is stored in the "comp" property. While "horizontal" is a read-only property that can be set only in the constructor, the other three properties are read/write bound properties as described in the JavaBeans specification.

The following code shows the two-argument constructor of the ScrollableBar class:

public ScrollableBar(Component comp, int orientation) {
this.comp = comp;
if (orientation == HORIZONTAL) {
   horizontal = true;
}
else {
   horizontal = false;
}
small = true;
// Arrow size on scroll button.
   inc = 4;
// Scroll width in pixels.
   updateUI();
}

Notice the call to updateUI() in the last line of the constructor. As can be seen in the following code, updateUI() calls the static method getUI() from the class UIManager to query the right UI delegate and associates it with the current ScrollableBar object.

public String getUIClassID() {
   return "ScrollableBarUI";
}

public void updateUI() {
   setUI(UIManager.getUI(this));
   invalidate();
}

UIManager.getUI() calls getUIClassID() to get the key that's used to query the actual UI delegate from a look and feel-dependent internal table. Usually the association of the standard Swing components with the appropriate UI classes is done by the different look and feels while they are initialized. However, as we are writing a new component, we have to establish this link manually, as shown below:

static {
   UIManager.put("ScrollableBarUI",
    "com.languageExplorer.widgets. - ScrollableBarUI");
}

Notice that linking a component to its UI delegate in this way results in the same UI class being used independent of the actual look and feel.

Besides the getter and setter methods for the corresponding properties, there's no more functionality in the ScrollableBar class. All the painting and user interaction is handled by the UI delegate ScrollableBarUI.

The ScrollableBarUI Class
One of the most important methods of the UI classes is installUI(), which is called every time a component is associated with its UI delegate (see Listing 1). This gives the UI delegate a chance to properly initialize itself and the component it's responsible for.

In our case, the UI delegate queries and stores the component's properties along with a reference to the component as private instance variables. Further on, it creates two arrow buttons and an object of type JViewport, which is used to wrap the scrollable component.

Based on the orientation of the associated ScrollableBar object, the newly created elements are then being added to it by using a vertical or horizontal box layout. Notice that the scroll buttons are initially set to be invisible. Finally, the UI object registers itself as a property change listener on the associated component, as a change listener on the viewport, and as a mouse listener on the arrow buttons.

The UI delegate is informed about every size change of the ScrollableBar object and the wrapped component by receiving a ChangeEvent from the viewport object. Depending on the new sizes, it can change the visibility state of the arrow buttons and re-lay out the component. Property changes in the ScrollableBar object are signaled to the UI delegate by a PropertyChangeEvent. Based on these events, it can update the internally cached values of these properties.

Finally, the events resulting from the user interactions on the scroll buttons are handled by the different mouse listener methods. The UI delegate keeps a private boolean instance variable pressed that's set to true if a button was pressed, and reset to false as soon as the button is released or the mouse pointer leaves the button. As can be seen in Listing 2, pressing one of the buttons also starts a new thread that scrolls the underlying component by "inc" pixels in the corresponding direction and then sleeps for a short time. These two actions are subsequently repeated in the thread as long as the value of the instance variable "pressed" is true, while the amount of sleeping time is reduced in every iteration step. This results in a continuously accelerating scrolling speed, as long as the user keeps on pressing the arrow button.

It should be noted that we don't need any special paint method for the ScrollableBarUI class, because painting occurs naturally from the standard Swing button and viewport components that we used.

After we've discussed the main parts of the implementation, it should be evident why the advantages of dividing the functionality of the ScrollableBar class into two classes outweigh the coding overhead. First, we cleanly separated the properties of the component from the way that it displays and interacts with the user. Second, it's easy now to define a new UI delegate that renders the component in a different way or to derive a new UI delegate from the existing one that slightly adopts appearance or user interaction properties to a specific look and feel.

Using the ScrollableBar Class
Using the ScrollableBar class is easy and straightforward. In fact we can wrap every arbitrary Swing component inside a ScrollableBar object by passing it as an argument to the constructor when creating the object. For the example application shown in Figure 4 it was necessary to only change a single line:

JToolBar toolbar = new JToolBar();
...
panel.add("North", toolbar);
from the original Stylepad application to:

JToolBar toolbar = new JToolBar();
...
panel.add("North", new ScrollableBar(toolbar));

in order to make the horizontal toolbar scrollable if the space becomes too small to render it as a whole.

In general, the ScrollableBar class is recommended for wide and not very high components in horizontal mode and narrow and high components in vertical mode. If used for other components, the scroll buttons would get too big and take up too much space to be really useful.

Menu Bars in JFrame Objects
As shown in the last section, it's very easy to use the ScrollableBar class in your own applications. Even upgrading existing applications isn't very hard. The only problem that may arise is when a ScrollableBar should be used as a wrapper for a menu bar that will be added directly to a JFrame object. (Notice that in our example application, the menu bar has been added to a JPanel object before the whole panel has been added to the JFrame object.)

The problem arises because JFrame provides a specialized setJMenuBar() method for adding menu bars and this method expects an argument of Type JMenuBar. At first glance, we could just use one of the generic add() methods defined in JFrame's ancestor classes instead. However, if we take a closer look, we'll see that the problem is a bit more complex.

First, in the case of JFrame, children are not being added to the component directly, but to the so-called "root pane", which is a special child component of every JFrame. However, we also can't add the menu bar directly to the root pane, because the root pane also has a special method called setJMenuBar() that expects a JMenuBar object as an argument. Using this method to add menu bars is essential, because only then will the RootLayout layout manager used by the JRootPane class honor the presence of the menu bar. RootLayout, which is a protected inner class of JRootPane, uses the protected JRootPane property "menuBar" that has been set by JRootPane.setJMenuBar() for layout calculations.

To cut a long story short, we have to create a new SMJFrame class (which stands for Scrollable Menu JFrame) that overrides the createRootPane() method to return a new, customized root pane class. For this purpose we just derive an anonymous class from JRootPane that overrides the two methods setJMenuBar() and createRootLayout().

setJMenuBar(), the first of these two methods, wraps the menu bar into our ScrollableBar class before storing it as a protected instance variable and adding it to the layered pane that's a part of the root pane.

The second method, createRootLayout(), returns an anonymous class that inherits from the JRootPane protected inner class RootLayout. It overrides the layout methods in that class in such a way that they use the ScrollableBar instance variable for layout calculations instead of using the bare menu bar, as it was done by the original version of the methods.

These modifications finally give the desired result. A call to setJMenuBar() on a SMJFrame object will be forwarded to the customized root pane. There the menu bar will be wrapped into a ScrollableBar object before it will actually be added to the frame. Because the customized root pane uses a customized layout manager, it will handle the scrollable menu bar in the same way in which a JFrame object handles an ordinary menu bar. With respect to all other concerns, SMJFrame behaves exactly like its ancestor JFrame.

Limitations
The only limitation for the use of the ScrollableBar class so far is that it cannot handle floating tool bars. This is because JToolBar objects have to be laid out in a container whose layout manager is of type BorderLayout if they want to be floatable. In addition, no other children can be added to any of the other four "sides." This is obviously not the case if the toolbar is wrapped inside a ScrollableBar object.

Fixing this problem would require extensive changes in BasicToolBarUI, the UI delegate of JToolBar. Unfortunately, since not all the methods that need to be customized are declared public or protected, a complete rewrite of the delegate would be necessary.

Conclusion
This article presented quite a small and simple yet powerful container class, which fills a gap in the set of standard Swing components. Using it involves no overhead at development time or at runtime but yields a lot of benefits. The most important ones are better usability and user friendliness, and more robust and intuitive GUI applications.

The source code presented in this article is available at www.progdoc.org/ScrollableBar.

References

  • Eckstein, R., Loy, M., and Wood, D. (1998). Java Swing. O'Reilly.
  • Gamma, E., Helm R., Johnson, R., and Vlissides, J. (1995). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley.
  • Hamilton, G. (Ed.) JavaBeans Sun Microsystems, Version 1.01-A, August 1997: java.sun.com/beans
  • Simonis, V. "International Swinging: Making Swing Components Locale-Sensitive." C/C++ Users Journal, Java Supplement, August 2002: www.cuj.com/java/jsup2008/
  • Simonis, V. Prog DOC - A Program Documentation System: www.progdoc.org
  • Zukowski, J. "Magic with Merlin: Scrolling tabbed panes": www-106.ibm.com/developerworks/java/library/j-mer0905/
  • Zukowski, J. and Stanchfield, S. "Fundamentals of JFC/Swing, Part II", MageLang Institute: developer.java.sun.comdeveloper/onlineTraining/GUI/Swing2
  • About Volker Simonis
    Volker H. Simonis is an independent software developer and consultant. He is an expert in the field of software design and documentation, i18n, generic programming, C++, and Java with about eight years of working experience in these areas. Volker received a masters degree in computer science from the University of Tübingen (Germany) and is currently finishing his PhD thesis.

    YOUR FEEDBACK
    Ben Glancy wrote: Great, then you try to view the code to use the implementation and it's a broken link. Fantastic.
    LATEST JAVA STORIES & POSTS
    Unit testing is hard. There I said it. Although I have been developing software for the past 18 years I still find that putting my applications through their paces via unit testing is difficult. I have learned the lesson (I'm sure like many of you) the hard way. Unit testing is p...
    Continuent has announced support and enhancements to MySQL Server 5.1.30 GA release, the 5.1 production version of the open source database. MySQL 5.1.30 is recommended for use on production systems by the MySQL build team at Sun Microsystems. Continuent Tungsten provides advance...
    As a software journalist, there are times when certain vendors will shut the door on reporting opportunities that might represent too much of an "inside view" of their technology or their organization. I've been to more developer events than I can remember where I've been handed ...
    Active Endpoints has announced the general availability of ActiveVOS 6.0.2, in response to ever increasing demands for improved process performance and efficiencies. ActiveVOS is an all-in-one, 100% standards-based orchestration and business process management system (BPM) that p...
    Just because the web has been open so far doesn't mean that it will stay that way. Flash and Silverlight, arguably the two market-leading technology toolkits for rich media applications are not open. Make no mistake - Microsoft and Adobe aim to have their proprietary plug-ins, ak...
    Doing network I/O on the user interface (UI) thread is bad. Most developers know that and can tell you why; unfortunately, it’s still done. At this year's JavaOne, one of the keynote JavaFX demos bombed because the network was slow, something that would be forgivable had the en...
    SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
    SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
    Click to Add our RSS Feeds to the Service of Your Choice:
    Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
    myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
    Publish Your Article! Please send it to editorial(at)sys-con.com!

    Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


    SYS-CON FEATURED WHITEPAPERS

    SPONSORED BY INFRAGISTICS
    In every field of design one of the first things students do is learn from the work of others. They ...
    There are many forces that influence technological evolution. After a decade of building enterprise ...
    2008 is going to be an important year for Rich Internet Applications. Most organizations are deliver...
    The OpenAjax Alliance is developing an Ajax industry wishlist for future browsers, using a dedicated...
    Infragistics announced the availability of two Community Technology Preview (CTP) User Interface (UI...
    The YUI development team has released version 2.5.2; you can download the new release from SourceFor...
    ADS BY GOOGLE