2016-11-07 1 views
7

Je suis en train de créer un champ de texte numérique pour Entiers en utilisant le TextFormatter de JavaFX 8.TextField numérique pour Entiers JavaFX 8 avec TextFormatter et/ou UnaryOperator

Solution avec UnaryOperator:

UnaryOperator<Change> integerFilter = change -> { 
    String input = change.getText(); 
    if (input.matches("[0-9]*")) { 
     return change; 
    } 
    return null; 
}; 

myNumericField.setTextFormatter(new TextFormatter<String>(integerFilter)); 

Solution avec IntegerStringConverter:

myNumericField.setTextFormatter(new TextFormatter<>(new IntegerStringConverter())); 

Les deux solutions ont leurs propres problèmes. Avec l'UnaryOperator, je ne peux entrer que les chiffres de 0 à 9 comme prévu, mais j'ai aussi besoin d'entrer des valeurs négatives comme "-512", où le signe n'est autorisé qu'à la première position. Aussi, je ne veux pas de chiffres comme "00016" qui est encore possible. La méthode IntegerStringConverter fonctionne mieux: tout nombre invalide comme "-16-123" n'est pas accepté et les nombres comme "0123" sont convertis en "123". Mais la conversion ne se produit que lorsque le texte est validé (en appuyant sur Entrée) ou lorsque le TextField perd son focus.

Existe-t-il un moyen d'appliquer la conversion de la seconde méthode à IntegerStringConverter chaque fois que la valeur de TextField est mise à jour?

Répondre

13

Le convertisseur est différent du filtre: le convertisseur spécifie comment convertir le texte en valeur, et les filtres de filtre que l'utilisateur peut modifier. Il semble que vous souhaitiez les deux, mais vous souhaitez que le filtre filtre plus précisément les modifications autorisées.

Habituellement, je trouve qu'il est plus facile de vérifier la nouvelle valeur du texte si la modification a été acceptée. Vous souhaitez éventuellement avoir un -, suivi de 1-9 avec un nombre de chiffres après celui-ci. Il est important d'autoriser une chaîne vide, sinon l'utilisateur ne pourra pas tout supprimer.

Alors vous avez besoin probablement quelque chose comme

UnaryOperator<Change> integerFilter = change -> { 
    String newText = change.getControlNewText(); 
    if (newText.matches("-?([1-9][0-9]*)?")) { 
     return change; 
    } 
    return null; 
}; 

myNumericField.setTextFormatter(
    new TextFormatter<Integer>(new IntegerStringConverter(), 0, integerFilter)); 

Vous pouvez même ajouter plus de fonctionnalités au filtre pour le laisser traiter - d'une façon plus intelligente, par exemple

UnaryOperator<Change> integerFilter = change -> { 
    String newText = change.getControlNewText(); 
    // if proposed change results in a valid value, return change as-is: 
    if (newText.matches("-?([1-9][0-9]*)?")) { 
     return change; 
    } else if ("-".equals(change.getText())) { 

     // if user types or pastes a "-" in middle of current text, 
     // toggle sign of value: 

     if (change.getControlText().startsWith("-")) { 
      // if we currently start with a "-", remove first character: 
      change.setText(""); 
      change.setRange(0, 1); 
      // since we're deleting a character instead of adding one, 
      // the caret position needs to move back one, instead of 
      // moving forward one, so we modify the proposed change to 
      // move the caret two places earlier than the proposed change: 
      change.setCaretPosition(change.getCaretPosition()-2); 
      change.setAnchor(change.getAnchor()-2); 
     } else { 
      // otherwise just insert at the beginning of the text: 
      change.setRange(0, 0); 
     } 
     return change ; 
    } 
    // invalid change, veto it by returning null: 
    return null; 
}; 

Cela vous permettra de la presse utilisateur - à tout moment et il basculera le signe de l'entier.

SSCCE:

import java.util.function.UnaryOperator; 

import javafx.application.Application; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.TextField; 
import javafx.scene.control.TextFormatter; 
import javafx.scene.control.TextFormatter.Change; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 
import javafx.util.StringConverter; 
import javafx.util.converter.IntegerStringConverter; 

public class IntegerFieldExample extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TextField integerField = new TextField(); 
     UnaryOperator<Change> integerFilter = change -> { 
      String newText = change.getControlNewText(); 
      if (newText.matches("-?([1-9][0-9]*)?")) { 
       return change; 
      } else if ("-".equals(change.getText())) { 
       if (change.getControlText().startsWith("-")) { 
        change.setText(""); 
        change.setRange(0, 1); 
        change.setCaretPosition(change.getCaretPosition()-2); 
        change.setAnchor(change.getAnchor()-2); 
        return change ; 
       } else { 
        change.setRange(0, 0); 
        return change ; 
       } 
      } 
      return null; 
     }; 

     // modified version of standard converter that evaluates an empty string 
     // as zero instead of null: 
     StringConverter<Integer> converter = new IntegerStringConverter() { 
      @Override 
      public Integer fromString(String s) { 
       if (s.isEmpty()) return 0 ; 
       return super.fromString(s); 
      } 
     }; 

     TextFormatter<Integer> textFormatter = 
       new TextFormatter<Integer>(converter, 0, integerFilter); 
     integerField.setTextFormatter(textFormatter); 

     // demo listener: 
     textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> System.out.println(newValue)); 

     VBox root = new VBox(5, integerField, new Button("Click Me")); 
     root.setAlignment(Pos.CENTER); 
     Scene scene = new Scene(root, 300, 120); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

L'utilisation intelligente de '' sur le groupe numéro?! Pensait à '-? ([1-9]? | [1-9] [0-9] *)', mais c'est beaucoup plus propre! – flakes

+1

J'apprécie vraiment vos efforts, votre solution a parfaitement fonctionné! – ShadowEagle

1
TextField txtpoint = new TextField(); 
    txtpoint.textProperty().addListener(new ChangeListener<String>() { 
     @Override 
     public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { 
      if (!newValue.isEmpty()) { 
       try { 
        long pointI = Integer.parseInt(newValue); 
        txtpoint.setText(String.valueOf(pointI)); 
       } catch (Exception e) { 
        txtpoint.clear(); 
        txtpoint.setText(getNumber(oldValue)); 
       } 
      } 
     } 
    }); 


private String getNumber(String value) { 
    String n = ""; 
    try { 
     return String.valueOf(Integer.parseInt(value)); 
    } catch (Exception e) { 
     String[] array = value.split(""); 
     for (String tab : array) { 
      try { 
       System.out.println(tab); 
       n = n.concat(String.valueOf(Integer.parseInt(String.valueOf(tab)))); 
      } catch (Exception ex) { 
       System.out.println("not nomber"); 
      } 
     } 
     return n; 
    } 
} 
+1

Sur débordement de la pile quelques mots d'explication/instruction d'utilisation sont généralement les bienvenus. – mkl