Как реализовать NumberField в javaFX 2.0? - PullRequest
20 голосов
/ 05 декабря 2011

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

Спасибо

Ответы [ 7 ]

14 голосов
/ 15 мая 2013

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

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

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

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

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

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 при изменении).

Обучающее руководство см .:


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

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 голосов
/ 03 мая 2012

Существует подсказка по FXExperience , которая решает такую ​​же проблему.Перефразируя, вы расширяете TextField и переопределяете методы replaceText() и replaceSelection(), фильтруя все входные данные, которые не являются числами.

После реализации оба метода должны следовать следующему шаблону:

if (!newText.matches("[0-9]")) {
    super.call(allParams)
}
2 голосов
/ 24 августа 2016

Для числа TextFiled (включая десятичную точку)

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)
            ));
2 голосов
/ 10 декабря 2015

Нашел решение. :)

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 голосов
/ 29 мая 2013

Вот поле 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());
    }
}

}

1 голос
/ 08 мая 2018

Комбинированное решение BaiJiFeiLong и AJAY PRAKASH для поддержки десятичных входных данных

package com.mazeworks.cloudhms.view.components;

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 NumericTextField 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 NumericTextField.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]*\\.?[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]*\\.?[0-9]*$")) {
                return;
            }
        }
        super.replaceSelection(text);
        if (getText().length() > getMaxSize()) {
            String maxSubString = getText().substring(0, getMaxSize());
            setText(maxSubString);
            positionCaret(getMaxSize());
        }
    }
}
0 голосов
/ 15 сентября 2015

Наследование от 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);
    }
}
...