Manière élégante de gérer la saisie au clavier dans JavaFX


Je travaille actuellement sur une calculatrice dans JavaFX et en ce moment j'essaie d'implémenter la prise en charge de la saisie au clavier.

Pour cela, j'essaie d'implémenter un EventHandler dans le principal .fichier java comme ceci:

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene_main = new Scene(root);

    stage.setScene(scene_main);
    stage.show();

    scene_main.setOnKeyPressed(new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent keyEvent) {

            switch (keyEvent.getCode()) {
                case ENTER:
                    System.out.println("Enter");
                    break;
                case ADD:
                    System.out.println("Plus");
                    break;
                case SUBTRACT:
                    System.out.println("Minus");
                    break;
                case DIVIDE:
                    System.out.println("Division");
                    break;
                case MULTIPLY:
                    System.out.println("Multiply");
                    break;

            }
        }
    }
    );
}

Le FXMLDocumentController.java:

import java.net.URL;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.Random;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;

/**
 *
 * @author ilja
 */
public class FXMLDocumentController implements Initializable {

@FXML
private void handleTestAction(ActionEvent event) throws Exception {
    ((Node) (event.getSource())).getScene().getWindow().hide();
    Parent parent = FXMLLoader.load(getClass().getResource("/calculator/CrashPopup.fxml"));
    Stage stage = new Stage();
    Scene scene = new Scene(parent);
    stage.setScene(scene);
    stage.setTitle("Teeeeest");
    stage.show();
}

private enum State {

    EQUALED, FIRST, SECOND, OPERATOR
}

public static String operator = "+";
private double oldValue = 0;
private double newValue = 0;
private double result = 0;
private String oldText, newText;
private String digit;
private boolean equaled = false;
Random r = new Random();
int i1;

private State state = State.EQUALED;

NumberFormat nf = new DecimalFormat("##.###", new DecimalFormatSymbols(Locale.US));

@FXML
private TextField displayField;

@Override
public void initialize(URL url, ResourceBundle rb) {
    // TODO
    displayField.setText("0");
}

@FXML
private void handleDotAction(ActionEvent event) {

    double result;

    oldText = displayField.getText();

    if (!oldText.isEmpty() && !oldText.contains(".")) {
        newText = oldText + ".";
    } else {
        newText = oldText;
    }

    displayField.setText(newText);
    result = Double.parseDouble(newText);

    if (state == State.EQUALED || state == State.FIRST) {
        oldValue = result;
        state = State.FIRST;
    } else {
        newValue = result;
        state = State.SECOND;
    }
}

@FXML
private void handleDigitAction(ActionEvent event) {

    digit = ((Button) event.getSource()).getText();
    if (state == State.FIRST || state == State.SECOND) {
        oldText = displayField.getText();
    } else {
        oldText = "";
    }

    if ("0".equals(oldText) /*|| "0.0".equals(oldText)*/) {
        displayField.setText(digit);
    } else {
        displayField.setText(oldText + digit);
    }

    if (state == State.EQUALED || state == State.FIRST) {
        oldValue = Double.parseDouble(displayField.getText());
        state = State.FIRST;
    } else {
        newValue = Double.parseDouble(displayField.getText());
        state = State.SECOND;
    }
}

@FXML
private void handleOperator(ActionEvent event) {

    if (state == State.EQUALED) {
        operator = ((Button) event.getSource()).getText();
    }

    if (state == State.SECOND) {
        switch (operator) {
            case "+":
                oldValue += newValue;
                break;
            case "-":
                oldValue -= newValue;
                break;
            case "*":
                oldValue *= newValue;
                break;
            case "/":
                oldValue /= newValue;
                break;
            default:
                break;
        }
        result = oldValue;
        newValue = 0;
        displayField.setText(String.valueOf(nf.format(oldValue)));
    }

    operator = ((Button) event.getSource()).getText();
    state = State.OPERATOR;
}

@FXML
private void handleEqualAction(ActionEvent event) throws Exception{

    i1 = r.nextInt(6 - 0) + 0;

    if (i1 == 1) {
        ((Node) (event.getSource())).getScene().getWindow().hide();
        Parent parent = FXMLLoader.load(getClass().getResource("/calculator/CrashPopup.fxml"));
        Stage stage = new Stage();
        Scene scene = new Scene(parent);
        stage.setScene(scene);
        stage.setTitle("Unerwarteter Fehler");
        stage.show();
    }

    switch (operator) {
        case "+":
            oldValue += newValue;
            break;
        case "-":
            oldValue -= newValue;
            break;
        case "*":
            oldValue *= newValue;
            break;
        case "/":
            oldValue /= newValue;
            break;
        default:
            break;
    }
    result = oldValue;
    displayField.setText(String.valueOf(nf.format(oldValue)));

    state = State.EQUALED;

}

@FXML
private void handleClearAction(ActionEvent event) {
    displayField.setText("0");
    oldValue = 0;
    newValue = 0;
    operator = "+";
    state = State.EQUALED;
}

@FXML
private void handleClearEntryAction(ActionEvent event) {
    displayField.setText("0");
    newValue = 0;
    switch (state) {
        case EQUALED:
            displayField.setText(String.valueOf(nf.format(result)));
            break;
        case FIRST:
            oldValue = 0;
            state = State.EQUALED;
            break;
        case SECOND:
        case OPERATOR:
            newValue = 0;
            state = State.OPERATOR;
            break;
        default:
            break;
    }
}

private void handleZeroAction(ActionEvent event) {
    digit = ((Button) event.getSource()).getText();
    oldText = displayField.getText();
    if ("0".equals(oldText) || "0.0".equals(oldText)) {
        newText = oldText;
    } else {
        newText = oldText + digit;
    }
    displayField.setText(newText);
}
}

Maintenant, le problème est que chaque fois que ces touches sont pressées, les mêmes choses devraient se produire que lorsque je clique sur les boutons correspondants dans l'interface graphique.

Tous les boutons numériques partagent un événement onAction et +,-,/,* partagez également un, etc. Ils utilisent tous des variables dans le FXMLDocumentController.fichier java.

Je ne suis donc pas sûr de la meilleure façon de gérer cela. Puis-je simplement invoquer les événements onAction à partir du principal.fichier java ou dois-je copier coller (ce qui provoquerait une redondance) le contenu de la méthode dans ce fichier et rendre les variables publiques/protégées?

J'ai essayé d'appeler les méthodes à partir du fichier principal mais j'ai échoué car je ne comprends pas quels paramètres la méthode obtiendra, comme ils nécessitent un objet ActionEvent.

Author: Someguy, 2015-10-14

1 answers

Si vous refactorisez les méthodes du gestionnaire afin qu'elles déterminent simplement la valeur qu'elles représentent, appelez une autre méthode, par exemple:

@FXML
private void handleDigitAction(ActionEvent event) {

    String digit = ((Button) event.getSource()).getText();
    handleDigit(digit) ;
}

public void handleDigit(String digit) {
    if (state == State.FIRST || state == State.SECOND) {
        oldText = displayField.getText();
    } else {
        oldText = "";
    }

    if ("0".equals(oldText) /*|| "0.0".equals(oldText)*/) {
        displayField.setText(digit);
    } else {
        displayField.setText(oldText + digit);
    }

    if (state == State.EQUALED || state == State.FIRST) {
        oldValue = Double.parseDouble(displayField.getText());
        state = State.FIRST;
    } else {
        newValue = Double.parseDouble(displayField.getText());
        state = State.SECOND;
    }
}

Ensuite, vous pouvez appeler la nouvelle méthode si nécessaire:

@Override
public void start(Stage stage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
    Parent root = loader.load();
    FXMLDocumentController controller = loader.getController();

    Scene scene_main = new Scene(root);

    stage.setScene(scene_main);
    stage.show();

    scene_main.setOnKeyPressed(new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent keyEvent) {

            switch (keyEvent.getCode()) {
                case DIGIT1:
                    controller.handleDigit("1");
                    break ;
                case DIGIT2:
                    controller.handleDigit("2");
                    break ;
                case DIGIT3:
                    controller.handleDigit("3");
                    break ;
                case DIGIT4:
                    controller.handleDigit("4");
                    break ;
                case DIGIT5:
                    controller.handleDigit("5");
                    break ;
                case DIGIT6:
                    controller.handleDigit("6");
                    break ;
                case DIGIT7:
                    controller.handleDigit("7");
                    break ;
                case DIGIT8:
                    controller.handleDigit("8");
                    break ;
                case DIGIT9:
                    controller.handleDigit("9");
                    break ;

            }
        }
    }
    );
}

Et ainsi de suite.

 1
Author: James_D, 2015-10-15 13:07:06