5 things you didn't know about ... enhancing Swing

Yes, you can build beautiful user interfaces with Swing!

Swing is an older toolkit, developed long before the advent of beautiful user interfaces, and it's missing some of the components you might need for building rich UIs. Fortunately, open source projects like Substance, SwingX, and the Java™ Look-and-Feel Graphics Repository make up the difference. Author Steven Haines shows you how to painlessly add tree tables, syntax highlighting, and more to your Swing UIs.

Share:

Steven Haines, Founder and CEO, GeekCap Inc.

Steven Haines is a technical architect at ioko and the founder of GeekCap Inc. He has written three books on Java programming and performance analysis, as well as several hundred articles and a dozen white papers. Steven has also spoken at industry conferences such as JBoss World and STPCon, and he previously taught Java programming at the University of California, Irvine, and Learning Tree University. He resides near Orlando, Florida.



19 October 2010

Also available in Chinese Russian Japanese

About this series

So you think you know about Java programming? The fact is, most developers scratch the surface of the Java platform, learning just enough to get the job done. In this ongoing series, Java technology sleuths dig beneath the core functionality of the Java platform, turning up tips and tricks that could help you solve even your stickiest programming challenges.

User interface design and development have changed a lot in recent years, and some would say the Java platform hasn't really kept up. Swing, released in 1997, is still the standard toolkit for building user interfaces into the JVM. On the upside, it's a familiar standard and easy to work with; on the downside, it's missing some features that have become common to rich UI design.

In this edition of the 5 things series, I introduce four free, open source components that you can use to modernize your Swing GUIs, then round out the discussion with something you might not know about Swing threading.

1. Substance

Develop skills on this topic

This content is part of a progressive knowledge path for advancing your skills. See Become a Java developer

Integrating Java applications with a native operating system can be tricky, mainly because Swing paints its own components manually. One workaround for this is the Java look and feel, which allows the JVM to delegate the appearance of an application's components to the native look and feel. Thus, when using the Windows® look and feel, Swing applications will look like Windows applications; when using the Mac look and feel, they'll look like Mac applications.

Swing ships with the standard, native look and feel as well as its own platform-independent look and feel, called Metal. Alternately, Substance is an open source project, developed by Kirill Grouchnikov, that provides more than a dozen skinnable look and feels. To try it out, download Substance from Java.net then:

  1. Add the substance.jar file to your CLASSPATH.
  2. Add the following system property to the startup of one of your applications:
    -Dswing.defaultlaf=org.jvnet.substance.skin.lookandfeelname
  3. In place of the lookandfeelname variable in Step 2, try any of the following values:
         SubstanceAutumnLookAndFeel
         SubstanceBusinessBlackSteelLookAndFeel
         SubstanceBusinessBlueSteelLookAndFeel
         SubstanceBusinessLookAndFeel
         SubstanceChallengerDeepLookAndFeel
         SubstanceCremeCoffeeLookAndFeel
         SubstanceCremeLookAndFeel
         SubstanceDustCoffeeLookAndFeel
         SubstanceDustLookAndFeel
         SubstanceEmeraldDuskLookAndFeel
         SubstanceMagmaLookAndFeel
         SubstanceMistAquaLookAndFeel
         SubstanceMistSilverLookAndFeel
         SubstanceModerateLookAndFeel
         SubstanceNebulaBrickWallLookAndFeel
         SubstanceNebulaLookAndFeel
         SubstanceOfficeBlue2007LookAndFeel
         SubstanceOfficeSilver2007LookAndFeel
         SubstanceRavenGraphiteGlassLookAndFeel
         SubstanceRavenGraphiteLookAndFeel
         SubstanceRavenLookAndFeel
         SubstanceSaharaLookAndFeel
         SubstanceTwilightLookAndFeel

Figure 1 shows a Java application with the default Metal look and feel, while Figure 2 shows it with the Substance Raven look and feel:

Figure 1. The Java platform's Metal look and feel
A screen capture of a GUI with the Java platform's default Metal look and feel.
Figure 2. Substance's Raven look and feel
A screen capture of the same GUI with the Substance Raven look and feel.

2. SwingX

The Swing framework includes most of the standard controls that you need, including trees, tables, lists, and so forth. But it's missing some of the more modern controls, like tree tables. The SwingX project, which is part of SwingLabs, provides a rich component set that includes the following:

  • Sorting, filtering, and highlighting for tables, trees, and lists
  • Find/search
  • Auto-completion
  • Login/authentication framework
  • TreeTable component
  • Collapsible panel component
  • Date picker component
  • Tip-of-the-Day component

To try it out, download the SwingX JAR from SwingLabs and add it to your CLASSPATH, or just add the following dependency to your Maven POM file:

    <dependency>
      <groupId>org.swinglabs</groupId>
      <artifactId>swingx</artifactId>
      <version>1.6</version>
    </dependency>

The tree table in Figure 3 is one example of a SwingX component:

Figure 3. SwingX TreeTable component
A GUI screen capture showing the SwingX TreeTable component.

Building a SwingX TreeTable

Building a tree table is very straightforward using the SwingX JXTreeTable control. Just think of each row in your table as potentially having column data, as well as optionally having child nodes. SwingX provides a model class that can be extended to provide this functionality, called org.jdesktop.swingx.treetable.AbstractTreeTableModel. Listing 1 shows an example of a tree-table model implementation:

Listing 1. MyTreeTableModel.java
package com.geekcap.swingx.treetable;

import java.util.ArrayList;
import java.util.List;

import org.jdesktop.swingx.treetable.AbstractTreeTableModel;

public class MyTreeTableModel extends AbstractTreeTableModel 
{
	private MyTreeNode myroot;
	
	public MyTreeTableModel()
	{
		myroot = new MyTreeNode( "root", "Root of the tree" );
		
		myroot.getChildren().add( new MyTreeNode( "Empty Child 1", 
		  "This is an empty child" ) );
		
		MyTreeNode subtree = new MyTreeNode( "Sub Tree", 
		  "This is a subtree (it has children)" );
		subtree.getChildren().add( new MyTreeNode( "EmptyChild 1, 1", 
		  "This is an empty child of a subtree" ) );
		subtree.getChildren().add( new MyTreeNode( "EmptyChild 1, 2", 
		  "This is an empty child of a subtree" ) );
		myroot.getChildren().add( subtree );
		
		myroot.getChildren().add( new MyTreeNode( "Empty Child 2", 
		  "This is an empty child" ) );
		
	}

	@Override
	public int getColumnCount() 
	{
		return 3;
	}
	
	@Override
	public String getColumnName( int column )
	{
		switch( column )
		{
		case 0: return "Name";
		case 1: return "Description";
		case 2: return "Number Of Children";
		default: return "Unknown";
		}
	}

	@Override
	public Object getValueAt( Object node, int column ) 
	{
		System.out.println( "getValueAt: " + node + ", " + column );
		MyTreeNode treenode = ( MyTreeNode )node;
		switch( column )
		{
		case 0: return treenode.getName();
		case 1: return treenode.getDescription();
		case 2: return treenode.getChildren().size();
		default: return "Unknown";
		}
	}

	@Override
	public Object getChild( Object node, int index ) 
	{
		MyTreeNode treenode = ( MyTreeNode )node;
		return treenode.getChildren().get( index );
	}

	@Override
	public int getChildCount( Object parent ) 
	{
		MyTreeNode treenode = ( MyTreeNode )parent;
		return treenode.getChildren().size();
	}

	@Override
	public int getIndexOfChild( Object parent, Object child ) 
	{
		MyTreeNode treenode = ( MyTreeNode )parent;
		for( int i=0; i>treenode.getChildren().size(); i++ )
		{
			if( treenode.getChildren().get( i ) == child )
			{
				return i;
			}
		}

		return 0;
	}
	
	 public boolean isLeaf( Object node )
	 {
		 MyTreeNode treenode = ( MyTreeNode )node;
		 if( treenode.getChildren().size() > 0 )
		 {
			 return false;
		 }
		 return true;
	 }
	 
	 @Override
	 public Object getRoot()
	 {
		 return myroot;
	 }
}

Listing 2 shows a custom tree node:

Listing 2. MyTreeNode.java
class MyTreeNode
{
	private String name;
	private String description;
	private List<MyTreeNode> children = new ArrayList<MyTreeNode>();
	
	public MyTreeNode() 
	{
	}
	
	public MyTreeNode( String name, String description ) 
	{
		this.name = name;
		this.description = description;
	}
	
	public String getName() 
	{
		return name;
	}
	
	public void setName(String name) 
	{
		this.name = name;
	}
	
	public String getDescription() 
	{
		return description;
	}
	
	public void setDescription(String description) 
	{
		this.description = description;
	}
	
	public List<MyTreeNode> getChildren() 
	{
		return children;
	}
	
	public String toString()
	{
		return "MyTreeNode: " + name + ", " + description;
	}
}

If you want to use this tree-table model, you'll need to create an instance of it and then pass that instance to the JXTreeTable constructor, like so:

private MyTreeTableModel treeTableModel = new MyTreeTableModel();
private JXTreeTable treeTable = new JXTreeTable( treeTableModel );

Now you can add the treeTable to any Swing container, such as a JPanel or a JFrame's content pane.


3. RSyntaxTextArea

Another component that is sorely missing from Swing is a text editor with syntax highlighting capabilities. If you've written an XML document, then you know how helpful it is to be able to visually differentiate between tags, attributes, attribute values, and tag values. The developers at FifeSoft have built a set of rich components that you can use in your Swing-based Java applications, one of which is the RSyntaxTextArea component.

RSyntaxTextArea supports most programming languages out of the box, including C, C++, Perl, PHP, and the Java language, as well as HTML, JavaScript, XML, and even SQL.

Figure 4 is a screen capture of the RSyntaxTextArea component displaying an XML file:

Figure 4. RSyntaxTextArea displaying an XML file
A screen capture of the RSyntaxTextArea component displaying an XML file.

Adding syntax highlighting to Swing apps

First, download the RSyntaxTextArea JAR file from Sourceforge. If you're using Maven, you might want to install it into your local repository using a command like this one:

mvn install:install-file -DgroupId=com.fifesoft -DartifactId=rsyntaxtextarea
 -Dversion=1.0 -Dpackaging=jar -Dfile=/path/to/file

Once you've added the JAR file to your project, you can create an instance of RSyntaxTextArea in your application, add it to a RTestScrollPane if you want scrolling capabilities, and invoke the setSyntaxEditingStyle() method, passing it one of the SyntaxConstants. For example, Listing 3 creates a scrollable RSyntaxTextArea that renders text as XML:

Listing 3. Syntax highlighting in Swing
RSyntaxTextArea text = new RSyntaxTextArea();
add( new RTextScrollPane( text ) );
text.setSyntaxEditingStyle( SyntaxConstants.SYNTAX_STYLE_XML );

4. The Java Look-and-Feel Graphics Repository

One thing that Microsoft has done well is to ensure that Windows applications have a consistent look and feel. If you've been writing Java Swing applications for any length of time, you've probably come across Oracle's Java Look-and-Feel Graphics Repository. If not, you're in for a treat. The Java Look-and-Feel Graphics Repository contains a set of icons for standard application behaviors such as File->New and Edit->Copy, as well as more esoteric commands such as media controls, browser navigation functions, and programming actions for Java developers. Figure 5 shows a screen capture of icons captured on the Oracle website:

Figure 5. Java Look-And-Feel Graphics Repository icons
RSyntaxTextArea displaying an XML file

It would be good enough if the Java Look-And-Feel Graphics Repository just provided prebuilt graphics, but it also provides standard conventions that you should use when building and naming menus, toolbars, and short-cut keys. For example, a copy function should be implemented with a Ctrl-C shortcut, named Copy, and given a tooltip of Copy. When it is inside a menu, the copy function's mnemonic should be C, P, or lastly, Y.

Using Java Look-And-Feel Graphics Repository icons

To try out some of the prebuilt graphics shown in Figure 5, download the Java Look-and-Feel Graphics Repository JAR from Oracle and add it to your CLASSPATH. You'll then need to load the icons as resources from within the JAR file. The icons are in the following format:

...
toolbarButtonGraphics/general/Copy16.gif
toolbarButtonGraphics/general/Copy24.gif
toolbarButtonGraphics/general/Cut16.gif
toolbarButtonGraphics/general/Cut24.gif
toolbarButtonGraphics/general/Delete16.gif
toolbarButtonGraphics/general/Delete24.gif
...

All icons are contained in the toolbarButtonGraphics directory, partitioned into the categories shown in Figure 5. In this case, we're looking at copy, cut, and delete from the general category. The "16" and "24" references in the names reflect the size of the icon: 16x16 or 24x24. You can create an ImageIcon to the file as follows:

Class class = this.getClass();
String urlString = "/toolbarButtonGraphics/general/Cut16.gif"
URL url = class.getResource( urlString );
ImageIcon icon = new ImageIcon( url );

5. Swing threading

While launching the examples in this article, you might have encountered some strange looking runtime errors. If so, you're probably making a common mistake with threading in your Swing applications. Many Java developers do not know that Swing applications are expected to run in their own thread, and not in the main execution thread. Swing will forgive a mistake in this area, but many of the components introduced so far will not.

To help you launch your Swing application in its own thread, the Java platform provides a class called SwingUtilities that has an invokeLater() method, which you should use to start up Swing applications. Listing 4 shows the JXTreeTable being launched with the SwingUtilities.invokeLater() method:

Listing 4. SwingXExample.java
package com.geekcap.swingx;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

import org.jdesktop.swingx.JXTreeTable;

import com.geekcap.swingx.treetable.MyTreeTableModel;

public class SwingXExample extends JFrame 
{
	private JTabbedPane tabs = new JTabbedPane();
	
	private MyTreeTableModel treeTableModel = new MyTreeTableModel();
	private JXTreeTable treeTable = new JXTreeTable( treeTableModel );
	
	public SwingXExample()
	{
		super( "SwingX Examples" );
		
		// Build the tree table panel
		JPanel treeTablePanel = new JPanel( new BorderLayout() );
		treeTablePanel.add( new JScrollPane( treeTable ) );
		tabs.addTab( "JXTreeTable", treeTablePanel );
		
		// Add the tabs to the JFrame
		add( tabs );
		
		setSize( 1024, 768 );
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		setLocation( d.width / 2 - 512, d.height/2 - 384 );
		setVisible( true );
		setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	}
	
	
	public static void main( String[] args )
	{
		AppStarter starter = new AppStarter( args );
		SwingUtilities.invokeLater( starter );
	}
}

class AppStarter extends Thread
{
	private String[] args;
	
	public AppStarter( String[] args )
	{
		this.args = args;
	}
	
	public void run()
	{
		SwingXExample example = new SwingXExample();
	}
}

The constructor sets the visibility of the JFrame to true, which is not permitted by Swing when running in the application's main thread. So Listing 4 creates a separate class called AppStarter, which extends Thread and creates the SwingXExample class. The main() method creates an instance of the AppStarter class and passes it to the SwingUtilities.invokeLater() method to properly start the application. Try to get into the habit of running your Swing applications this way — not only is it correct, but some third-party components may not work if you don't.


In conclusion

Swing is a powerful library that allows you to build user interfaces on the Java platform, but it's missing some modern components that you might want to incorporate into your applications. In this article, I've offered up a handful of tips for beautifying (and modernizing) your Swing applications. Open source projects like Substance, SwingX, and the Java look and feel Graphics Repository make it easier to build rich user interfaces on the Java platform. See the Resources section to learn more about these projects and about Swing programming.

Resources

Learn

  • "5 things you didn't know about ... : Find out how much you don't know about the Java platform, in this series dedicated to turning Java technology trivia into useful programming tips.
  • "Introduction to Swing" (Michael Abernethy, developerWorks, June 2005): This first half of a two-part tutorial walks through the essential components in the Swing library.
  • "5 things you didn't know about ... Maven" (Steven Haines, developerWorks, September 2010): Maven's a preferred build tool for many Java developers, but it also offers a complete set of tools for managing the application life cycle — several of them profiled in this article.
  • "Swing threading and the event-dispatch thread" (John Zukowski, JavaWorld, August 2007): Traces Swing's single-threaded event model from Java 1.0 to its origins in the JavaBeans component model and AWT, then reveals an initialization bug in a commonly used start-up pattern and shows you how to fix it.
  • "Substance (Swing) Sightings Volume 1" (Kirill Grouchnikov, Pushing Pixels, August 2007): Select screen captures of applications running with Substance's skinnable look and feel, compiled by Substance creator Kirill Grouchnikov.
  • "Java Reference Guide: SwingX " (Steven Haines, InformIT, November 2009): Learn more about SwingX and using it to build tree tables for Java application UIs.
  • The developerWorks Java technology zone: Hundreds of articles about every aspect of Java programming.

Get products and technologies

  • Download Substance: Extend the variety of look and feels you can implement in your Swing applications.
  • Download SwingX: This SwingLabs project brings a number of rich application components to the Swing GUI toolkit.
  • Download RSyntaxTextArea: One of a set of rich components that you can use in your Swing-based Java applications, developed by FifeSoft.
  • Download the Java Look-and-Feel Graphics Repository: A collection of toolbar button graphics designed for use with the Java look and feel, developed and released by the Java Software Human Interface group at Oracle.

Discuss

  • Get involved in the My developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=551046
ArticleTitle=5 things you didn't know about ... enhancing Swing
publish-date=10192010