Подтвердить что ты не робот

Как реализовать NumberField в javaFX 2.0?

Мне нужно вставить числовое поле в свой пользовательский интерфейс. Поэтому мне нужно проверить ключевые события в текстовом поле, чтобы проверить, является ли входной символ числом. Я создал класс, расширив TextField. Если в классе TextField есть метод, который обрабатывает keyEvents, я могу просто переопределить этот метод с помощью костюмов в поле чисел. Любые идеи?

Спасибо

4b9b3361

Ответ 1

Найден решение.:)

public class NumFieldFX extends TextField {
   public NumFieldFX() {
      this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
         public void handle( KeyEvent t ) {
            char ar[] = t.getCharacter().toCharArray();
            char ch = ar[t.getCharacter().toCharArray().length - 1];
            if (!(ch >= '0' && ch <= '9')) {
               System.out.println("The char you entered is not a number");
               t.consume();
            }
         }
      });
   }
}

Ответ 2

Обновление 27 мая 2016 года

Java 8u40 представила класс TextFormatter, который является рекомендуемым способом выполнения этой функции (хотя решение, предоставленное в этом ответе, будет по-прежнему Работа). Для получения дополнительной информации см. Uwe answer, Hassan answer и другие ответы, в которых упоминается TextFormatter на следующий вопрос:

Существует также это решение из другого ответа на этот вопрос, который я не пробовал, но выглядит хорошо, и модератор StackOverflow удален:

TextField numberField = new TextField();
numberField.setTextFormatter(new TextFormatter<>(new NumberStringConverter()));

Приведенный выше код пропускает фильтр UnaryOperator для TextFormatter, который вам обычно также требуется (в противном случае поле не будет отображать ограничивать ввод пользователя только форматированным значением, оно просто позволит вам отслеживать неформатированное значение через текст formatters value). Чтобы расширить решение для использования фильтра, можно использовать следующий код:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.stage.Stage;
import javafx.util.converter.NumberStringConverter;

import java.text.ParsePosition;
import java.util.function.UnaryOperator;

public class NumberConverterFieldTest extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        TextField numberField = new TextField();
        NumberStringFilteredConverter converter = new NumberStringFilteredConverter();
        final TextFormatter<Number> formatter = new TextFormatter<>(
                converter,
                0,
                converter.getFilter()
        );

        numberField.setTextFormatter(formatter);

        formatter.valueProperty().addListener((observable, oldValue, newValue) ->
                System.out.println(newValue)
        );

        stage.setScene(new Scene(numberField));
        stage.show();
    }

    class NumberStringFilteredConverter extends NumberStringConverter {
        // Note, if needed you can add in appropriate constructors 
        // here to set locale, pattern matching or an explicit
        // type of NumberFormat.
        // 
        // For more information on format control, see 
        //    the NumberStringConverter constructors
        //    DecimalFormat class 
        //    NumberFormat static methods for examples.
        // This solution can instead extend other NumberStringConverters if needed
        //    e.g. CurrencyStringConverter or PercentageStringConverter.

        public UnaryOperator<TextFormatter.Change> getFilter() {
            return change -> {
                String newText = change.getControlNewText();
                if (newText.isEmpty()) {
                    return change;
                }

                ParsePosition parsePosition = new ParsePosition( 0 );
                Object object = getNumberFormat().parse( newText, parsePosition );
                if ( object == null || parsePosition.getIndex() < newText.length()) {
                    return null;
                } else {
                    return change;
                }
            };
        }
    }
}

При выполнении приведенного выше примера отредактируйте поле ввода и нажмите клавишу ввода, чтобы увидеть обновленное значение (обновленное значение выводится на System.out при изменении).

Для учебника см.:


Это то же самое решение, которое ссылается на Urs, однако я просто поместил его в полностью исполняемую программу, чтобы предоставить пример в контексте и изменить регулярное выражение (добавив * в конец), чтобы копировать и вставлять и это не проблема, о которой говорит Улук. Решение кажется довольно простым и, скорее всего, будет достаточным для большинства целей:

import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

public class NumericTextFieldTest extends Application {
  public static void main(String[] args) { launch(args); }

  @Override public void start(Stage stage) {
    TextField numberField = new TextField() {
      @Override public void replaceText(int start, int end, String text) {
        if (text.matches("[0-9]*")) {
          super.replaceText(start, end, text);
        }
      }

      @Override public void replaceSelection(String text) {
        if (text.matches("[0-9]*")) {
          super.replaceSelection(text);
        }
      }
    };

    stage.setScene(new Scene(numberField));
    stage.show();
  }
}

Альтернативные решения

Вы также можете быть заинтересованы в моем альтернативном решении в Пример JavaFX привязки значения ползунка к редактируемому TextField. В этом решении я расширяю TextField, чтобы выдать IntegerProperty в поле для простых целей привязки. Альтернативное решение похоже на то, которое описано в оригинальном плакате в их обновленном вопросе (т.е. Фильтр событий добавляется для ограничения входных данных из ключевых событий), но дополнительно к свойствам TextField добавляется ChangeListener, чтобы гарантировать, что скопированные и вставленные значения принимаются только в том случае, если они являются числовыми.

Есть несколько других решений этого вопроса в теме форума JavaFX Числовое текстовое поле в JavaFX 2.0?, которое включает ссылку на числовые поля из элементов управления FXExperience.

Ответ 3

В FXExperience, в котором рассматривается проблема. Чтобы перефразировать, вы расширяете TextField и переопределяете методы replaceText() и replaceSelection(), фильтруя весь вход, который не является числом.

После внедрения оба метода должны следовать этому шаблону:

if (!newText.matches("[0-9]")) {
    super.call(allParams)
}

Ответ 4

Вот поле CustomText, которое я написал. Он обрабатывает только ввод чисел, а также maximumSize. Его собственный элемент управления, который можно использовать в FXML, а также свойства можно установить в самом FXMl.

package fxml;

import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.IntegerPropertyBase;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.TextField;

public class CustomTextField extends TextField {

/**
 * numericOnly property if set, will allow accept only numeric input.
 */
private BooleanProperty numericOnly = new SimpleBooleanProperty(this,
        "numericOnly", false);

public final boolean isNumericOnly() {
    return numericOnly.getValue();
}

public final void setNumericOnly(boolean value) {
    numericOnly.setValue(value);
}

public final BooleanProperty numericOnlyProperty() {
    return numericOnly;
}

/**
 * maxSize property , determines the maximum size of the text that can be
 * input.
 */
public IntegerProperty maxSize = new IntegerPropertyBase(1000) {

    @Override
    public String getName() {
        return "maxSize";
    }

    @Override
    public Object getBean() {
        return CustomTextField.this;
    }
};

public final IntegerProperty maxSizeProperty() {
    return maxSize;
};

public final int getMaxSize() {
    return maxSize.getValue();
}

public final void setMaxSize(int value) {
    maxSize.setValue(value);
}

/**
 * this method is called when user inputs text into the textField
 */
@Override
public void replaceText(int start, int end, String text) {
    if (numericOnly.getValue() && !text.equals("")) {
        if (!text.matches("[0-9]")) {
            return;
        }
    }
    if (getText().length() < getMaxSize() || text.equals("")) {
        super.replaceText(start, end, text);
    }
}

/**
 * this method is called when user pastes text into the textField
 */
@Override
public void replaceSelection(String text) {
    if (numericOnly.getValue() && !text.equals("")) {
        if (!text.matches("[0-9]+")) {
            return;
        }
    }
    super.replaceSelection(text);
    if (getText().length() > getMaxSize()) {
        String maxSubString = getText().substring(0, getMaxSize());
        setText(maxSubString);
        positionCaret(getMaxSize());
    }
}

}

Ответ 5

Для нескольких текстовых файлов (включая десятичную точку)

Arrays.asList(txtLongitude, txtLatitude, txtAltitude, txtSpeed, txtOrientation).forEach(textField ->
            textField.textProperty().addListener((observable, oldValue, newValue) ->
                    textField.setText(newValue.matches("^[0-9]*\\.?[0-9]*$") ? newValue : oldValue)
            ));

Ответ 6

Наследовать от TextField и переопределить replaceText как таковой, чтобы получить только значения Double TextField:

@Override
public void replaceText(int start, int end, String text) {
    String preText = getText(0, start);
    String afterText = getText(end, getLength());
    String toBeEnteredText = preText + text + afterText;

    // Treat the case where the user inputs proper text and is not inputting backspaces or other control characters
    // which would be represented by an empty text argument:
    if (!text.isEmpty() && text.matches("\\d|\\.")) {
        Logger.getAnonymousLogger().info("Paring non-empty.");
        try {
            Logger.getAnonymousLogger().info("Parsing " + toBeEnteredText);
            Double.parseDouble(toBeEnteredText);
            super.replaceText(start, end, text);
        } catch (Exception ignored) {
        }
    }

    // If the user used backspace or del, the result text is impossible to not parse as a Double/Integer so just
    // enter that text right ahead:
    if (text.isEmpty()) {
        super.replaceText(start, end, text);
    }
}