javafx multiple buttons to same handler


Question

I try to make a simple calculator with 20 buttons and one handler. In java I can use 'if' statement with event.getSource() in ActionPerformed to check which button is pressed, but it doesn't work with handler in javafx. Is it possible in javafx that all buttons has one handler? (I don't want to use java 8 Lambdas.) Last time I tried with setId/getId but it same not work (to me).

public class Calculator extends Application {

    public Button b0, b1;

    @Override
    public void start(Stage primaryStage) {

        GridPane grid = new GridPane();

        b0 = new Button("0");
        b0.setId("0");
        b0.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        grid.add(b0, 0, 1);
        b0.setOnAction(myHandler);

        b1 = new Button("1");
        b1.setId("1");
        b1.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        grid.add(b1, 0, 0);
        b1.setOnAction(myHandler);

        Scene scene = new Scene(grid, 365, 300);
        scene.getStylesheets().add
            (Calculator.class.getResource("calculator.css").toExternalForm());

        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    final EventHandler<ActionEvent> myHandler = new EventHandler<ActionEvent>(){

        @Override
        public void handle(final ActionEvent event) {
            Button x = (Button) event.getSource();
            if (x.getId().equals(b0.getId()))
                System.out.println("0");
            else if(x.getId().equals(b1.getId()))
                System.out.println("1");
        }
    };
    public static void main(String[] args) {
        launch(args);
    }

}

1
6
8/20/2014 3:43:42 PM

Accepted Answer

I tested your code and it seems to work just fine.

There's no real reason to test the ids of the buttons, though. If you really want to use the same handler (which I don't advise), just test for equality between each button and the source of the event:

final EventHandler<ActionEvent> myHandler = new EventHandler<ActionEvent>(){

    @Override
    public void handle(final ActionEvent event) {

        if (event.getSource() == b0)
            System.out.println("0");
        else if(event.getSource() == b1)
            System.out.println("1");
    }
};

But it's (almost?) always better to use a different handler for each action. It keeps the code free of all the if/else constructs, which both makes it cleaner and better in terms of performance. Here, since your buttons do almost the same thing, you can use a single implementation but multiple objects.

Here's a complete example:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;

public class Calculator extends Application {

    private final IntegerProperty value = new SimpleIntegerProperty();


    class NumberButtonHandler implements EventHandler<ActionEvent> {
        private final int number ;
        NumberButtonHandler(int number) {
            this.number = number ;
        }
        @Override
        public void handle(ActionEvent event) {
            value.set(value.get() * 10 + number);
        }

    }

    @Override
    public void start(Stage primaryStage) {

        GridPane grid = createGrid();

        for (int n = 1; n<10; n++) {
            Button button = createNumberButton(n);
            int row = (n-1) / 3;
            int col = (n-1) % 3 ;
            grid.add(button, col, 2 - row);
        }

        Button zeroButton = createNumberButton(0);
        grid.add(zeroButton, 1, 3);

        Button clearButton = createButton("C");

        // without lambdas:

//        clearButton.setOnAction(
//            new EventHandler<ActionEvent>() {
//                @Override
//                public void handle(ActionEvent event) {
//                    value.set(0);
//                }
//            }
//        );

        // with lambdas:
        clearButton.setOnAction(event -> value.set(0));

        grid.add(clearButton, 2, 3);

        TextField displayField = createDisplayField();

        BorderPane root = new BorderPane();
        root.setPadding(new Insets(10));
        root.setTop(displayField);
        root.setCenter(grid);

        Scene scene = new Scene(root, 365, 300);

        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

     private Button createNumberButton(int number) {
        Button button = createButton(Integer.toString(number));
        button.setOnAction(new NumberButtonHandler(number));
        return button ;
    }

    private Button createButton(String text) {
        Button button = new Button(text);
        button.setMaxSize(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
        GridPane.setFillHeight(button, true);
        GridPane.setFillWidth(button, true);
        GridPane.setHgrow(button, Priority.ALWAYS);
        GridPane.setVgrow(button, Priority.ALWAYS);
        return button ;
    }


    private GridPane createGrid() {
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(5);
        grid.setVgap(5);
        grid.setPadding(new Insets(10));
        return grid;
    }

    private TextField createDisplayField() {
        TextField displayField = new TextField();
        displayField.textProperty().bind(Bindings.format("%d", value));
        displayField.setEditable(false);
        displayField.setAlignment(Pos.CENTER_RIGHT);
        return displayField;
    }

    public static void main(String[] args) {
        launch(args);
    }
}
5
8/20/2014 4:56:15 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon