How to Organize Event Listeners

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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?

Back in my Java2D time I use no 2.

Uh, isn’t the most organized way to create something like an Input class which implements whatever you want it to?

… Yes? Java 2D requires an object implementing a listener interface. The fact that addMouseListener expects a custom implementation of a MouseListener interface means you will indeed have a class designed to handle input that implements stuff to do whatever you want.

The question is where you create that class. Do you want it in the same file or a separate file? If it is an inner class, do you want it to be static or non-static? Do you want an anonymous or general purpose class?

If you mean the mega input classes that noobs inevitably create to centralize input processing or emulate polling, then it depends on the situation. If your requirements are so simple that you can use polling exclusively, then you can use a centralized class. If you’re creating a game with multiple types (uses) of input, then you will want a modular set up. Your input class or its clients would turn into a giant mess if you had to manage the state of every aspect of your UI in one object. It’s the Java equivalent to a C programmer overusing global variables. Things would easily break if they were changed and it would be hard to read if you could not isolate the code relevant to what you were looking to read.

I presume the reader requires the use of a callback based interface in a library such as, but not necessarily, Java2D. And if not, it is still helpful for people that would not consider different styles of programming because they only know how to handle things like listeners using hacks. It is also good advice to Java programmers in general. (I write a lot of applets and desktop applications. I also use them to prototype physics simulations, algorithms, and control systems for games. Adapting between different styles of user interface libraries does not cost me any time.) I don’t advocate or care if someone uses Java2D and this may be irrelevant to LWJGL users, but it would be better if people could use this as a reference or template.

It is embarrassing to be a Java programmer whenever someone releases source code with hacks to get listeners working.
Or, makes a terrible UI because the programmer spent too much time writing disorganized Swing code.
Or, reinvents the wheel be making their own input handling classes.
Or, complains about the problem of using ugly anonymous classes.
Or, says that Java needs duck typing or first class functions.
Or, says that Java projects have more source code files than other projects. (A myth true for C++ but not Java, contrary to popular misconception.)

For some reason, I do not see many other people store anonymous classes directly in fields or using the same layout as normal classes. They always stick them in local variables or directly in function parameters. It’s one of the tricks I learned that probably is not standard Java practices but really improves your productivity. It also addresses one of the persistent criticisms/myths of Java that JDK programmers try to solve with language modifications based on truly bad programming languages.

  1. Use a little helper to map events directly to handler methods: no clutter from anonymous classes, meaningful names like onSaveButtonClicked(…) instead of actionPerformed(…), one place for common actions like logging ui exceptions, multiple event handlers possible

EDIT:
Without using any magic helper, just keep the anonymous listeners classes as small as possible and call the real handlers from there (again, meaningful methods names). Easier to test, easier to trigger the same functions from various event sources, one code block to group the listener clutter which usually do not need be looked at later.

Good point. Action listeners are strange… :expressionless:

I still like encapsulating UI input state in its own class/object. I like to think of the listener class as a plugin, so that even if I only write one, the user interface code can be written independently from the rendering and functional methods of the main class. This might be useful, for example, if you started with a applet supporting two button computers but later decide you want to expand the project to support touch screens. If you mixed the functionality of the two classes, you would have to rewrite most of your class and then you may need multiple versions of the same methods or similar variables. Noobs to that type of UI programming, including myself at one time, end up writing terrifying spaghetti code. When I don’t need two implementations, it is still helpful in case I ever make a mistake that requires reworking part of the class and because I can write a crude interface using the easiest methods for quick testing and replace the listener/state-handler later with a more polished one.

It’s absolutely a good idea to split up a basic listener interface with individual “events”. A lot of people make the mistake of doing things like creating a public save() method of their component class instead of a protected saveButtonPressed() and a public saveProject() method in another class. You can use both methods, so I would not call it a fifth method. :slight_smile: