Extend Swing by Example - A Custom Searchable JComboBox

INTRODUCTION

When developing an application using object-oriented (OO) language such as C++ and Java, the developers frequently encounter one task, which is to extend the existing classes to provide more or customized functionalities to meet users’ requirements. From pure OO perspective, creating a subclass from an existing one (or interface), adding more functions or overriding existing functions in parent classes would achieve this goal. This task is with the big word in OO world, Inheritance. Object composition is another way of extending existing classes. But in real world things tend to be more complex, hence theory should be applied differently. That’s what developers will experience in Java world.

One of the well-know design patterns that is heavily applied in Java Swing is Model-View-Controller (MVC). To customize a Swing component, a developer must understand how MVC architect works. This article will demonstrate MVC in action by customizing JComboBox to change the default searching capability.

MVC

Java Swing is a collection of GUI components that are totally redesigned apart from Java AWT. The architecture of Swing is based on so called modified-MVC. The MVC is a design pattern originated from the pure object-oriented language small-talk. Basically it’s the separation of a GUI component’s data, appearance and function (action). In Java Swing architecture, the View and Controller of MVC are collapsed to be one GUI Manager of a component. That’s where the word ‘modified’ comes from. This concept can be well represented by one of business practice, outsourcing. That is whenever you instantiate a Swing component, you actually got a shell package. The life of the component is supported by a group of objects handling different organs of the component. The benefits of such design pattern are enormous, which is not the focus of this article.

For developers, to extend and customize the behavior of Swing component, obviously will not be as simple as extend the component itself. The developers will deal with the outsourcing parties of the component.

To allow developers communicating with the Swing component and providing extra functionalities, usually a set of interfaces are defined within the component. By implementing the interface, the developers can customize the component by plug the implementation. In this case, the inheritance of OO is more a mechanical tools than a methodology.

Encounter JComboBox

A Swing Combo Box is consisting of two parts. One part is a text field and another one is a drop down list. The text field can be set editable or non-editable.

By default, when the text field is set non-editable, the combo box can be searched by typing the first letter of the item in the list. If there are more than one item shares the same initial, the first one is always the selected one. In certain situation this default search is becoming useless. For example, when all the items in the list have the same prefix, the search becomes handicapped.

When a custom behavior is in demand, the touching of Swing MVC is inedible. Now, let’s take a look what JComboBox offers to extend the functionality.

javax.swing
Class JComboBox

java.lang.Object
+–java.awt.Component
+–java.awt.Container
+–javax.swing.Jcomponent
+–javax.swing.JComboBox

Here are some methods in of JComboBox interesting us.

public void setEditor(ComboBoxEditor anEditor)

public void setKeySelectionManager(JComboBox.KeySelectionManager aManager)

public void setModel(ComboBoxModel aModel)

public void setRenderer(ListCellRenderer aRenderer)

public void setUI(ComboBoxUI ui)

By looking at these function, we would notice that the JComboBox delegates certain functions and internal data to different objects that have certain Swing type(interface). These setters can be used to provide JComboBox with custom data and behaviors. The OO Inherence is out of picture here. The JComboBox, like almost all of other Swing components, is a composition classes. Using MVC terminology, the above methods can be categorized as:

Model: setModel() to custom the data that the combo box represent.

View: setUI() and setRenderer() to custom the combo box look and feel.

Control: setEditor(), setKeySelectionManager() to custom editing and keyboard related functions.

A good design pattern book would explain all the benefit of such architect, if you catch an empty feeling when lost the powerful OO inherence. A recommendation is Design Pattern, by Erich Gamma …, and published by Addison Wesley.

Retool the Search

This demo application has two combo boxes on it.

As stated in previous section, the searching in JComboBox is not sufficient enough for some application. In this section, we will customize the searching. Two approaches will be demonstrated:

Searching while typing

While typing, the combo box trying to locate the item the mach the typed string (not just the initial letter) from the first letter. Hit any non-character key will start a new search. For example, when you type ‘thi’, the selected item will be ‘this’, which is the first one matches the ‘thi’.

This type of searching is achived by providing the JComboBox a custom JComboBox.KeySelectionManager object.

Searching after typing

The text field of JComboBox is set to be editable. After type a string, hit Enter key, the matched item will be selected and shown in the text field. The matching is same as the first type of search.

An Action Listener is added to the JComboBox to conduct the searching by response the Enter key.

Let’s work through the code to see how they are done.

public class SearchableComboBox extends JPanel {

static JFrame frame;
/**

* the drop down box for Searching while Typing.

*/

JComboBox jcb1 = null;
/**

* The drop down box for Search after Typing.

*/

JComboBox jcb2 = null;

/**

* If the Frame is visible. The combombox poppup

* Can only be set to

* visible after the main frame is visible.

*/

public boolean bVisible = false;

Notice the plain Swing JComboBox is used to define the two combo box members. We are not customizing it by extending it.

public SearchableComboBox() {

String[] listExamples = {

“This”,

“is”,

“just”,

“a”,

“test”,

“case”,

“hello”,

“the”,

“world”

};

This is the list of string we put into the combo box to do the test.

jcb1 = new JComboBox(listExamples);

jcb1.setEditable(false);

jcb1.setAlignmentX(Component.LEFT_ALIGNMENT);

jcb1.setKeySelectionManager( new myKeyManager() );

The first combo box, search while typing, has set to have a new JComboBox.KeySelectionManager instance. Be aware that KeySelectionManager is an interface defined as inner interface of JComboBox. MyKeyManager is an inner class defined in SearchableComboBox by implementing the interface.

Implementing Interfaces are the most important way of customizing Swing components.

class myKeyManager implements JComboBox.KeySelectionManager {

String keys = null;

int curSelected = 0;

myKeyManager ()

{ }

/**

* Searchs the data model based on the letter typed in.

*

* @param aKey the current typed in letter.

* @param aModel

* @return the index of item selected.

*/

public int selectionForKey(char aKey, ComboBoxModel aModel)

{

int iCount = aModel.getSize();

int iPatternLen = 0;

int iSelected = 0;

String sItem = null;

if ( Character.getNumericValue(aKey) == -1)

{

keys = null;

}

else

{

if (keys != null)

keys = keys + (new Character(aKey)).toString();

else

keys = (new Character(aKey)).toString();

if (keys != null )

iPatternLen = keys.length();

for (int pos = 0; pos < iCount; pos ++ )

{

sItem = (String)aModel.getElementAt(pos);

if (sItem.length() >= iPatternLen )

{

if( sItem.substring(0,iPatternLen).equals(keys) )

{

iSelected = pos;

curSelected = iSelected;

break;

}

}

else

iSelected = curSelected;

}

}

if( bVisible )

jcb1.setPopupVisible(true);

return curSelected;

}

}

In the method selectionForKey, any custom searching mechanism can be created and the JComboBox will take it use it. JComboBox only knows the interface, means it only deals with a type of object. The concrete function is delegated to the object that implements the interface.

The same approach has footprints all over Swing. To customize Swing, you basically replace some bolts and nuts. You won’t touch or rebuild the whole frame.

The second combo box is event driven searching.

void searchJCB(JComboBox jcb) {

String newSelection = (String)jcb.getSelectedItem();

int iCount = jcb.getItemCount();

int iSelectionLen = newSelection.length();

//save the selection index from last search.

int iSelected = 0;

//the current selection index.

int iSelecting = 0;

String sItem = null;

for (int pos = 0; pos < iCount; pos ++ )

{

sItem = (String)jcb.getItemAt(pos);

A method searchJCM is defined to conduct the search based on the string in the text field of the JComboBox object.

As you may see or feel, the first the approach is more flexible. Different searching algorisms can be easily plug-and-play. It’s the recommended method of customizing Swing components.

Updated on 6 March 2006