I think a lot of people probably have trouble writing event listener code. It is awkward and error prone for new Java users. Here’s how I deal with event listeners and other single purpose anonymous classes. Notice that the object/anonymous class looks a lot like a nested class. The code to attach the event listener is in the object’s constructor and the code that defines the listener is in its own function. (This code is based on a file from a non-game project using Swing.)
I can think of four alternatives:
- Make your class implement a listener interface and attach it by passing
this
as a parameter. – This has the downside that you can only use one instance of a given listener type and that your event listener interface is exposed as public. - Use an inner class and create a new one the first time you use it. – This code is essentially the same, but it is a little easier to use. You could attach or remove listeners if you had to. The addListener code is more concise and readable. It is the same number of lines or one fewer.
- Declare your class in the same place as you first use it. – It’s harder to find the relevant code and is more difficult to read once you find it.
- Use lambdas, anonymous functions, or other magic imported from scripting languages. – Nope. It involves fewer characters, which is no practical benefit, but it is as bad as #3.
This method is easy to use. Takes only a few characters with the use of autocompletetion and could easily be made a code template. It is extremely readable and is consistent with Java’s type system and its practical features. It is very easy to find the relevant code if you’re used to the practice and can be found easier with IDE tools. The nested usage and scoping makes it easy to define methods and variables consistent with good object oriented programming practices. Using adapter classes instead of interfaces is helpful while developing since you can add functionality later without adding empty methods. (Use IDE code completion again to make that task even faster.)
public GridThingy extends JWhatever
{
public GridThingy()
{
addMouseListener(ml);
addMouseMotionListener(ml);
}
public int yToRow()
{
// Convert y position to row number
}
public Object setValue(int row, Object value)
{
// Set row data
}
public void clearValue(int row)
{
// Clear row data
}
/*
* Other methods ...
*/
private final MouseAdapter ml = new MouseAdapter()
{
private final long doubleClickTime = 600;
private long clickTime = System.currentTimeMillis() - doubleClickTime;
@Override public void mouseClicked(MouseEvent e)
{
long time = System.currentTimeMillis();
int x = e.getX(), y = e.getY();
boolean dbl = time - clickTime < doubleClickTime;
clickTime = time;
if(dbl && e.getButton() == MouseEvent.BUTTON1 && /* Omitted */ )
{
int row = yToRow(y);
Object o = promptValue(row);
if(o != null) setValue(row, o);
}
if(e.getButton() == MouseEvent.BUTTON3)
{
clearValue(yToRow(e.getX()));
}
}
@Override public void mouseMoved(MouseEvent e)
{
repaint();
}
};
}
It looks a lot better than the alternatives, doesn’t it?