How to constrain a TextField so that it can only contain one '.' the character? JavaFX

I found a very useful class on the internet that I can use to constrain the TextField. I am facing an issue where my TextField can only contain one. the character. I suspect I can handle this by writing a regex appripriate and setting it as a constraint on an instance of that class. I use the following regex: "[0-9.-]", but it allows as many periods as the user enters. May I ask you to help me customize my TextField so that no more than one. allowed.

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;

/**
 * Created by Anton on 7/14/2015.
 */
public class RestrictiveTextField extends TextField {
private IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
private StringProperty restrict = new SimpleStringProperty(this, "restrict");

public RestrictiveTextField() {
    super("0");
    textProperty().addListener(new ChangeListener<String>() {

        private boolean ignore;

        @Override
        public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {

            if (ignore || s1 == null)
                return;
            if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
                ignore = true;
                setText(s1.substring(0, maxLength.get()));
                ignore = false;
            }

            if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
                ignore = true;
                setText(s);
                ignore = false;
            }
        }
    });
}

/**
 * The max length property.
 *
 * @return The max length property.
 */
public IntegerProperty maxLengthProperty() {
    return maxLength;
}

/**
 * Gets the max length of the text field.
 *
 * @return The max length.
 */
public int getMaxLength() {
    return maxLength.get();
}

/**
 * Sets the max length of the text field.
 *
 * @param maxLength The max length.
 */
public void setMaxLength(int maxLength) {
    this.maxLength.set(maxLength);
}

/**
 * The restrict property.
 *
 * @return The restrict property.
 */
public StringProperty restrictProperty() {
    return restrict;
}

/**
 * Gets a regular expression character class which restricts the user input.

 *
 * @return The regular expression.
 * @see #getRestrict()
 */
public String getRestrict() {
    return restrict.get();
}

/**
 * Sets a regular expression character class which restricts the user input.

 * E.g. [0-9] only allows numeric values.
 *
 * @param restrict The regular expression.
 */
public void setRestrict(String restrict) {
    this.restrict.set(restrict);
}

      

}

+3


source to share


3 answers


There are different versions of the regular expression, depending on what you want to support. Note that you not only want to match actual numbers, but partial entries, because the user needs to be able to edit this. So, for example, an empty string is not a valid number, but of course you want the user to be able to delete anything while editing; similarly you want to allow "0."

etc.

So, you probably want something like

An optional minus sign followed by either any number of digits or at least one digit, a period ( .

), and any number of digits.

A regex for this could be -?((\\d*)|(\\d+\.\\d*))

. There may be other ways to do this, some of which are perhaps more efficient. And if you want to support exponential forms ( "1.3e12"

), it gets more complicated.



To use this with TextField

, it is recommended to use TextFormatter

. TextFormatter

consists of two things: a converter to convert between text and the value it represents (a Double

in your case: you can just use the inline DoubleStringConverter

), and vice versa, and then a filter. A filter is implemented as a function that takes an object TextFormatter.Change

and returns an object of the same type. Typically, you either leave the object Change

as it is and return it (to accept Change

"as is"), or modify it in some way. It is also legal to returnnull

to represent "no change". So, in your simple case, just examine the new suggested text, see if it matches the regex, revert the change "as is" if it does, and returns null

otherwise.

Example:

import java.util.regex.Pattern;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.converter.DoubleStringConverter;

public class NumericTextFieldExample extends Application {

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

        Pattern validDoubleText = Pattern.compile("-?((\\d*)|(\\d+\\.\\d*))");

        TextFormatter<Double> textFormatter = new TextFormatter<Double>(new DoubleStringConverter(), 0.0, 
            change -> {
                String newText = change.getControlNewText() ;
                if (validDoubleText.matcher(newText).matches()) {
                    return change ;
                } else return null ;
            });

        textField.setTextFormatter(textFormatter);

        textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
            System.out.println("New double value "+newValue);
        });

        StackPane root = new StackPane(textField);
        root.setPadding(new Insets(24));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

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

      

+9


source


You can use the following regex,

"[^\\.]*\\.{0,1}[^\\.]"

      

Or, as VGR pointed out, "The period has no special meaning within the parentheses of the class symbol, and 0 or 1 time can be represented by the character '?' (question mark). so you can also use

"[^.]*\\.?[^.]"

      

I don't know why, but your class seems to be appending *

to a regex, so the above regex will be effective,



"[^\\.]*\\.{0,1}[^\\.]*"

      

It means that

  • It will allow any character except .

    0 or more (greedy).
  • This will allow .

    0 or 1 times.
  • It will allow any character except .

    0 or more (greedy).

This is what you think you need. DEMO

+1


source


{[0-9]+\\.[0-9]+}

      

to match any number if that's really what you want to do

0


source







All Articles