Question

Je dois insérer un champ de numéro dans mon interface utilisateur. Donc, je dois vérifier les événements clés sur un champ de texte afin de vérifier si le caractère d'entrée est un nombre. J'ai créé une classe en étendant TextField. S'il existe une méthode dans la classe TextField qui gère KeyEvents, je peux simplement overide cette méthode avec des costumes à champ numérique. Toutes les idées?

Merci

Était-ce utile?

La solution 4

trouvé une solution. :)

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();
            }
         }
      });
   }
}

Autres conseils

Mise à jour le 27 mai 2016

Java 8u40 a introduit le TextFormatter classe qui est la méthode recommandée pour accomplir cette fonctionnalité (bien que la solution proposée dans cette réponse sera encore du travail). Pour plus d'informations, consultez Uwe de réponse, réponse de Hassan et d'autres réponses mentionnant TextFormatter à la question suivante:

Il y a aussi cette solution d'une autre réponse à cette question que je ne l'ai pas essayé, mais semble bon et un modérateur StackOverflow supprimé:

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

Le code ci-dessus misses le filtre UnaryOperator pour le TextFormatter qui vous habituellement besoin aussi (sinon, le champ ne sera pas afficher limiter les entrées utilisateur à la seule valeur formatée, il va simplement vous permettre de surveiller la valeur non formatée par le texte formatteurs Valeur de la propriété). Pour étendre la solution à utiliser un filtre, le code comme celui ci-dessous peut être utilisé:

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;
                }
            };
        }
    }
}

Lorsque vous exécutez l'exemple ci-dessus, modifier le champ de saisie et appuyez sur la touche Entrée pour voir la valeur actualisée (valeur actualisée est sortie System.out lorsque changé).

Pour un tutoriel voir:


Ceci est la même solution que les références Urs, mais je viens de mettre dans un programme entièrement exécutable pour fournir un exemple dans son contexte et modifié l'expression régulière (en ajoutant * à la fin) de telle sorte que copier-coller fonctionne et ne pas la question Uluk fait référence. La solution semble assez simple et sera probablement suffisant pour la plupart des cas:

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();
  }
}

Solutions alternatives

Vous pourriez également être intéressé par ma solution de rechange JavaFX exemple de lier une valeur de curseur pour un champ de texte modifiable . Dans cette solution, je tiens TextField d'exposer une IntegerProperty sur le terrain à des fins de liaison de simples. La solution alternative est similaire à celle décrite par l'auteur original dans leur question mise à jour (par exemple un filtre d'événement est ajouté à limiter les données d'entrée des événements clés), mais en plus un ChangeListener est ajouté sur la propriété de texte TextField pour faire en sorte que copier et empâtées valeurs ne sont acceptées que si elles sont numériques.

Il existe d'autres solutions à cette question dans le fil Forum JavaFX numérique Textfield dans JavaFX 2.0? qui inclut une référence au champs nombre de contrôles FXExperience .

Il y a une astuce sur FXExperience qui traite une question comme ça. Pour paraphraser, vous étendez la TextField et passer outre les méthodes de replaceText() et replaceSelection(), filtrer toutes les entrées qui ne sont pas un nombre.

Une fois mis en œuvre, les deux méthodes devraient suivre ce modèle:

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

Voici le champ customText je l'ai écrit. Il gère les deux numéros que entrée et aussi maximumSize. Son un contrôle personnalisé qui peut être utilisé dans FXML et aussi les propriétés peuvent être définies dans FXML lui-même.

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());
    }
}

}

Pour un certain nombre de champs texte (y compris le point décimal)

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)
            ));

solution combinée BaiJiFeiLong et AJAY PRAKASH pour supporter des entrées décimales

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());
        }
    }
}

TextField et override replaceText en tant que tel, pour obtenir une valeur double uniquement 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);
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top