IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaFX Discussion :

Gérer les notations scientifiques dans un TextField - Progapagtion vers DoubleProperty


Sujet :

JavaFX

  1. #1
    Membre du Club
    Homme Profil pro
    Ingénieur projet
    Inscrit en
    Juin 2014
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur projet
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2014
    Messages : 46
    Points : 43
    Points
    43
    Par défaut Gérer les notations scientifiques dans un TextField - Progapagtion vers DoubleProperty
    Bonjour,
    je cherche à trouver le meilleur moyen de propager les infos contenues dans un champ de saisie TextField vers une propriété de type DoubleProperty.
    Ça marche très bien lorsque l’utilisateur saisi des chiffres, mais je ne parviens pas à trouver une solution optimale lorsque l’utilisateur utilise une notation scientifique (e, E).
    Sans précaution particulière, l'utilisation d'un listener de type changelistener déclenche une exception de type NumberFormatException lorsque l’utilisateur saisi e ou E.
    Rien d'anormal, sauf que je ne parviens pas à trouver une solution à ce problème.

    J'ai initialement pensé à utiliser un changelistener de ce type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ChangeListener<String> volumeOfreactorListener = (ObservableValue<? extends String> o,String oldVal, String newVal)->{
    		try
    	    {
    	        Double.parseDouble(newVal);
    	        // Valid double
    	        node.myProperty().set(Double.valueOf(newVal));
    	    }
    	    catch (NullPointerException | NumberFormatException ex)
    	    {
    	        // Not valid double
    	    }
    	};
    Le problème intervient si l'utilisateur saisi uniquement une valeur du type "x.xe" sans rien mettre après le "e". Je ne peux pas laisser l’utilisateur quitter le champ incomplet.
    Si je tente de restaurer la valeur de la propriété dans la TextField dans le cas où la conversion n'est pas possible, alors, cela revient à m’empêcher d’utiliser les notations scientifiques.
    Car il va m'effacer les caractères de type e chaque fois qu'une erreur de conversion est rencontrée.

    J'ai ensuite pensé à utiliser un listener de type myTextField.setOnKeyPressed(new EventHandler<KeyEvent>() { ...});
    En filtrant la saisi clavier aux touches Enter et Tab, on sais quand l’utilisateur valide la saisie, et on peut vérifier la compatibilité du champ saisi avec une propriété de type DoubleProperty.
    Problème : lorsque l'utilisateur clic sur un autre élément graphique sans valider la saisie par un appui sur les touches Enter ou Tab, les modifications ne sont pas prises en compte.

    Inversement, lorsque j'utilise un listener de type myTextField.focusProperty(), le changement n'est pas propagé lorsque l’utilisateur utilise les touches du clavier pour valider la saisie, ce qui peut être source d'erreur si il n'est pas suffisamment attentif.

    L'idéal aurait été une combinaison de ces listeners.
    J'aimerais donc avoir votre avis sur l'approche qui vous semble la plus pertinente pour traiter ce genre de cas.
    Merci d'avance.

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    J'pense à un truc comme ça (tapé rapidement et sujet à améliorations) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    package test;
     
    import java.math.BigDecimal;
    import java.math.RoundingMode;
    import java.text.DecimalFormat;
    import java.text.NumberFormat;
    import java.util.Objects;
    import java.util.function.UnaryOperator;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.TextField;
    import javafx.scene.control.TextFormatter;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.util.StringConverter;
     
    public class Main extends Application {
     
        private static class BigDecimalConverter extends StringConverter<BigDecimal> {
     
            private final NumberFormat formatter = new DecimalFormat("0.0E0");
            private BigDecimal lastValidValue;
     
            public BigDecimalConverter(final BigDecimal defaultValue, final int scale) {
                Objects.requireNonNull(defaultValue);
                if (scale < 0) {
                    throw new IllegalArgumentException();
                }
                lastValidValue = defaultValue;
                formatter.setRoundingMode(RoundingMode.HALF_UP);
                formatter.setMinimumFractionDigits(scale);
            }
     
            @Override
            public String toString(BigDecimal value) {
                System.out.printf("toString(%s)%n", value);
                final String result = formatter.format(value);
                System.out.println(result);
                return result;
            }
     
            @Override
            public BigDecimal fromString(String value) {
                System.out.printf("fromString(%s)%n", value);
                BigDecimal result = lastValidValue;
                try {
                    result = new BigDecimal(value);
                    lastValidValue = result;
                } catch (NumberFormatException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println(result);
                return result;
            }
        };
     
        @Override
        public void start(Stage primaryStage) {
            final TextField field = new TextField();
            final BigDecimal defaultValue = BigDecimal.ZERO;
            final StringConverter<BigDecimal> valueConverter = new BigDecimalConverter(defaultValue, 3);
            final UnaryOperator<TextFormatter.Change> filter = (change) -> {
                final String text = change.getText();
                System.out.printf("FILTER: %s%n", text);
                System.out.println(text.isEmpty() || text.matches("[0-9.E+-]+"));
                final TextFormatter.Change result = (text.isEmpty() || text.matches("[0-9.E+-]+")) ? change : null;
                return result;
            };
            final TextFormatter<BigDecimal> formatter = new TextFormatter<>(valueConverter, defaultValue, filter);
            field.setTextFormatter(formatter);
            formatter.valueProperty().addListener((observable, oldValue, newValue) -> System.out.printf("%s -> %s%n", oldValue, newValue));
            final StackPane root = new StackPane();
            root.getChildren().add(field);
            final Scene scene = new Scene(root, 300, 250);
            primaryStage.setTitle("Test");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
     
        public static void main(String[] args) {
            launch(args);
        }
    }
    PS : le filter sert à restreindre la saisie (la seule lettre qu'on peut taper c'est 'E') tandis que le valueConverter sert à faire la conversions String <-> BigDecimal suivant quand la fonction est invoquée (j'ai laissé les impressions console pour que tu puisses tester).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre du Club
    Homme Profil pro
    Ingénieur projet
    Inscrit en
    Juin 2014
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur projet
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2014
    Messages : 46
    Points : 43
    Points
    43
    Par défaut
    Merci bien pour ces réponses toujours instructives bouye.
    Je ne connaissais pas cette astuce d’utiliser un formateur et d'y intégrer un filtre de saisie.
    J'ai un peu adapté le code, et cela fonctionne à merveille.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    package test;
     
    import java.util.function.UnaryOperator;
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.TextField;
    import javafx.scene.control.TextFormatter;
    import javafx.scene.layout.StackPane;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    import javafx.util.StringConverter;
     
    public class Main extends Application {
     
        @Override
        public void start(Stage primaryStage) {
     
            final TextField field = new TextField();
            final TextField field2 = new TextField();
     
            final Double defaultValue = 0.5;
     
            final UnaryOperator<TextFormatter.Change> numberOnlyFilter = change -> { 
                final String text = change.getText(); 
                return (text.isEmpty() || text .matches("[0-9.eE+-]")) ? change : null; 
            }; 
     
            // Déclaration du convertisseur
            final StringConverter<Double> NumberConverter = new StringConverter<Double>() { 
     
                @Override 
                public String toString(Double value) { 
                    return (value == null) ? null : value.toString(); 
                }   
     
                @Override 
                public Double fromString(String text) { 
                    return (text == null || text.trim().isEmpty()) ? null : Double.parseDouble(text.trim()); 
                } 
            }; 
     
            // Mise en place du convertisseur dans le formatteur
            final TextFormatter<Double> numberOnlyFormatterField1 = new TextFormatter<Double>(NumberConverter, defaultValue, numberOnlyFilter);
            final TextFormatter<Double> numberOnlyFormatterField2 = new TextFormatter<Double>(NumberConverter, defaultValue, numberOnlyFilter);
     
            // Restriction de l'édition - Mise en place du filtre et du convertisseur. 
            field.setTextFormatter(numberOnlyFormatterField1);  
            field2.setTextFormatter(numberOnlyFormatterField2);
     
            numberOnlyFormatterField1.valueProperty().addListener((observable, oldValue, newValue) -> System.out.printf("%s -> %s%n", oldValue, newValue));
     
     
            final StackPane root = new StackPane();
            root.getChildren().addAll(new VBox(field, field2));
            final Scene scene = new Scene(root, 300, 250);
            primaryStage.setTitle("Test");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
     
        public static void main(String[] args) {
            launch(args);
        }
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. gérer les formulaires windows dans vb.net 2005
    Par jokke dans le forum VB.NET
    Réponses: 3
    Dernier message: 09/05/2008, 03h33
  2. comment gérer les retour chariot dans un label?
    Par Jayceblaster dans le forum Windows Forms
    Réponses: 24
    Dernier message: 07/07/2007, 18h15
  3. Réponses: 9
    Dernier message: 23/08/2006, 15h12
  4. Réponses: 9
    Dernier message: 13/04/2006, 11h40
  5. Comment gérer les valeur Nulles dans une requête ?
    Par sondo dans le forum Bases de données
    Réponses: 3
    Dernier message: 16/03/2005, 11h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo