Cách được khuyến nghị để tạo Trường văn bản số trong JavaFX là gì?


85

Tôi cần giới hạn đầu vào trong Trường văn bản ở các số nguyên. Có lời khuyên nào không?


3
Lưu ý: nghe textProperty là sai ! Đó là điều tốt nhất có thể được thực hiện trước khi có TextFormatter (kể từ fx8u40 trở lên). Kể từ đó, quy tắc cơ bản được áp dụng: Nói chung được coi là thực hành xấu để sửa đổi giá trị quan sát trong phương pháp này và sử dụng TextFormatter là giải pháp chấp nhận được duy nhất .
kleopatra

Câu trả lời:


118

Chủ đề rất cũ, nhưng điều này có vẻ gọn gàng hơn và loại bỏ các ký tự không phải số nếu được dán.

// force the field to be numeric only
textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, 
        String newValue) {
        if (!newValue.matches("\\d*")) {
            textField.setText(newValue.replaceAll("[^\\d]", ""));
        }
    }
});

3
Hoạt động tuyệt vời. Lưu ý rằng bạn cũng có thể sử dụng \\D+(hoặc chỉ \\D) thay vì [^\\d], nếu bạn muốn lưu một vài ký tự.
ricky3350

5
Đơn giản hơn nữa là đặt văn bản trở lại oldValue. Bằng cách đó, bạn không phải loay hoay với các thay thế regex (không may là điều này không phù hợp với tôi).
geisterfurz007 13/07/17

@ geisterfurz007 Tuy nhiên, điều này cung cấp tùy chọn loại bỏ các số không phải số khỏi văn bản được dán.
Evan Knowles

10
Lỗi thời, hãy xem câu trả lời TextFormatter bên dưới.
gerardw

3
Cũng có thể chỉ sử dụng Integer.parseInt(newValue)và sử dụng trycatchphát hiện lỗiNumberFormatException
Pixel

43

Cập nhật tháng 4 năm 2016

Câu trả lời này đã được tạo ra cách đây vài năm và câu trả lời ban đầu phần lớn đã lỗi thời.

Kể từ Java 8u40, Java có TextFormatter thường tốt nhất để thực thi đầu vào của các định dạng cụ thể như số trên Trường văn bản JavaFX:

Xem thêm các câu trả lời khác cho câu hỏi này đề cập cụ thể đến TextFormatter.


Câu trả lời gốc

Có một số ví dụ về điều này trong ý chính này , tôi đã sao chép một trong các ví dụ dưới đây:

// helper text field subclass which restricts text input to a given range of natural int numbers
// and exposes the current numeric int value of the edit box as a value property.
class IntField extends TextField {
  final private IntegerProperty value;
  final private int minValue;
  final private int maxValue;

  // expose an integer value property for the text field.
  public int  getValue()                 { return value.getValue(); }
  public void setValue(int newValue)     { value.setValue(newValue); }
  public IntegerProperty valueProperty() { return value; }

  IntField(int minValue, int maxValue, int initialValue) {
    if (minValue > maxValue) 
      throw new IllegalArgumentException(
        "IntField min value " + minValue + " greater than max value " + maxValue
      );
    if (maxValue < minValue) 
      throw new IllegalArgumentException(
        "IntField max value " + minValue + " less than min value " + maxValue
      );
    if (!((minValue <= initialValue) && (initialValue <= maxValue))) 
      throw new IllegalArgumentException(
        "IntField initialValue " + initialValue + " not between " + minValue + " and " + maxValue
      );

    // initialize the field values.
    this.minValue = minValue;
    this.maxValue = maxValue;
    value = new SimpleIntegerProperty(initialValue);
    setText(initialValue + "");

    final IntField intField = this;

    // make sure the value property is clamped to the required range
    // and update the field's text to be in sync with the value.
    value.addListener(new ChangeListener<Number>() {
      @Override public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
        if (newValue == null) {
          intField.setText("");
        } else {
          if (newValue.intValue() < intField.minValue) {
            value.setValue(intField.minValue);
            return;
          }

          if (newValue.intValue() > intField.maxValue) {
            value.setValue(intField.maxValue);
            return;
          }

          if (newValue.intValue() == 0 && (textProperty().get() == null || "".equals(textProperty().get()))) {
            // no action required, text property is already blank, we don't need to set it to 0.
          } else {
            intField.setText(newValue.toString());
          }
        }
      }
    });

    // restrict key input to numerals.
    this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
      @Override public void handle(KeyEvent keyEvent) {
        if(intField.minValue<0) {
                if (!"-0123456789".contains(keyEvent.getCharacter())) {
                    keyEvent.consume();
                }
            }
            else {
                if (!"0123456789".contains(keyEvent.getCharacter())) {
                    keyEvent.consume();
                }
            }
      }
    });

    // ensure any entered values lie inside the required range.
    this.textProperty().addListener(new ChangeListener<String>() {
      @Override public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
        if (newValue == null || "".equals(newValue) || (intField.minValue<0 && "-".equals(newValue))) {
          value.setValue(0);
          return;
        }

        final int intValue = Integer.parseInt(newValue);

        if (intField.minValue > intValue || intValue > intField.maxValue) {
          textProperty().setValue(oldValue);
        }

        value.set(Integer.parseInt(textProperty().get()));
      }
    });
  }
}

41

Tôi biết đây là một chủ đề khá cũ, nhưng đối với những độc giả trong tương lai, đây là một giải pháp khác mà tôi thấy khá trực quan:

public class NumberTextField extends TextField
{

    @Override
    public void replaceText(int start, int end, String text)
    {
        if (validate(text))
        {
            super.replaceText(start, end, text);
        }
    }

    @Override
    public void replaceSelection(String text)
    {
        if (validate(text))
        {
            super.replaceSelection(text);
        }
    }

    private boolean validate(String text)
    {
        return text.matches("[0-9]*");
    }
}

Chỉnh sửa: Cảm ơn none_SCBoy vì những cải tiến được đề xuất của bạn.


1
Có ai biết những gì regex để sử dụng cho các số thập phân (ví dụ: 123.456)? Giá trị của tham số hàm xác thực (văn bản) "văn bản" là ký tự cuối cùng do người dùng chỉnh sửa, không phải toàn bộ chuỗi trong trường văn bản, do đó, regex có thể không khớp chính xác. Ví dụ: tôi đang sử dụng lệnh này như vậy: text.matches("\\d+"); và tôi không thể xóa bất kỳ ký tự nào trong trường văn bản
mils

1
@mils Nhìn ở đâyở đây .
vellotis

1
Tôi nghĩ rằng đây là một giải pháp tốt, nhưng tôi sẽ thay đổi một điều. Thay vì viết text.matches ("[0-9] *"), tôi sẽ tạo biến cho mẫu và biên dịch nó. Trong mã của bạn, mẫu mã được biên dịch mỗi khi ai đó viết ký tự vào một trường và điều này gây tốn kém cho CPU và bộ nhớ. Vì vậy, tôi sẽ thêm biến: private static Pattern integerPattern = Pattern.compile ("[0-9] *"); Và thay thế xác thực nội dung bằng: integerPattern.matcher (text) .matches ();
P. Jowko

38

Bắt đầu với JavaFX 8u40, bạn có thể đặt đối tượng TextFormatter trên trường văn bản:

UnaryOperator<Change> filter = change -> {
    String text = change.getText();

    if (text.matches("[0-9]*")) {
        return change;
    }

    return null;
};
TextFormatter<String> textFormatter = new TextFormatter<>(filter);
fieldNport = new TextField();
fieldNport.setTextFormatter(textFormatter);

Điều này tránh được cả sự kiện thay đổi phân lớp và trùng lặp mà bạn sẽ nhận được khi thêm trình xử lý thay đổi vào thuộc tính văn bản và sửa đổi văn bản trong trình nghe đó.


30

Các TextInputcó một TextFormattermà có thể được sử dụng để định dạng, chuyển đổi và hạn chế các loại văn bản có thể được nhập vào.

TextFormattermột bộ lọc có thể được sử dụng để từ chối đầu vào. Chúng ta cần đặt điều này để từ chối bất kỳ thứ gì không phải là số nguyên hợp lệ. Nó cũng có một bộ chuyển đổi mà chúng ta cần thiết lập để chuyển đổi giá trị chuỗi thành một giá trị số nguyên mà chúng ta có thể liên kết sau này.

Cho phép tạo một bộ lọc có thể sử dụng lại:

public class IntegerFilter implements UnaryOperator<TextFormatter.Change> {
    private final static Pattern DIGIT_PATTERN = Pattern.compile("\\d*");

    @Override
    public Change apply(TextFormatter.Change aT) {
        return DIGIT_PATTERN.matcher(aT.getText()).matches() ? aT : null;
    }
}

Bộ lọc có thể thực hiện một trong ba điều, nó có thể trả về thay đổi chưa được sửa đổi để chấp nhận nó như cũ, nó có thể thay đổi thay đổi theo một cách nào đó mà nó cho là phù hợp hoặc nó có thể quay lại nullđể từ chối tất cả thay đổi.

Chúng tôi sẽ sử dụng tiêu chuẩn IntegerStringConverterlàm công cụ chuyển đổi.

Kết hợp tất cả lại với nhau chúng ta có:

TextField textField = ...;

TextFormatter<Integer> formatter = new TextFormatter<>(
    new IntegerStringConverter(), // Standard converter form JavaFX
    defaultValue, 
    new IntegerFilter());
formatter.valueProperty().bindBidirectional(myIntegerProperty);

textField.setTextFormatter(formatter);

Nếu bạn muốn không cần bộ lọc có thể tái sử dụng, bạn có thể thực hiện thay thế một lớp lót ưa thích này:

TextFormatter<Integer> formatter = new TextFormatter<>(
    new IntegerStringConverter(), 
    defaultValue,  
    c -> Pattern.matches("\\d*", c.getText()) ? c : null );

21

Tôi không thích ngoại lệ vì vậy tôi đã sử dụng matcheshàm từ String-Class

text.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, 
        String newValue) {
        if (newValue.matches("\\d*")) {
            int value = Integer.parseInt(newValue);
        } else {
            text.setText(oldValue);
        }
    }
});

1
đôi khi bạn có một ngoại lệ, vì hạt nhân có thể quá lớn.
schlagi123

1
Mẹo: thay thế regex "\\ d +" thành "\\ d *". Điều này sẽ cho phép bạn xóa tất cả các ký tự khỏi trường nhập văn bản (sử dụng phím xóa / xóa lùi để xóa trường).
Guus

1
Đừng quên thiết lập vị trí dấu mũ sau khi đặt nó trở lại giá trị cũ:textField.positionCaret(textField.getLength());
hsson 27/01

Thay đổi điều kiện nắm tay if thành: if (newValue.matches("\\d*") && newValue.getText().length < 5) nếu bạn muốn giới hạn đầu vào là 4 chữ số trong trường hợp này.
Cappuccino 90

@ Cappuccino90 Bạn nên chuyển các báo cáo vì kiểm tra chiều dài là rẻ hơn nhiều trên mỗi hit hơn một phân tích cú pháp regex
thatsIch

9

Bắt đầu từ Java SE 8u40 , đối với nhu cầu như vậy, bạn có thể sử dụng " số nguyên " Spinnercho phép chọn một số nguyên hợp lệ một cách an toàn bằng cách sử dụng các phím mũi tên lên / xuống của bàn phím hoặc các nút mũi tên lên / xuống được cung cấp.

Bạn cũng có thể xác định giá trị tối thiểu , tối đa và giá trị ban đầu để giới hạn các giá trị được phép và số tiền tăng hoặc giảm theo từng bước.

Ví dụ

// Creates an integer spinner with 1 as min, 10 as max and 2 as initial value
Spinner<Integer> spinner1 = new Spinner<>(1, 10, 2);
// Creates an integer spinner with 0 as min, 100 as max and 10 as initial 
// value and 10 as amount to increment or decrement by, per step
Spinner<Integer> spinner2 = new Spinner<>(0, 100, 10, 10);

Ví dụ về kết quả với một con quay " số nguyên " và một con quay " kép "

nhập mô tả hình ảnh ở đây

Một spinner là một single-line kiểm soát lĩnh vực văn bản cho phép người dùng chọn một số hoặc một giá trị đối tượng từ một chuỗi các lệnh giá trị như vậy. Spinners thường cung cấp một cặp nút mũi tên nhỏ để lướt qua các phần tử của chuỗi. Các phím mũi tên lên / xuống của bàn phím cũng xoay vòng qua các phần tử. Người dùng cũng có thể được phép nhập giá trị (hợp pháp) trực tiếp vào trình quay. Mặc dù các hộp kết hợp cung cấp chức năng tương tự, các trình quay vòng đôi khi được ưa thích hơn vì chúng không yêu cầu danh sách thả xuống có thể che khuất dữ liệu quan trọng và cũng vì chúng cho phép các tính năng như gói từ giá trị lớn nhất trở lại giá trị nhỏ nhất (ví dụ: từ số nguyên dương lớn nhất đến 0).

Thêm chi tiết về điều khiển Spinner


Mọi người không nên con quay không xác thực đối với mục nhập văn bản hoặc bị mất tiêu điểm
hình học

7

Câu trả lời được ưu tiên thậm chí có thể nhỏ hơn nếu bạn sử dụng Java 1.8 Lambdas

textfield.textProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue.matches("\\d*")) return;
    textfield.setText(newValue.replaceAll("[^\\d]", ""));
});

6
TextField text = new TextField();

text.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable,
            String oldValue, String newValue) {
        try {
            Integer.parseInt(newValue);
            if (newValue.endsWith("f") || newValue.endsWith("d")) {
                manualPriceInput.setText(newValue.substring(0, newValue.length()-1));
            }
        } catch (ParseException e) {
            text.setText(oldValue);
        }
    }
});

Các ifđiều khoản rất quan trọng để xử lý nguyên liệu đầu vào như 0.5ngày hoặc 0.7f được phân tích một cách chính xác bởi Int.parseInt (), nhưng không nên xuất hiện trong lĩnh vực văn bản.


9
Woot? Vì khi nào 0,5d được phân tích cú pháp chính xác bởi Integer.parseInt () ?! Nó ném một java.lang.NumberFormatException: Đối với chuỗi đầu vào: "0.5ngày" (như mong đợi, vì nó không phải là một Integer)
Burkhard

4

Hãy thử mã đơn giản này, nó sẽ thực hiện công việc.

DecimalFormat format = new DecimalFormat( "#.0" );
TextField field = new TextField();
field.setTextFormatter( new TextFormatter<>(c ->
{
    if ( c.getControlNewText().isEmpty() )
    {
        return c;
    }

    ParsePosition parsePosition = new ParsePosition( 0 );
    Object object = format.parse( c.getControlNewText(), parsePosition );

    if ( object == null || parsePosition.getIndex() <          c.getControlNewText().length() )
    {
        return null;
    }
    else
    {
        return c;
    }
}));

3

Nếu bạn muốn áp dụng cùng một trình nghe cho nhiều hơn một TextField thì đây là giải pháp đơn giản nhất:

TextField txtMinPrice, txtMaxPrice = new TextField();

ChangeListener<String> forceNumberListener = (observable, oldValue, newValue) -> {
    if (!newValue.matches("\\d*"))
      ((StringProperty) observable).set(oldValue);
};

txtMinPrice.textProperty().addListener(forceNumberListener);
txtMaxPrice.textProperty().addListener(forceNumberListener);

3

Điều này đã làm việc cho tôi.

public void RestrictNumbersOnly(TextField tf){
    tf.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, 
            String newValue) {
            if (!newValue.matches("|[-\\+]?|[-\\+]?\\d+\\.?|[-\\+]?\\d+\\.?\\d+")){
                tf.setText(oldValue);
            }
        }
    });
}

3

Tôi muốn trợ giúp ý tưởng của mình từ việc kết hợp câu trả lời Evan Knowles với TextFormattertừ JavaFX 8

textField.setTextFormatter(new TextFormatter<>(c -> {
    if (!c.getControlNewText().matches("\\d*")) 
        return null;
    else
        return c;
    }
));

chúc may mắn;) hãy bình tĩnh và code java


2

Đây là một lớp đơn giản xử lý một số xác thực cơ bản TextField, sử dụng được TextFormattergiới thiệu trong JavaFX 8u40

BIÊN TẬP:

(Mã được thêm vào bình luận của Floern)

import java.text.DecimalFormatSymbols;
import java.util.regex.Pattern;

import javafx.beans.NamedArg;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;

public class TextFieldValidator {

    private static final String CURRENCY_SYMBOL   = DecimalFormatSymbols.getInstance().getCurrencySymbol();
    private static final char   DECIMAL_SEPARATOR = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    private final Pattern       INPUT_PATTERN;

    public TextFieldValidator(@NamedArg("modus") ValidationModus modus, @NamedArg("countOf") int countOf) {
        this(modus.createPattern(countOf));
    }

    public TextFieldValidator(@NamedArg("regex") String regex) {
        this(Pattern.compile(regex));
    }

    public TextFieldValidator(Pattern inputPattern) {
        INPUT_PATTERN = inputPattern;
    }

    public static TextFieldValidator maxFractionDigits(int countOf) {
        return new TextFieldValidator(maxFractionPattern(countOf));
    }

    public static TextFieldValidator maxIntegers(int countOf) {
        return new TextFieldValidator(maxIntegerPattern(countOf));
    }

    public static TextFieldValidator integersOnly() {
        return new TextFieldValidator(integersOnlyPattern());
    }

    public TextFormatter<Object> getFormatter() {
        return new TextFormatter<>(this::validateChange);
    }

    private Change validateChange(Change c) {
        if (validate(c.getControlNewText())) {
            return c;
        }
        return null;
    }

    public boolean validate(String input) {
        return INPUT_PATTERN.matcher(input).matches();
    }

    private static Pattern maxFractionPattern(int countOf) {
        return Pattern.compile("\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + countOf + "})?");
    }

    private static Pattern maxCurrencyFractionPattern(int countOf) {
        return Pattern.compile("^\\" + CURRENCY_SYMBOL + "?\\s?\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + countOf + "})?\\s?\\" +
                CURRENCY_SYMBOL + "?");
    }

    private static Pattern maxIntegerPattern(int countOf) {
        return Pattern.compile("\\d{0," + countOf + "}");
    }

    private static Pattern integersOnlyPattern() {
        return Pattern.compile("\\d*");
    }

    public enum ValidationModus {

        MAX_CURRENCY_FRACTION_DIGITS {
            @Override
            public Pattern createPattern(int countOf) {
                return maxCurrencyFractionPattern(countOf);
            }
        },

        MAX_FRACTION_DIGITS {
            @Override
            public Pattern createPattern(int countOf) {
                return maxFractionPattern(countOf);
            }
        },
        MAX_INTEGERS {
            @Override
            public Pattern createPattern(int countOf) {
                return maxIntegerPattern(countOf);
            }
        },

        INTEGERS_ONLY {
            @Override
            public Pattern createPattern(int countOf) {
                return integersOnlyPattern();
            }
        };

        public abstract Pattern createPattern(int countOf);
    }

}

Bạn có thể sử dụng nó như thế này:

textField.setTextFormatter(new TextFieldValidator(ValidationModus.INTEGERS_ONLY).getFormatter());

hoặc bạn có thể khởi tạo nó trong một tệp fxml và áp dụng nó vào một customTextField với các thuộc tính tương ứng.

app.fxml:

<fx:define>
    <TextFieldValidator fx:id="validator" modus="INTEGERS_ONLY"/>
</fx:define>

CustomTextField.class:

public class CustomTextField {

private TextField textField;

public CustomTextField(@NamedArg("validator") TextFieldValidator validator) {
        this();
        textField.setTextFormatter(validator.getFormatter());
    }
}

Mã trên github


2

Đây là những gì tôi sử dụng:

private TextField textField;
textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        if(!newValue.matches("[0-9]*")){
            textField.setText(oldValue);
        }

    }
});

Tương tự trong ký hiệu lambda sẽ là:

private TextField textField;
textField.textProperty().addListener((observable, oldValue, newValue) -> {
    if(!newValue.matches("[0-9]*")){
        textField.setText(oldValue);
    }
});

2

Phương thức này cho phép TextField hoàn tất tất cả quá trình xử lý (sao chép / dán / hoàn tác an toàn). Không yêu cầu mở rộng các lớp và cho phép bạn quyết định phải làm gì với văn bản mới sau mỗi thay đổi (để đẩy nó về logic, hoặc quay trở lại giá trị trước đó hoặc thậm chí để sửa đổi nó).

  // fired by every text property change
textField.textProperty().addListener(
  (observable, oldValue, newValue) -> {
    // Your validation rules, anything you like
      // (! note 1 !) make sure that empty string (newValue.equals("")) 
      //   or initial text is always valid
      //   to prevent inifinity cycle
    // do whatever you want with newValue

    // If newValue is not valid for your rules
    ((StringProperty)observable).setValue(oldValue);
      // (! note 2 !) do not bind textProperty (textProperty().bind(someProperty))
      //   to anything in your code.  TextProperty implementation
      //   of StringProperty in TextFieldControl
      //   will throw RuntimeException in this case on setValue(string) call.
      //   Or catch and handle this exception.

    // If you want to change something in text
      // When it is valid for you with some changes that can be automated.
      // For example change it to upper case
    ((StringProperty)observable).setValue(newValue.toUpperCase());
  }
);

Đối với trường hợp của bạn, chỉ cần thêm logic này vào bên trong. Hoạt động hoàn hảo.

   if (newValue.equals("")) return; 
   try {
     Integer i = Integer.valueOf(newValue);
     // do what you want with this i
   } catch (Exception e) {
     ((StringProperty)observable).setValue(oldValue);
   }

0

Ừm. Tôi đã gặp phải vấn đề đó vài tuần trước. Vì API không cung cấp kiểm soát để đạt được điều đó,
bạn có thể muốn sử dụng API của riêng mình.
Tôi đã sử dụng một cái gì đó như:

public class IntegerBox extends TextBox {
    public-init var value : Integer = 0;
    protected function apply() {
        try {
            value = Integer.parseInt(text);
        } catch (e : NumberFormatException) {}
        text = "{value}";
    }
    override var focused = false on replace {apply()};
    override var action = function () {apply()}
}

Nó được sử dụng giống như cách thông thường TextBox,
nhưng cũng có một valuethuộc tính lưu trữ số nguyên đã nhập.
Khi điều khiển mất tiêu điểm, nó xác nhận giá trị và hoàn nguyên (nếu không hợp lệ).


2
đây là ngôn ngữ gì
Stealth Rabbi

Đó là JavaFX Script Rabbi, nó đã lỗi thời .
jewelsea

0

Mã này Tạo văn bản của bạn Trường Chỉ chấp nhận Số

textField.lengthProperty().addListener((observable, oldValue, newValue) -> {
        if(newValue.intValue() > oldValue.intValue()){
            char c = textField.getText().charAt(oldValue.intValue());
            /** Check if the new character is the number or other's */
            if( c > '9' || c < '0'){
                /** if it's not number then just setText to previous one */
                textField.setText(textField.getText().substring(0,textField.getText().length()-1));
            }
        }
    });

0

Mã này hoạt động tốt đối với tôi ngay cả khi bạn cố gắng sao chép / dán.

myTextField.textProperty().addListener((observable, oldValue, newValue) -> {
    if (!newValue.matches("\\d*")) {
        myTextField.setText(oldValue);

    }
});

-1

Trong các bản cập nhật gần đây của JavaFX, bạn phải đặt văn bản mới trong phương thức Platform.runLater giống như sau:

    private void set_normal_number(TextField textField, String oldValue, String newValue) {
    try {
        int p = textField.getCaretPosition();
        if (!newValue.matches("\\d*")) {
            Platform.runLater(() -> {
                textField.setText(newValue.replaceAll("[^\\d]", ""));
                textField.positionCaret(p);
            });
        }
    } catch (Exception e) {
    }
}

Bạn cũng nên đặt vị trí dấu mũ.


1
Cảm ơn về câu trả lời của bạn! Bạn có thể giải thích một chút tại sao lại Platform.runLatercần thiết?
TuringTux

@TuringTux trong phiên bản gần đây của JavaFX, nó sẽ ném ngoại lệ nếu bạn không sử dụng Platform.runLater
bdshahab

-1

Tôi muốn cải thiện câu trả lời của Evan Knowles: https://stackoverflow.com/a/30796829/2628125

Trong trường hợp của tôi, tôi có lớp với các trình xử lý cho phần Thành phần giao diện người dùng. Khởi tạo:

this.dataText.textProperty().addListener((observable, oldValue, newValue) -> this.numericSanitization(observable, oldValue, newValue));

Và phương pháp numbericSanitization:

private synchronized void numericSanitization(ObservableValue<? extends String> observable, String oldValue, String newValue) {
    final String allowedPattern = "\\d*";

    if (!newValue.matches(allowedPattern)) {
        this.dataText.setText(oldValue);
    }
}

Từ khóa được đồng bộ hóa được thêm vào để ngăn chặn sự cố khóa hiển thị có thể xảy ra trong javafx nếu setText sẽ được gọi trước khi tệp cũ kết thúc thực thi. Nó rất dễ dàng để tái tạo nếu bạn bắt đầu gõ sai ký tự rất nhanh.

Một lợi thế khác là bạn chỉ giữ một mẫu để phù hợp và chỉ cần thực hiện quay lui. Sẽ tốt hơn vì bạn có thể dễ dàng rút gọn dung dịch cho các mẫu vệ sinh khác nhau.


-1
rate_text.textProperty().addListener(new ChangeListener<String>() {

    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        String s="";
        for(char c : newValue.toCharArray()){
            if(((int)c >= 48 && (int)c <= 57 || (int)c == 46)){
                s+=c;
            }
        }
        rate_text.setText(s);
    }
});

Điều này hoạt động tốt vì nó cho phép bạn chỉ nhập giá trị số nguyên và giá trị thập phân (có mã ASCII 46).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.