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

Composants Java Discussion :

JFormattedTextField qui accepte plusieurs formats de date


Sujet :

Composants Java

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2018
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2018
    Messages : 50
    Points : 46
    Points
    46
    Par défaut JFormattedTextField qui accepte plusieurs formats de date
    Bonjour à tous !
    Pour un programme, j'ai une classe JFormattedTextField pour des dates :
    Code java : 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
     
    package modele;
     
    import javax.swing.*;
    import java.sql.Date;
    import java.text.SimpleDateFormat;
    import java.time.LocalDate;
    import java.time.ZoneId;
    import java.time.ZoneOffset;
    import java.time.ZonedDateTime;
     
    public class DateTextField extends JFormattedTextField {
        public DateTextField() {
            super(new SimpleDateFormat("dd/MM/yyyy"));
        }
        public DateTextField(LocalDate d) {
            super(new SimpleDateFormat("dd/MM/yyyy"));
            if (d != null)
                this.setValue(Date.from(d.atStartOfDay().toInstant(ZoneOffset.ofHours(2))));
        }
        public LocalDate getDateValue() {
            Object value = this.getValue();
            if ( value instanceof Date ) {// ici java.sql.Date à cause de l'import
                return ((Date)value).toLocalDate();
            }
            else  if ( value instanceof java.util.Date ) {
                ZonedDateTime zdt = ZonedDateTime.ofInstant ( ((java.util.Date )value).toInstant(), ZoneId.systemDefault() );
                return  zdt.toLocalDate();
            }
            else {
                return null;
            }
        }
    }

    Elle fonctionne très bien lorsque je mets une date. Cependant, je voudrais qu'une saisie de type "12/02" soit "demi valide", c'est-à-dire qu'elle soit directement changée en "12/02/annéeEnCours" au lieu d'être effacée.
    Comment faire ?

    Merci d'avance de vos réponses

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    On pourrait bricoler un truc comme ça :
    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
    	public static class DateTextField extends JFormattedTextField {
     
    		private static String SHORT_DATEFORMAT =  "dd/MM";
    		private static String DATEFORMAT =  SHORT_DATEFORMAT + "/yyyy";
    		private SimpleDateFormat shortFormatter;
     
    	    public DateTextField() {
    	        super(new SimpleDateFormat(DATEFORMAT));
    	        shortFormatter=new SimpleDateFormat(SHORT_DATEFORMAT);
    	    }
    	    public DateTextField(LocalDate d) {
    	    	this();
    	        if (d != null)
    	            this.setValue(Date.from(d.atStartOfDay().toInstant(ZoneOffset.ofHours(2))));
    	    }
     
    	    @Override
    	    public void commitEdit() throws ParseException {
     
    	    	AbstractFormatter format = getFormatter();
     
    	        if (format != null) {
    	        	String dateText = getText();
    	        	try {
    	        		format.stringToValue(dateText);
    	        	}
    	        	catch (ParseException e) {
    	        		try {
    	        			java.util.Date date = shortFormatter.parse(dateText);
    	        			date.setYear(Year.now().getValue()-1900);
    	        			setText(format.valueToString(date));
    	        		}
    	        		catch (ParseException ee) {
    					}
    				}
    	        }
     
    	    	super.commitEdit();
    	    }
     
    	    public LocalDate getDateValue() {
    	        Object value = this.getValue();
    	        if ( value instanceof Date ) {// ici java.sql.Date à cause de l'import
    	            return ((Date)value).toLocalDate();
    	        }
    	        else  if ( value instanceof java.util.Date ) {
    	            ZonedDateTime zdt = ZonedDateTime.ofInstant ( ((java.util.Date )value).toInstant(), ZoneId.systemDefault() );
    	            return  zdt.toLocalDate();
    	        }
    	        else {
    	            return null;
    	        }
    	    }
    	}
    Mais pourquoi pas utiliser un JSpinner plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static class DateTextSpinner extends JSpinner {
     
    		private static String DATEFORMAT =  "dd/MM/yyyy";
     
    		public DateTextSpinner() {
    			super(new SpinnerDateModel());
    			JSpinner.DateEditor editor = new JSpinner.DateEditor(this, DATEFORMAT);
    			setEditor(editor);
    			DateFormatter formatter = (DateFormatter)editor.getTextField().getFormatter();
    			formatter.setAllowsInvalid(false); 
    			formatter.setOverwriteMode(true);
    		}
     
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2018
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2018
    Messages : 50
    Points : 46
    Points
    46
    Par défaut
    Tout d'abord merci beaucoup de ta réponse !
    pourquoi pas utiliser un JSpinner plutôt :
    parce qu'avant de lire ce message je ne savais même pas que cet objet existait ?
    Sinon, le truc qui m’embête avec le JSpinner c'est que je veux que la case soit vide en arrivant, j'entre la date au pavé numérique, et elle s'ajuste au cas où. Or avec le JSpinner j'ai une date de mise au début donc c'est un peu moins ergonomique...
    Le "bricolage" par contre donne exactement le rendu que j'attends . Ceci dit, il utilise java.util.Date.setYear(int) qui est déprécié. Je n'ai jamais utilisé de fonction dépréciée, c'est gênant ? On va pas en prison hein ! Plus sérieusement, je dois avouer que je n'ai pas compris tout le code, notamment ce qui touche au AbstractFormatter. Mais du peu que je comprends, je dois pouvoir faire la même chose avec Calendar plutôt que java.util.Date ?

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par WAitWaitW Voir le message
    Sinon, le truc qui m’embête avec le JSpinner c'est que je veux que la case soit vide en arrivant, j'entre la date au pavé numérique, et elle s'ajuste au cas où. Or avec le JSpinner j'ai une date de mise au début donc c'est un peu moins ergonomique...
    Pourquoi moins ergonomique ? S'il y'a déjà une date de saisie, y'a des chances que ça puisse être la bonne (c'est celle du jour, mais on peut initialiser avec une autre date). Ce qui serait (plus) ergonomique, ce serait d'avoir un date picker (et c'est ce qu'on voit dans toutes les interfaces modernes)).
    .
    Citation Envoyé par WAitWaitW Voir le message
    Le "bricolage" par contre donne exactement le rendu que j'attends . Ceci dit, il utilise java.util.Date.setYear(int) qui est déprécié.
    Oui, on ne devrait pas l'utiliser et utiliser un Calendar et tout le toutim de conversion (ce que fait la méthode setYear() avec un décalage de 1900), ou passer par java.time et faire de la conversion instant vers date. Mais pourquoi se compliquer la vie avec ça. C'est un bricolage, un peu plus ou un peu moins bricolé, ça change pas grand chose, et ce n'est pas très grave. Déjà, utiliser un java.util/sql.Date, c'est du bricolage. A la limite, on peut mettre un commentaire pour expliquer pourquoi on fait ça comme ça.

    Pour le principe de fonctionnement, si le formatter de base du JFormattedTextFIeld ne reconnait pas la saisie, on essaye de vérifier si cette saisie correspond au format jour/mois et si c'est le cas, on convertit en date et on force l'année à la valeur voulue (la conversion par parsing donnera une année par défaut(1970) , puisqu'il n'y en a pas dans le format).
    On pourrait aussi tester si la String correspond à un jour/mois, mais ce serait finalement plus compliqué (un test par expression régulière, un test de bornes pour le mois, un test plus compliqué pour les jours. Le seul truc qui va être un peu foireux c'est si l'utilisateur saisit 29/02... (ça donnera 01/03/2020), ou 34/01, 12/25, etc... la date sera décalée au lieu d'être refusée... mais bon c'est la conséquence d'utiliser des java.util.Date.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2018
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2018
    Messages : 50
    Points : 46
    Points
    46
    Par défaut
    Merci de ta réponse (éclair !!).
    S'il y'a déjà une date de saisie, y'a des chances que ça puisse être la bonne
    C'est pour entrer des factures qui datent de X jours ou vont arriver bientôt, du coup la date est quand même aléatoire et je trouve plus pratique d'écrire à la chaîne avec le pavé numérique plutôt que surligner / changer ou appuyer avec la souris sur up/doown
    Ceci dit oui un date picker serait parfait... et sera sans doute implémenté... un de ces 4 quand j'aurai le temps de creuser ça

    Sinon, quand pour la méthode "bricolée" j'ai l'impression que tu ne l'apprécies pas plus que ça. Pourquoi ? C'est pas "sérieux" de faire un truc comme ça ? C'est pas efficace niveau ressources ou autre ?

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par WAitWaitW Voir le message
    C'est pour entrer des factures qui datent de X jours ou vont arriver bientôt, du coup la date est quand même aléatoire et je trouve plus pratique d'écrire à la chaîne avec le pavé numérique plutôt que surligner / changer ou appuyer avec la souris sur up/doown
    Le JSPinner se comporte exactement comme ça. Pas besoin de sélectionner. On entre dans le champ (par tab par exemple), on tape directement les chiffres (c'est le setOverwriteMode(true) qui permet ça), sans les /. On pourrait faire que la frappe du / fasse passer directement au sous champ suivant.
    Alors oui, il y a les boutons up / down. On n'est pas obligé de s'en servir. Je n'ai jamais chercher à les supprimer. Cela peut se tenter éventuellement.

    Citation Envoyé par WAitWaitW Voir le message
    Ceci dit oui un date picker serait parfait... et sera sans doute implémenté... un de ces 4 quand j'aurai le temps de creuser ça
    Pour de la saisie en galet de facture, je suis moins sûr. Cela oblige à passer par la souris, ou d'utiliser de la navigation au clavier beaucoup plus longue que de simplement taper les chiffres.

    Citation Envoyé par WAitWaitW Voir le message
    Sinon, quand pour la méthode "bricolée" j'ai l'impression que tu ne l'apprécies pas plus que ça. Pourquoi ? C'est pas "sérieux" de faire un truc comme ça ? C'est pas efficace niveau ressources ou autre ?
    Ce n'est pas très lourd non. On parse deux fois la date au lieu d'une fois, voire une fois de plus si l'année n'est pas saisie. On perd donc un peu de temps. Mais on est dans de l'UI. Même pour une saisie ultra-rapide, ça ne se sentira pas.
    Non, le truc, c'est que c'est le JFormattedTextField que je n'aime pas à la base. Je le trouve mal foutu. Il oblige justement à bricoler des verrues pour obtenir des comportements qui devraient être fournis de base. Et de toute manière, on arrive jamais à avoir quelque chose de complètement satisfaisant. Je trouve absurde que malgré un format, on puisse quand même saisir n'importe quoi. Il y a bien quelques paramètres de base qui permettent d'approcher à un minimum d'ergonomie satisfaisante, et quelques possibilités d'extension, mais malgré un long travail de tuning et d'adaptation, je ne suis jamais parvenu à obtenir un composant que je qualifierais de réellement fonctionnel, permettant une saisie rapide et naturelle, aussi bien en galet, en formulaire, ou en saisie "profane". Cela fait d'ailleurs un moment que je songe à fabriquer un composant mieux pensé, mais le temps, d'autres priorités, l'obsolescence de Swing, tout ça, on fait que ça ne s'est pas concrétisé. En tout cas l'idée est d'avoir un champ avec une saisie mix à la spinner, sans les boutons up/down, avec navigation interne de champ en champ, avec possibilité d'avoir un champ vide, mais les / (ou autre séparateur) affiché quand même, validation directe inline, complétion par champ, conversion intelligente au paste, etc.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2018
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2018
    Messages : 50
    Points : 46
    Points
    46
    Par défaut
    Merci mille fois pour la réponse super bien expliquée !
    Tu m'as donné toutes les clés pour réussir. J'ai encore du taff sur ça mais je mets en résolu car je n'ai plus besoin d'aide, tu as éclairé toutes mes interrogations.
    Merci encore.

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

Discussions similaires

  1. [PHP 7] gérer plusieurs formats de date
    Par laurentSc dans le forum Langage
    Réponses: 3
    Dernier message: 04/02/2020, 20h55
  2. [V10] Champ qui accepte plusieurs valeurs dans une liste de valeurs
    Par lamazze dans le forum Odoo (ex-OpenERP)
    Réponses: 0
    Dernier message: 24/01/2019, 18h08
  3. [AC-2003] Requête qui traite un format de date personnalisé
    Par ostrich95 dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 12/03/2014, 16h43
  4. Réponses: 22
    Dernier message: 08/10/2008, 13h40
  5. [JFormattedTextfield] format de date en java
    Par bil_info05 dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 19/04/2007, 14h08

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