Tuesday, November 15, 2011

Creating a Custom Swing Component

I always return to my blog when I'm stuck, and I'm stuck right now.

I want to create a custom Swing component. Specifically, I want something like a JProgressBar, with the following changes:

  1. In place of a flat Foreground color, I want a rainbow spectrum, showing only the red range for low Values, and the whole spectrum for values close to the Maximum value;
  2. Instead of a rectangular box, I want the progress "bar" to take the shape of a normal, or Gaussian, distribution curve;
  3. I want progress to be displayed by the area under the curve, rather than by a simple linear scale along the x axis.

It's not that there isn't stuff out there. I have five tabs open in my browser, specifically addressing the creation of custom components in Swing, as well as the source code for the JProgressBar. It is that, like everything to do with Java, it is bloody difficult to read.

I shall begin from the horse's mouth as it were, with an article on the Java.net website entitled: How to Write a Custom Swing Component. It begins by defining the "building blocks" of Swing components as:

  • The component class itself, which provides an API for creating, changing, and querying the component basic state.
  • The model interface and the model default implementation(s) that handle the component business logic and change notifications.
  • The UI delegate that handles component layout, event handling (mouse and keyboard), and painting.

I understand the first four words of that lot. I hate it when documents, especially formal ones, use abbreviations without definitions, but a Google search on API produces a first page full of formal Sun/Oracle documents, which do that, even in the title.

According to an archived (by which I mean so old or unimportant that Oracle has not woven itself into the URL) glossary, API is defined as:

Application Programming Interface. The specification of how a programmer writing an application accesses the behavior and state of classes and objects.

So if you insert the full definition into the first bullet, you get:

  • The component class itself, which provides a specification of how a programmer writing an application accesses the behavior and state of classes and objects for creating, changing, and querying the component basic state.

And that is gibberish, like so much of the material used to describe Java, and the closer you get to "the horse" often the more confusing it gets. To be fair, if you insert the words behind the acronym, it looks a little better:

  • The component class itself, which provides an Application Programming Interface for creating, changing, and querying the component basic state.

But then it starts to overlap with the second "building block", which begins:

The model interface ...

When I first read that, I wasn't sure whether it said model or modal. Either way it is not clear how the model interface differs from the Application Programming Interface.

The third "building block" opens with:

The UI delegate ...

I used the same glossary to look up UI, and it wasn't even in there. A Google search on UI brings up a slew of pages on GUI, and the weight of evidence suggests "User Interface". So now we have Application Programming Interface, model interface, and a User Interface, each purportedly in their own "building block".

Are we really dealing with distinct building "building blocks" here, or a "blob" of amorphous building material with fuzzily defined functionality zones?

The next title in the article, after Basic Building Blocks, is The Component Class: UI Delegate Plumbing, which looks to me very like a composite of building blocks 1 and 3. The third heading is The Model Interface, so presumably it refers to the second building block. It includes some code, with two class declarations, and it opens with:

This (sic) is ... the most important class for a custom component.

The article continues, on and on, in a similarly confusing fashion, so I thought I'd cut to the chase and have a look at the source code and see if I could make it work. The code for the main class JFlexiSlider.java, begins with:

package org.jvnet.flamingo.slider;

import javax.swing.*;

import org.jvnet.flamingo.slider.FlexiRangeModel.Range;
import org.jvnet.flamingo.slider.ui.BasicFlexiSliderUI;
import org.jvnet.flamingo.slider.ui.FlexiSliderUI;

Three questions arise from this. Is the web address given for the imported classes in the public domain? Are the classes listed still there? And if so, is Java smart enough to navigate through the Internet to find them? When I tried to compile the class. The first of 18 errors was:

package org.jvnet.flamingo.slider.FlexiRangeModel does not exist

Out of curiosity I typed jvnet.org into my browser and it came up blank. I ran a whois on jvnet.org, and this confirmed that the domain name is registered, and to Oracle. So I guess that when this code was written, all the package and import information was meaningful, but now it certainly isn't. And to cut a long story short, the effort of addressing each error in turn to make the code run outweighed any possible benefit, so I gave up.

My next port of call was to the source code of the existing JProgressBar. One of eleven imported classes was:

import javax.swing.plaf.ProgressBarUI;

So I checked out the source code for this, which was:

public abstract class ProgressBarUI extends ComponentUI {
}

To do a proper job I should have downloaded the source code for ComponentUI as well, but to honest, the whole thing was rendered virtually unreadable by all the comments, so I reached another boredom threshold.

I then went to a much more readable article entitled Creating a custom component in Swing by a Danish gentleman called Christian Petersen. As my Rasch Itembank Project is inspired by the Danish Mathematician, Georg Rasch, I was happy to be reading something by one of his countrymen.

There were no remote or unreachable packages in the code given with this article (in fact there were no packages at all), and the code compiled and ran perfectly first time. Inspired by this success, and the simplicity of his approach, I went right back to basics, to a lesson in The Java Tutorial entitled Compiling and Running Swing Programs. This lesson gives a link to source code for a "program" called HelloWorldSwing.

HelloWorldSwing essentially displays a Swing component called JLabel, in another component called JFrame. I took this code and replaced the JLabel with the class for my rainbow colored Gaussian curve as follows:

import javax.swing.*;
public class HelloWorldSwing {
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add the ubiquitous "Hello World" label.
NormJ2 label2 = new NormJ2();
frame.getContentPane().add(label2);
//Display the window.
frame.setSize(520, 300);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}

}

And it came up as shown below:

I've left all the comments and the HelloWorldSwing heading (and even the component name: label2) to emphasize that creating a custom swing component is really as simple as that. You don't need packages, collections of remote and difficult to find "ui" classes. You just insert one class, compiled with Swing components, into another.

As components go, mine is currently somewhat limited. It looks pretty (though I say it myself), but it does nothing else. The purpose of all the guff at the head of this post is to bring components alive, but there has to be a simpler, more commonsense, way to do it.

3 comments:

geetha said...

Ecorptrainings.com provides JAVA SWING in hyderabad with best faculties on real time projects. We give the best online trainingamong the JAVA SWING in Hyderabad. Classroom Training in Hyderabad India

elizabeth thomas said...

"Very Nice post..well written..

Here i would like to give a plug to my website..which your reader might find intresting...link is as below

.Agile Certification"

Andrew Rayy said...

To stop making avoidable mistakes in project management one can also try attending good PMP classes conducted by any of the PMI registered REP's for gainig expertise best processes of project management. Any good PMP prep course will provide students with lots of actionable insights in project management along with preparing them for PMP certification.