raincloud
raincloud

Reputation: 21

Converting decimal input in a Javafx textfield to a double

So, I'm pretty new to javafx and was trying to use the textfield to take in a string and then, using a try catch, convert the string to a double if possible. The only problem I'm having is that if I enter a decimal, ex 1000.56, the catch activates and my error label pops up saying that it can't take in a string. This is the relevant block of code, please assume I have all the proper imports and all the basic setup for the variables done.

            //takes in the users input and trims spaces
            holder[i] = txtFld.getText().trim();
            while(run == false) {
                try {
                    //attempts to parse the stripped text to a double
                    amt[i] = Double.parseDouble(holder[i]);
                    //allows the loop to break
                    run = true;
                }catch(NumberFormatException ex) {
                    txtFld.setText("");
                    //tells the user about the error
                    grid.add(Err, 0, 3);
                }
            }

Upvotes: 0

Views: 1391

Answers (1)

fabian
fabian

Reputation: 82461

You should not do loops like this in JavaFX for several reasons:

  • A loop like this blocks the application thread. This results in no inputs being processed while the loop is running.
  • You modify the text even if the input is not finished. Consider the scenario wher the user wants to input -1E3. The only way your code would allow this input would be stepwise changing the text like this: "" -> "1" -> "-1" -> "-13" -> "-1E3"

The simplest fix would be to simply check on "submitting" the data. Alternatively listen to the TextField.text property and display some indication of invalid input (e.g. some icon) but do not modify the text on every change.

There's some implementation already available that tries to parse the text on focus loss: TextFormatter:

@Override
public void start(Stage primaryStage) {
    TextField textField = new TextField();

    TextFormatter<Double> formatter = new TextFormatter<>(new DoubleStringConverter(), 0d);
    textField.setTextFormatter(formatter);

    formatter.valueProperty().addListener((o, oldValue, newValue) -> System.out.println("value changed to " + newValue));

    Button button = new Button("some other focusable element");

    Scene scene = new Scene(new VBox(textField, button));
    primaryStage.setScene(scene);
    primaryStage.show();
}

Edit

For "submission" buttons simply validate the value from the event handler:

@Override
public void start(Stage primaryStage) {
    TextField textField = new TextField();
    Label textErrorLabel = new Label();
    textErrorLabel.setTextFill(Color.RED);

    HBox textBox = new HBox(10, textField, textErrorLabel);
    textBox.setPrefWidth(300);

    Button button = new Button("Submit");
    button.setOnAction(evt -> {
        boolean valid = true;
        double value = 0;
        try {
            value = Double.parseDouble(textField.getText());
            textErrorLabel.setText("");
            textField.setStyle(null);
        } catch (NumberFormatException ex) {
            valid = false;
            textErrorLabel.setText("erroneous input");
            textField.setStyle("-fx-control-inner-background: red;");
        }

        // you could do more input validation here...

        if (valid) {
            System.out.println("successfully submitted "+ value);
        }
    });

    Scene scene = new Scene(new VBox(textBox, button));
    primaryStage.setScene(scene);
    primaryStage.show();
}

Upvotes: 2

Related Questions