To take action for a button, you should call button.setOnAction(eventHandler)
, not button.setOnMouseClicked(mouseEventHandler)
. That way if the button action is triggered in some other way than clicking on it with a mouse (e.g. via a keyboard action or a programmatic call to button.fire()
), the desired action will still be triggered.
The eventHandler
is already the equivalent of a function reference, all it does is provide a single method to handle()
the event, so, for the purposes of Java 8, it forms a SAM type, which allows useful shortcuts using lambdas and method references.
There are lots of different ways to define and set event handler methods. The source code below provides some examples. Not all examples are used, so it has redundant code on purpose, but it includes lots of examples to demonstrate the different ways functions can be defined and used.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class FunctionalButton extends Application {
@Override
public void start(Stage stage) throws Exception {
Layout layout = new Layout();
layout.setFunction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println(
"Invoked function from anonymous inner class defined in " + FunctionalButton.class.getSimpleName()
);
}
});
layout.setFunction(
(actionEvent) ->
System.out.println(
"Invoked function from lambda defined in " + FunctionalButton.class.getSimpleName()
)
);
// use a method reference.
layout.setFunction(this::applicationInstanceHandleButtonAction);
stage.setScene(new Scene(layout));
stage.show();
}
private void applicationInstanceHandleButtonAction(ActionEvent event) {
System.out.println("Invoked event handler for method applicationInstanceHandleButtonAction");
}
public static void main(String[] args) {
launch(args);
}
}
class Layout extends StackPane {
private Button button = new Button("Invoke Configurable Function");
private EventHandler<ActionEvent> layOutEventHandlerWithoutLambda =
new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Invoked event handler layOutEventHandlerWithoutLambda");
}
};
private EventHandler<ActionEvent> layOutEventHandlerWithLambda =
event -> System.out.println("Invoked event handler layOutEventHandlerWithLambda");
private static void staticHandleButtonAction(ActionEvent event) {
System.out.println("Invoked event handler for method staticHandleButtonAction");
}
private void instanceHandleButtonAction(ActionEvent event) {
System.out.println("Invoked event handler for method instanceHandleButtonAction");
}
public Layout() {
getChildren().add(button);
button.setOnAction(layOutEventHandlerWithoutLambda);
button.setOnAction(layOutEventHandlerWithLambda);
button.setOnAction(Layout::staticHandleButtonAction); // Java 8 static method reference.
button.setOnAction(this::instanceHandleButtonAction); // Java 8 instance method reference.
}
public void setFunction(EventHandler<ActionEvent> eventHandler) {
button.setOnAction(eventHandler);
}
}
For background (and to help if you can't understand some of the code in the example), you could review:
As you are using FXML, if you need to know how to pass a value to a controller (to set the event handler on the button from another class outside the controller), review: