In virtually all examples I could find, JavaFX event handlers are created as anonymous inner classes,
like so:
button.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getClickCount()>1) {
System.out.println("double clicked!");
}
}
});
But, I really hate anonymous inner classes (UGLY!!!), and I also don't want to create separate classes for each and every event handler. I would like to use existing methods as event handlers, as FXMLLoader does. My first idea was to use reflection and generics, and this is what I came up with:
public final static <E extends Event> EventHandler<E> createEventHandler(
final Class<E> eventClass, final Object handlerInstance, final String handlerMethod) {
try {
final Method method = handlerInstance.getClass().getMethod(handlerMethod, eventClass);
return new EventHandler<E>() {
@Override
public void handle(E event) {
try {
method.invoke(handlerInstance, event);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
};
} catch (NoSuchMethodException | SecurityException e) {
return null;
}
}
You pass a required Event class, handler instance and method name which will handle the event, and required EventHandler is returned. It works, but it doesn't look very elegant. Does anyone have a better idea?
Best Answer
Suggested Approach
Use Tom's idea regarding Java 8 method references:
Executable Sample
Futher discussion based upon points in the question and comment sections
Use Java 8 lambdas instead, they are not quite as ugly:
For a general purpose mechanism you could take a look at FXMLLoader source code and extract just the event handling mechanism out to a generic library.
Also, if your UI is defined in FXML, then you can just use the existing functionality in the FXMLLoader to get the behaviour you want. (I'm guessing you are looking for a solution which does not involve FXML though).
Keeping References
Assign the event handler to a reference. This approach is good in terms of usefulness in certain cases, not necessarily beauty.
One advantage of keeping a local reference to a handler is that it provides you a reference to later invoke node.removeEventHandler for a handler that was previously registered using node.addEventHandler.
Using alternate languages
If you are open to alternative languages, then implementing dynamic method calling is a little bit cleaner in a dynamic language. You can see how JRubyFX deals with the issue of event handler assignment from FXML documents (I don't think it relies on FXMLLoader but believe it has a pure Ruby replacement implementation of it's own). Of course, then you are using a dynamic language which may or may not desirable in your case.