Tutorial: Custom components

In this tutorial you will learn how to create your own recorder/simulator classes to deal with events generated by custom components. If you bump into an unknown concept or term, take a look in the concepts or the API section.

Custom components

Custom components are GUI components that are not part of the Java SDK (i.e. the java.awt or javax.swing components). Some custom components will come with their own listeners and events, and the standard JUseCase distribution will probably not be able to deal with them. In order to describe what to do to extend JUseCase we will in this tutorial add a custom component to our application, and then we will create a recorder/simulator class to deal with this custom component's events. You can find the source code for this tutorial's demo application here.

A double-click JLabel

The custom component in this tutorial is an extension of the Java Swing JLabel. It generates ActionEvents when double-clicked. You can download the DoubleClickLabel source code here.

Creating a new recorder/simulator class

When you want to extend JUseCase with a new recorder/simulator class you will probably want to extend from the ScriptedComponent class. It does most of the setup work for you, such as registering the recorder/simulator with JUseCase etc. For a working recorder/simulator you have to do the following:

Setting up the recorder

The ScriptedDoubleClickLabel (source code here) constructor takes two arguments:

Both of these arguments are in turn passed on to the ScriptedComponent constructor, which makes sure that our new recorder/simulator is registered with JUseCase properly. We then add an ActionListener to the DoubleClickLabel, and in the actionPerformed method we add a call to recordCommand to actually record the event when it is detected. The recordCommand method takes two arguments:

Since we don't need any extra information to be saved with the command name, and we want each double-click to be recorded, we call recordCommand("", false).

Setting up the simulator

We now basically have the recording mechanism in place - events will be sent to our listener, which then will record them. The next step is to implement performCommand which should simulate a double-click on the DoubleClickLabel. The method takes one argument, parameters, which will be set to whatever was recorded with recordCommand. Since it will be an empty string, we won't care about it in this simulator object. Instead we will create a double-click MouseEvent manually, and have it posted to the event queue, which then will deal with it like all other events. Eventually the DoubleClickLabel will receive the event, convert it to an ActionEvent and pass it on to all its listeners.

Component focus determines what is recored

Since the JUseCase recorder objects are normal listeners, they will receive events even if the user didn't initiate them. Assume you have a JButton, which when clicked will select an item in a JList. If JUseCase recorded both the button click and the selection event, the use case script would not be correct (the user only clicked the button!). To avoid this error, JUseCase only records events for components that have focus. In our example, the button would have focus (since it was clicked by the user) but the list would not. Our custom component, the DoubleClickLabel, is a JLabel and thus does not receive focus, so we have inform JUseCase of this. This is done by implementing hasCustomFocus(), which JUseCase will call in addition to checking for normal focus. If we always return true in our implementation of this method we're safe (unless you fake a double-click on the label somewhere outside of our simulator, in which case the event would be recorded even if it wasn't user-initiated).

Putting it together

All JUseCase recorder/simulator classes provide a static factory method, connect, which creates the recorder/simulator instance for you, so we do this in our new recorder/simulator as well. With this in place, it is ready for use in our tutorial demo application, and this marks the end of this tutorial.