web-dev-qa-db-fra.com

Contrôle des entrées au clavier dans javafx TextField

Je souhaite contrôler l'entrée dans un Javafx TextField afin de ne permettre que la saisie numérique. Ainsi, si le nombre maximal de caractères est dépassé, aucune modification ne sera apportée à la zone de texte.

edit: Basé sur une recommandation dans les commentaires, j’ai utilisé la méthode suggérée par le responsable de projet JavaFX. Cela fonctionne bien pour empêcher les lettres d'entrer. J'en ai juste besoin pour filtrer également les caractères spéciaux. J'ai essayé de changer le filtre en (text.matchs ("[0-9]") mais cela ne permettait pas de revenir en arrière.

edit2: créé un filtre sur les caractères spéciaux et la longueur. Voici mon code final. Merci pour la contribution des gars.

Voici la classe TextField que j'ai créée:

import javafx.scene.control.TextField;

public class AttributeTextField extends TextField{

    public AttributeTextField() {
        setMinWidth(25);
        setMaxWidth(25);
    }

    public void replaceText(int start, int end, String text) {
        String oldValue = getText();
        if (!text.matches("[a-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceText(start, end, text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }

    public void replaceSelection(String text) {
        String oldValue = getText();
        if (!text.matches("[a-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceSelection(text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }
}

Note: J'ai lu Quelle est la méthode recommandée pour créer un TextField numérique en JavaFX? ce post, et cette solution ne fonctionne pas pour moi. Il ne se déclenche que lorsque le numéro a été entré. Cela signifie que quelqu'un peut taper du texte alphabétique dans la zone, ce qui le permettrait jusqu'à ce que le focus soit détourné du champ de texte. En outre, ils peuvent entrer des nombres plus grands que ceux autorisés, mais la validation ne se produit pas à chaque pression de touche, mais après le décalage de la mise au point (événement 'changé').

9
Damienknight

Solution finale. Interdit les caractères alphabétiques et spéciaux et applique la limite de caractères.

import javafx.scene.control.TextField;

public class AttributeTextField extends TextField{

    public AttributeTextField() {
        setMinWidth(25);
        setMaxWidth(25);
    }

    public void replaceText(int start, int end, String text) {
        String oldValue = getText();
        if (!text.matches("[A-Za-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceText(start, end, text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }

    public void replaceSelection(String text) {
        String oldValue = getText();
        if (!text.matches("[A-Za-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceSelection(text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }
}
2
Damienknight

le meilleur moyen est:

    @FXML
private TextField txt_Numeric;
@FXML
private TextField txt_Letters;

@Override
public void initialize(URL url, ResourceBundle rb) {
    /* add Event Filter to your TextFields **************************************************/
    txt_Numeric.addEventFilter(KeyEvent.KEY_TYPED , numeric_Validation(10));
    txt_Letters.addEventFilter(KeyEvent.KEY_TYPED , letter_Validation(10));
}

/* Numeric Validation Limit the  characters to maxLengh AND to ONLY DigitS *************************************/
public EventHandler<KeyEvent> numeric_Validation(final Integer max_Lengh) {
    return new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent e) {
            TextField txt_TextField = (TextField) e.getSource();                
            if (txt_TextField.getText().length() >= max_Lengh) {                    
                e.consume();
            }
            if(e.getCharacter().matches("[0-9.]")){ 
                if(txt_TextField.getText().contains(".") && e.getCharacter().matches("[.]")){
                    e.consume();
                }else if(txt_TextField.getText().length() == 0 && e.getCharacter().matches("[.]")){
                    e.consume(); 
                }
            }else{
                e.consume();
            }
        }
    };
}    
/*****************************************************************************************/

 /* Letters Validation Limit the  characters to maxLengh AND to ONLY Letters *************************************/
public EventHandler<KeyEvent> letter_Validation(final Integer max_Lengh) {
    return new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent e) {
            TextField txt_TextField = (TextField) e.getSource();                
            if (txt_TextField.getText().length() >= max_Lengh) {                    
                e.consume();
            }
            if(e.getCharacter().matches("[A-Za-z]")){ 
            }else{
                e.consume();
            }
        }
    };
}    
/*****************************************************************************************/

Bonne chance.

8
MagicJ

Voici mon approche, deux filtres d’événement, qui pourrait être un, dans mon cas, je les ai utilisés dans différentes situations, c’est pourquoi il y en a deux.

Voici le maxValueFilter (en spanglish xD), celui-ci est une classe:

public class FilterMaxValue implements EventHandler<KeyEvent> {

        private int maxVal;

        public FilterMaxValue (int i) {
            this.maxVal= i;
        }

        public void handle(KeyEvent arg0) {

            TextField tx = (TextField) arg0.getSource();
            String chara = arg0.getCharacter();
            if (tx.getText().equals(""))
                return;

            Double valor;
            if (chara.equals(".")) {
                valor = Double.parseDouble(tx.getText() + chara + "0");
            } else {
                try {
                    valor = Double.parseDouble(tx.getText() + chara);
                } catch (NumberFormatException e) {
                    //The other filter will prevent this from hapening
                    return;
                }
            }
            if (valor > maxVal) {
                arg0.consume();
            }

        }
    }

Et l’autre filtre d’événement (filtre les caractères), c’est une méthode:

public static EventHandler<KeyEvent> numFilter() {

        EventHandler<KeyEvent> aux = new EventHandler<KeyEvent>() {
            public void handle(KeyEvent keyEvent) {
                if (!"0123456789".contains(keyEvent.getCharacter())) {
                    keyEvent.consume();

                }
            }
        };
        return aux;
    }

l'utilisation dans votre cas serait:

field.addEventFilter(KeyEvent.KEY_TYPED,
                numFilter());
field.addEventFilter(KeyEvent.KEY_TYPED, new FiltroValorMaximo(
                99));
4
Magcus

Je définis simplement l'événement 'On Key Typed' pour exécuter cette petite procédure:

    @FXML public void processKeyEvent(KeyEvent ev) {
    String c = ev.getCharacter();
    if("1234567890".contains(c)) {}
    else {
        ev.consume();
    }
}

Cela fonctionne comme un champion!

2
Michael Sims

J'ai créé un champ de texte personnalisé pouvant être ajouté à Java Builder FX (à l'aide de "importer un fichier JAR/FXML ...").

Avec ce TextField peut être défini 

  1. les caractères ou les nombres autorisés
  2. s'il y a ou non le caractère d'espace
  3. si l'entrée est seulement CAPITAL (la sortie affichée est en capital)
  4. et la longueur.

Bien sûr, cela peut être amélioré, mais c'est très utile. J'espère que cela aidera quelqu'un :)

FX Project LimitedTextField Ce projet permet de créer le fichier 'LimitedTextField.jar' à importer dans votre application ou dans Java Builder FX.

CustomControlExample.Java

package limitedtextfield;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class CustomControlExample extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        LimitedTextField customControl = new LimitedTextField();
        customControl.setText("Hello!");

        stage.setScene(new Scene(customControl));
        stage.setTitle("Custom Control");
        stage.setWidth(300);
        stage.setHeight(200);
        stage.show();
    }

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

custom_control.fxml

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<HBox>
    <limitedtextfield.LimitedTextField text="Hello World!"/>
</HBox>

LimitedTextField.Java

package limitedtextfield;
import javafx.scene.control.TextField;

public class LimitedTextField extends TextField
{
    private String characters;
    private int max;
    private boolean capital = false;
    private boolean space = true;

    static public final String CharactersNumbers = "[qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890èéòàùì ]";
    static public final String Characters = "[qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNMèéòàùì ]";
    static public final String Numbers = "[1234567890 ]";
    static public final String NumbersPoint = "[1234567890. ]";

    public LimitedTextField(String l){
        super();
        characters = l;
        max=0;
    }

    public LimitedTextField(){
        super();
        characters = "";
        max=0;
    }

    public LimitedTextField(String l, int max){
        super();
        characters = l;
        this.max=max;
        //System.out.println("Costruttore");
    }

    public LimitedTextField(int max){
        super();
        characters = "";
        this.max=max;
    }

    @Override
    public void replaceText(int start, int end, String text)
    {
        if(!characters.equals("")){
            if (validateCh(text))
            {
                text = check(text);
                super.replaceText(start, end, text);
                if(max>0)
                    verifyLengh();
            }
        }else{
            text = check(text);
            super.replaceText(start, end, text);
            if(max>0)
                verifyLengh();
        }
    }

    @Override
    public void replaceSelection(String text)
    {
        if(!characters.equals("")){
            if (validateCh(text))
            {
                text = check(text);
                super.replaceSelection(text);
                if(max>0)
                    verifyLengh();
            }  
        }else{
            text = check(text);
            super.replaceSelection(text);
            if(max>0)
                verifyLengh();
        }
    }

    private boolean validateCh(String text)
    {
        /*
        [abc] Find any of the characters between the brackets 
        [0-9] Find any of the digits between the brackets 
        (x|y) Find any of the alternatives separated with | 
        */
        return ("".equals(text) || text.matches(characters));
    }

    private void verifyLengh() {
        if (getText().length() > max) {
            setText(getText().substring(0, max));//use this line if you want to delete the newer characters inserted
            //setText(getText().substring(getText().length()-max, getText().length()));//use this line if you want to delete the older characters inserted
            positionCaret(max);//set the cursor position
        }

    }

    private String check(String text){
        if(capital)
            text = text.toUpperCase();
        if(!space)
            text = text.replace(" ", "");

        return text;
    }
    public void setLimitCharachters(String s){
        this.characters = s;
    }
    public String getLimitCharachters(){
        return characters;
    }
    public void setMaxLenght(int s){
        this.max= s;
    }
    public int getMaxLenght(){
        return max;
    }
    public boolean getCapital(){
        return this.capital;
    }
    public void setCapital(boolean t){
        this.capital = t;
    }
    public boolean getSpace(){
        return this.space;
    }
    public void setSpace(boolean t){
        this.space = t;
    }
}

Exemple d'utilisation:

MyFxmlApplication.fxml

...
<?import limitedtextfield.*?>
...
<HBox alignment="CENTER_LEFT" spacing="5.0">
      <children>
       <Label text="Name:" />
       <LimitedTextField fx:id="A_Name_S" />
      </children>
     <FlowPane.margin>
     <Insets right="5.0" />
     </FlowPane.margin>
</HBox>
...

MyFxmlApplicationController.fxml

...
import limitedtextfield.LimitedTextField;
@FXML
private LimitedTextField A_Name_S;

...
 @Override
public void initialize(URL url, ResourceBundle rb) {
    A_Name_S.setSpace(false);
    A_Name_S.setCapital(true); 
    A_Name_S.setMaxLenght(20);
    A_Name_S.setLimitCharachters(LimitedTextField.Characters);
}

au revoir

2
Matteo

Essayez cette solution en ajoutant cette fonction dans votre contrôleur, vous devez l'ajouter à l'action keyPressed de votre champ de texte.

@FXML
void verifnum(KeyEvent event) {

    txt.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue,
                String newValue) {
            if (!newValue.matches("\\d*")) {
                txt.setText(newValue.replaceAll("[^\\d]", ""));
            }
        }
    });
}
0
user7164105