Comments
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Cloud Expo on Google News


2008 West
DIAMOND SPONSOR:
Data Direct
SOA, WOA and Cloud Computing: The New Frontier for Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
GOLD SPONSORS:
Appsense
User Environment Management – The Third Layer of the Desktop
Cordys
Cloud Computing for Business Agility
EMC
CMIS: A Multi-Vendor Proposal for a Service-Based Content Management Interoperability Standard
Freedom OSS
Practical SOA” Max Yankelevich
Intel
Architecting an Enterprise Service Router (ESR) – A Cost-Effective Way to Scale SOA Across the Enterprise
Sensedia
Return on Assests: Bringing Visibility to your SOA Strategy
Symantec
Managing Hybrid Endpoint Environments
VMWare
Game-Changing Technology for Enterprise Clouds and Applications
Click For 2008 West
Event Webcasts

2008 West
PLATINUM SPONSORS:
Appcelerator
Get ‘Rich’ Quick: Rapid Prototyping for RIA with ZERO Server Code
Keynote Systems
Designing for and Managing Performance in the New Frontier of Rich Internet Applications
GOLD SPONSORS:
ICEsoft
How Can AJAX Improve Homeland Security?
Isomorphic
Beyond Widgets: What a RIA Platform Should Offer
Oracle
REAs: Rich Enterprise Applications
Click For 2008 Event Webcasts
SYS-CON.TV
Top 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.

    In order to post a comment you need to be registered and logged in.

    Register | Sign-in

    Reader Feedback: Page 1 of 1

    Great, then you try to view the code to use the implementation and it's a broken link. Fantastic.


    Your Feedback
    Ben Glancy wrote: Great, then you try to view the code to use the implementation and it's a broken link. Fantastic.
    Enterprise Open Source Magazine Latest Stories . . .
    With Cloud Expo 2012 New York (10th Cloud Expo) just four months away, what better time to start introducing you in greater detail to the distinguished individuals in our incredible Speaker Faculty for the technical and strategy sessions at the conference... We have technical and st...
    AMD said late Tuesday that its chief sales officer Emilio Ghilardi had left the company and that CEO and president Rory Read is going to do his job while a replacement is sought. AMD didn’t say why Ghilardi left but it’s assumed Read wants his own people. Read is relatively new to th...
    During the lifespan of M3 (Monitis Monitor Manager) there has always been something lacking – timers. M3 execution procedure was outlined in this previous article. The execution mentioned in the latter was a one-time-execution, whereas server monitoring requires periodic invocati...
    Red Hat is putting its bought-in Gluster scale-out NAS storage technology, acquired in October, on the Amazon cloud. It’s styled Red Hat Virtual Storage Appliance for Amazon Web Services and other clouds are supposed to follow in short order.
    A new episode of the screencast series is now available at the OpenNebula YouTube Channel. This screencast demonstrates the new easily-customizable self-service portal for cloud consumers. Its aim is to offer a simplified access to shared infrastructure for non-IT end users. The scree...
    C12G Labs has just announced an update release of OpenNebulaPro, the enterprise edition of the OpenNebula Toolkit. OpenNebula 3.2, released two weeks ago, brings important benefits to cloud providers with a new easily-customizable self-service portal for cloud consumers, and builders w...
    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
    ADS BY GOOGLE