0

I have a field and a filter on it that just allows digits and ,

I want that if I type 1, that I automatically have 1,0 when I leave the text field. I could parse it and check with a substring whether there is a , at the end. But that is not a very good way to do it in my opinion. Is there a better way to do it?

yemerra
  • 1,352
  • 4
  • 19
  • 44
  • Are you using a `TextFormatter`? If so, providing a converter should do this for you. (And haven't we already been over this twice before?) – James_D Mar 17 '16 at 19:02

2 Answers2

1

Use a converter in the text formatter you are using to filter the input:

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.function.UnaryOperator;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class DecimalTextField extends Application {

    @Override
    public void start(Stage primaryStage) {
        // decimal formatter for default locale:
        DecimalFormat decimalFormat = new DecimalFormat();
        decimalFormat.setMinimumFractionDigits(1);
        DecimalFormatSymbols symbols = decimalFormat.getDecimalFormatSymbols() ;
        char decimalSep = symbols.getDecimalSeparator() ;

        UnaryOperator<Change> filter = change -> {
            for (char c : change.getText().toCharArray()) {
                if ( (! Character.isDigit(c)) && c != decimalSep) {
                    return null ;
                }
            }
            return change ;
        };

        StringConverter<Double> converter = new StringConverter<Double>() {

            @Override
            public String toString(Double object) {
                return object == null ? "" : decimalFormat.format(object);
            }

            @Override
            public Double fromString(String string) {
                try {
                    return string.isEmpty() ? 0.0 : decimalFormat.parse(string).doubleValue();
                } catch (ParseException e) {
                    return 0.0 ;
                }
            }

        };

        TextFormatter<Double> formatter = new TextFormatter<>(converter, 0.0, filter);
        TextField textField = new TextField();
        textField.setTextFormatter(formatter);

        VBox root = new VBox(10, textField, new TextArea());
        root.setAlignment(Pos.CENTER);
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

(Obviously the filter could be improved here to, e.g. avoid multiple decimal separator characters in the input.)

James_D
  • 201,275
  • 16
  • 291
  • 322
  • why do i have to override the toString and fromString methods? – yemerra Mar 17 '16 at 19:40
  • How else would the converter know how to convert? I don't really understand that question. – James_D Mar 17 '16 at 19:40
  • Sorry, I just never saw someone overriding these methods. I always used these methods without overriding for integers e.g. – yemerra Mar 17 '16 at 19:41
  • Huh? [You have seen converters before.](http://stackoverflow.com/questions/35245741/why-do-we-need-converters-for-textformatters) It's impossible to write a converter without overriding those methods. – James_D Mar 17 '16 at 19:43
  • Oh sorry, I only used given converters actually. Like `new LocalDateStringConverter()` – yemerra Mar 17 '16 at 19:43
  • Does this solution consider that I want to have `,` for the numbers? – yemerra Mar 17 '16 at 19:52
  • Ah, it need to use the decimal format to parse the string... see updated version – James_D Mar 17 '16 at 19:58
  • When I write `1,` with this, I will have `1`as a result. But I want to have `1,0`in my field :( – yemerra Mar 17 '16 at 20:14
  • Really? I tried that and (with the locale set to German) I get `1,0`. You have the `setMinimumFractionDigits(1)` call? – James_D Mar 17 '16 at 20:16
  • Ah sorry, now it works. Just one little problem more. My filter just allows digits and `,`. If I write lets say 100000,5 i will get 100.000,5 as a result. So i cannot edit it since my filter always thinks it is forbidden because of the `.`. How can I get rid of the `.` ? – yemerra Mar 17 '16 at 20:20
  • Just fix the decimal formatter to be as you need it. If you want someone to actually do your entire job for you, you need to pay them. – James_D Mar 17 '16 at 20:25
  • I just don't know what couses this. Can you give me a hint what I have to look at? – yemerra Mar 17 '16 at 20:28
  • Are you bothering to understand the code I offer you, say by reading the actual documentation for the method calls, or are you just blindly copying it without even trying to figure out how it works? If you can't be bothered to even read the docs for the classes and methods, I am done here. – James_D Mar 17 '16 at 20:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106653/discussion-between-dennis-von-eich-and-james-d). – yemerra Mar 17 '16 at 20:35
0

I think the best would be to convert the string to a double and then convert the double back to a string using DecimalFormat. That way you know you'll know the number is in your desired format.

Community
  • 1
  • 1
Thomas4019
  • 563
  • 6
  • 10