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 :

Ajouter Menu Contextuel et écouteur à plusieurs TextFields


Sujet :

JavaFX

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Décembre 2013
    Messages : 49
    Points : 39
    Points
    39
    Par défaut Ajouter Menu Contextuel et écouteur à plusieurs TextFields
    Bonjour à tous.

    Je voudrais ajouter d'un seul coup un menu contextuel et un écouteur à tous les TextFields de mon Node, pour exemple avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    monNode.lookupAll(".text-field")
    mais je ne sais pas comment faire.

    En plus, l'action de l'écouteur doit savoir prendre le contenu du TextField où sera déployé le menu, mais je ne sais pas comment le faire.

    Merci si vous pouvez m'éclairer.

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 838
    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 838
    Points : 22 846
    Points
    22 846
    Billets dans le blog
    51
    Par défaut
    Ben, je dirai qqchose comme:
    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
    final Set<Node> nodes = control.lookupAll(".text-field");
    nodes.stream().map(node -> (TextField) node).forEach(textField -> {
        final MenuItem idMenu = new MenuItem(textField.getId());
        idMenu.setDisable(true);
        final MenuItem searchItem = new MenuItem();
        searchItem.disableProperty().bind(Bindings.isEmpty(textField.textProperty()));
        searchItem.textProperty().bind(new StringBinding() {
            {
                bind(textField.textProperty());
            }
     
            @Override
            public void dispose() {
                unbind(textField.textProperty());
            }
     
            @Override
            protected String computeValue() {
                final String text = textField.getText().trim();
                return (text.isEmpty()) ? "Search..." : String.format("Search \"%s\"...", text);
            }
        });
        searchItem.setOnAction(actionEvent -> {
            final String text = textField.getText().trim().replaceAll(" ", "_");
            final String url = String.format("http://fr.wikipedia.org/wiki/%s", text);
            getHostServices().showDocument(url);
        });
        final ContextMenu contextMenu = new ContextMenu();
        contextMenu.getItems().add(idMenu);
        contextMenu.getItems().add(new SeparatorMenuItem());
        contextMenu.getItems().add(searchItem);
        textField.setContextMenu(contextMenu);
    });
    Cette première partie est assez simple : on construit un ContextMenu pour chaque TextField avec des sous-menu prédéterminés mais dont le contenu et les actions changent cependant en fonction de ce qui est saisi dans le champ textuel.

    J'ai ensuite tenté de rajouter a la fin de la boucle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        final EventHandler<MouseEvent> mouseEventHandler = mouseEvent -> {
            System.out.println(mouseEvent.getButton());
            if (mouseEvent.isSecondaryButtonDown()) {
                final MenuItem otherItem = new MenuItem("Truc muche");
                contextMenu.getItems().add(otherItem);
            }
            mouseEvent.consume();
        };
        textField.setOnMousePressed(mouseEventHandler);
    Mais il y a un soucis :
    • Si le TextField a le focus ; quand on clique avec le bouton de droite, le ContextMenu est bien affiché et l’événement souris est appelé. Donc le menu contextuel affiché contient le nouveau menu qui a été ajouté (d'autres sont rajoutés par la suite plus on clique).
    • Si le TextField n'a pas le focus et qu'on clique avec le bouton de droite, le ContextMenu est bien affiché MAIS :
      • Si le focus appartient a un bouton, le champ textuel sur le quel on a cliqué récupère le focus et cela marche comme précédemment.
      • Si le focus appartient a un autre champ textuel, le champ textuel sur le quel on a clique ne récupère jamais le focus, l’événement souris n'est jamais appelé. Donc le menu contextuel ne contient pas le nouveau menu.

    C'est peut-etre un bug...
    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
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Décembre 2013
    Messages : 49
    Points : 39
    Points
    39
    Par défaut
    Bonjour Bouye, merci pour la réponse.

    La première partie du code je crois que peut résoudre mon problème, ce que je cherche c'est simplement récupérer dans le presse papier le contenu du TextField combiné avec une autre chaine…

    Lorsque le TextField a du contenu, pas de souci, mais s'il est vide j'ai l'erreur Null Pointer Exception sur la ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                final String text = textField.getText().trim();
    Si j'enleve la methode trim() je n'ai pas d'erreur, seulement qu'on ne contrôle pas les valeurs Null...

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 838
    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 838
    Points : 22 846
    Points
    22 846
    Billets dans le blog
    51
    Par défaut
    Ben faut le rajouter alors. Moi j'ai vite tapé ça, à toi de rendre le code sécure
    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

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Décembre 2013
    Messages : 49
    Points : 39
    Points
    39
    Par défaut
    D'accord…

    J'essais de rendre le code sécure, dans mon cas, il est seulement nécessaire de montrer le Menu Contextuel s'il y a du texte dans le TextField, puisqu'il s'agit de copier dans le presse papiers le contenu du TextField.

    Donc je procède comme cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          final Set<Node> nodes = cantosNode.lookupAll(".text-field");
          nodes.stream().map(node -> (TextField) node).forEach(textField -> {
              doMenuContextual(textField);
          });
    //...
    Puis:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        private void doMenuContextual(TextField textField) {
            final ContextMenu contextMenu = new ContextMenu();
            if ("txtComentarioUrl".equals(textField.getId())
    //Ici je crée des MenuItems selon le nom du Text Field… et après:
    //        textField.setContextMenu(contextMenu);
    J'ai pensé à écouter les TextFields en deux étapes, lorsqu'il change et lorsqu'il recoit le focus:

    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
            textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
                public void changed(ObservableValue<? extends Boolean> observable, 
                        Boolean oldValue, Boolean newValue) {
                    if(newValue.booleanValue()) {
                        if (StringUtils.isNotBlank(textField.getText())) {
                            System.out.println("textfield focus"+textField.getId()+" > "+textField.getText());
                            bolVisible=true;         
                        }
                        else {
                            bolVisible=false; 
                        }
                    }
                    showContextMenu(bolVisible, contextMenu, textField);
                }
            } );
            textField.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable,
                                String oldValue, String newValue) {
                if (StringUtils.isNotBlank(newValue)) {
                    bolVisible=true;
                }
                else {
                    bolVisible=false;
                }
                showContextMenu(bolVisible, contextMenu, textField);
            }});
    L'idée de deux écouteurs est d'atribuer vrai (il y a du texte) ou faux (il n'y a pas de texte) à la variable bolVisible et selon sa valeur montrer ou pas le MenuContextuel…

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        private void showContextMenu(boolean bolVisible, ContextMenu contextMenu, TextField textField) {
            System.out.println("----"+bolVisible);
            if (bolVisible==true){
                textField.setContextMenu(contextMenu);
            }
        }
    Le MenuContextuel se montre toujours, si bolVisible est vrai ou faux.

    ¿ContextMenu n'a pas une méthode?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    menuContextual.setVisible(bolVisible);
    Merci de vos conseils...

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 838
    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 838
    Points : 22 846
    Points
    22 846
    Billets dans le blog
    51
    Par défaut
    Hu, hu, hu... et en utilisant le binding tout simplement
    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
    contextMenuProperty().bind(new ObjectBinding<ContextMenu>() {
      {
         bind(textProperty());
      }
     
      @Override
      protected void dispose() {
        unbind(textProperty());
      }
     
      @Override
      public ContextMenu computeValue() {
        final String text = getText();
        final ContextMenu result =  (text == null || text.trim().isEmpty()) ? null : contextMenu;
        return result;
      }
    });
    Comme ça si y a pas de texte, y a pas de menu contextuel... tout court !
    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

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Décembre 2013
    Messages : 49
    Points : 39
    Points
    39
    Par défaut
    Merci Bouye,

    Le binding semble interessant, mais je n'arrive pas bien l'appliquer. J'ai lu quelque chose en anglais (sur Oracle), mais je n'ai pas bien compris son utilisation

  8. #8
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 838
    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 838
    Points : 22 846
    Points
    22 846
    Billets dans le blog
    51
    Par défaut
    Ben vioui mais mon article sur le binding de bas niveau n'a pas encore été passé en correction et donc il n'est pas prêt d’être publié... m'voila quoi...

    Bon bref, ici je défini un binding de bas niveau sur la propriété contextMenuProperty() du TextField et qui est lié à sa propriété textProperty().
    Donc :
    • Quand la valeur de textProperty() change -> contextMenuProperty() est invalidée.
    • Quand contextMenuProperty() est réévaluée (par exemple quand on fait myTextField.getContextMenu()), la méthode computeValue() est appelée.
    • Si le text est null, le menu retourné sera null.
    • Sinon la valeur retournée est mis à la valeur de notre menu qu'on avait tantôt.


    PS : un binding de haut niveau c'est quand on fait un truc simple dans le genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    textField1.textProperty().bind(textField2.textProperty());
    Le binding de bas niveau est plus complexe a écrire mais plus puissant : ici on produit une valeur de type ContextMenu en fonction des modifications d'une valeur de type String.
    On peut aussi rendre une simple propriété dépendante d'une dizaine d'autre très facilement, ça permet d’économiser de la mémoire plutôt que de passer par les methodes statiques prêtes a l'emploi de la classe Bindings qui sont certes faciles a utiliser mais consomment plus de mémoire. Ça évite aussi de mettre des ChangeListener partout quand il n'y en a pas besoin...
    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

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Décembre 2013
    Messages : 49
    Points : 39
    Points
    39
    Par défaut
    Très intéressant. J'attend ton article, car le binding semble être très utile.

    Maintenant le code marche, mais j'ai du faire quelques modifications:
    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
           textField.contextMenuProperty().bind(new ObjectBinding<ContextMenu>() {
               {
                   bind(textField.textProperty());
               }
               @Override
               public void dispose() {
                   unbind(textField.textProperty());
               }
               @Override
               public ContextMenu computeValue() {
                   final String text = textField.getText();
                   final ContextMenu result =  (text == null || text.trim().isEmpty()) ? null : contextMenu;
                   return result;
               }
    });
    Mais…

    Lorsque les TextFields n'ont pas de texte, c'est le Menu Contextuel du Systeme que s'affiche, avec le classique: Copier, Coller, Sélectionner Tout, etc

  10. #10
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 838
    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 838
    Points : 22 846
    Points
    22 846
    Billets dans le blog
    51
    Par défaut
    Celui là je n'ai aucune idée de comment le faire disparaître. Donc faut tester plus en avant.
    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

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2013
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Décembre 2013
    Messages : 49
    Points : 39
    Points
    39
    Par défaut
    J'ai cherché un peu dans les forums, et il semble qu'ils n'est pas possible, pour le moment, de cacher le Menu Contextuel par défaut.

    Donc, j'ai appliqué la solution suivante: montrer toujours le Menu Contextuel, mail si le TextField est vide, l'option du menu est désactivée:

    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
            final ContextMenu contextMenu = new ContextMenu();
                final MenuItem googleItem = new MenuItem("Google");
               googleItem.disableProperty().bind(Bindings.isEmpty(textField.textProperty()));
                contextMenu.getItems().add(googleItem);
                googleItem.setOnAction((ActionEvent e) -> {
     
                        final Clipboard clipboard = Clipboard.getSystemClipboard();
                        final ClipboardContent content = new ClipboardContent();
                        content.putString("https://docs.google.com/uc?export=download&id="+textField.getText());
                        clipboard.setContent(content);
                    
                });
    
                textField.setContextMenu(contextMenu);
    Le binding, c'est magique…

    Merci Bouye, je marque cette discussion comme résolue.

  12. #12
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 838
    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 838
    Points : 22 846
    Points
    22 846
    Billets dans le blog
    51
    Par défaut
    Mais de rien.
    Il faudrait peut-etre tester avec un event handler de bas niveau et voir s'il est possible d'intercepter l’évent et de le consommer en cas de champs vide (s'il est consommé il n'est pas propagé aux autres éléments et ne devient pas un MouseEvent).
    Une autre possibilité consisterait a implémenter ta propre skin en s'inspirant de la skin par defaut ce qui est faisable en JDK8 puisque c'est publique.
    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

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

Discussions similaires

  1. Ajouter menu contextuel
    Par Logiinx dans le forum VB.NET
    Réponses: 4
    Dernier message: 26/05/2015, 21h50
  2. [Débutant] DXTreeList : Ajouter menu contextuel et récupérer item clicé (pour suppression)
    Par Zoups dans le forum Windows Presentation Foundation
    Réponses: 1
    Dernier message: 12/06/2012, 17h51
  3. [APEX] Ajouter menu contextuel à un 'Shuttle'
    Par Bluedeep dans le forum Outils
    Réponses: 0
    Dernier message: 27/10/2011, 22h08
  4. Réponses: 15
    Dernier message: 12/08/2005, 16h06
  5. [Plugin] Ajouter une option au menu contextuel ?
    Par relivio dans le forum Eclipse Platform
    Réponses: 2
    Dernier message: 22/03/2004, 17h18

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