Existe-t-il un moyen simple de changer le comportement d’un contrôle Java / Swing lorsqu’il obtient le focus?

StackOverflow https://stackoverflow.com/questions/66455

  •  09-06-2019
  •  | 
  •  

Question

Pour la plupart des interfaces graphiques que j'ai utilisées, lorsqu'un contrôle qui contient du texte obtient le focus, tout le contenu du contrôle est sélectionné. Cela signifie que si vous commencez à taper, vous remplacez complètement le contenu précédent.

Exemple: vous avez un contrôle de rotation initialisé avec la valeur zéro. Vous y accédez et tapez "1". La valeur dans le contrôle est maintenant 1.

Avec Swing, cela n’arrive pas. Le texte du contrôle n'est pas sélectionné et le carat apparaît à une extrémité ou à une autre du texte existant. En reprenant l'exemple ci-dessus:

Avec un Swing JSpinner, lorsque vous passez au contrôle de rotation, le carat est à gauche. Vous tapez " 1 " et la valeur dans le contrôle est maintenant 10.

Cela me conduit (ainsi que mes utilisateurs) à monter un mur et j'aimerais le changer. Plus important encore, je voudrais le changer globalement pour que le nouveau comportement s'applique à JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner, etc. La seule façon que j’ai trouvée de faire cela consiste à ajouter un FocusAdapter à chaque contrôle et à substituer la méthode focusGained () à Do The Right Thing [tm].

Il doit y avoir un moyen plus facile et moins fragile. S'il vous plaît?

EDIT: Un élément d’information supplémentaire pour ce cas particulier. Le formulaire sur lequel je travaille a été généré à l'aide du concepteur de formulaires d'Idea. Cela signifie que normalement je n'écris pas le code pour créer les composants. Il est possible de dire à Idea que vous voulez les créer vous-même, mais c'est un problème que j'aimerais éviter.

Devise: Tous les bons programmeurs sont fondamentalement paresseux.

Était-ce utile?

La solution 4

Après avoir lu les réponses jusqu’à présent (Merci!), j’ai passé le JPanel le plus externe à la méthode suivante:

void addTextFocusSelect(JComponent component){
    if(component instanceof JTextComponent){
        component.addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(FocusEvent event) {
                    super.focusGained(event);
                    JTextComponent component = (JTextComponent)event.getComponent();
                    // a trick I found on JavaRanch.com
                    // Without this, some components don't honor selectAll
                    component.setText(component.getText());
                    component.selectAll();
                }
            });

    }
    else
    {
        for(Component child: component.getComponents()){
            if(child instanceof JComponent){
                addTextFocusSelect((JComponent) child);
            }
        }
    }
}

Cela fonctionne!

Autres conseils

Par le passé, j’ai eu besoin de cela, j’ai créé des sous-classes des composants à ajouter, "Auto-clearing". fonctionnalité aussi. par exemple:

public class AutoClearingTextField extends JTextField {
   final FocusListener AUTO_CLEARING_LISTENER = new FocusListener(){
      @Override
      public void focusLost(FocusEvent e) {
         //onFocusLost(e);
      }

      @Override
      public void focusGained(FocusEvent e) {
         selectAll();
      }
   };

   public AutoClearingTextField(String string) {
      super(string);
      addListener();
   }

   private void addListener() {
      addFocusListener(AUTO_CLEARING_LISTENER);      
   }
}

Le plus gros problème, c'est que je n'ai pas trouvé de "bon". moyen d'obtenir tous les constructeurs standard sans écriture écrasée. Les ajouter et forcer un appel à addListener est l'approche la plus générale que j'ai trouvée.

Une autre option consiste à surveiller ContainerEvents sur un conteneur de niveau supérieur avec ContainerListeer afin de détecter la présence de nouveaux widgets et à ajouter un écouteur de focus correspondant en fonction des widgets ajoutés. (par exemple, si l'événement conteneur est provoqué par l'ajout d'un TextField, ajoutez un écouteur de focus qui sait comment sélectionner tout le texte d'un TextField, etc.). Si un conteneur est ajouté, vous devez alors ajouter récursivement ContainerListener. à ce nouveau sous-conteneur également.

Dans les deux cas, vous n'aurez pas besoin de vous occuper des auditeurs de focus dans votre code d'interface utilisateur actuel - tout sera traité à un niveau supérieur.

Je n'ai pas essayé cela moi-même (il y a quelques instants seulement), mais vous pouvez probablement obtenir le composant actuellement ciblé en utilisant: KeyboardFocusManager (il existe une méthode statique getCurrentKeyboardFocusManager ()) un ajout d'un PropertyChangeListener à celui-ci. À partir de là, vous pouvez savoir si le composant est un composant JTextComponent et sélectionner tout le texte.

Une classe distincte qui associe un FocusListener au champ de texte souhaité peut être écrite. Tout l'écouteur de focus ferait, il appellerait selectAll () sur le widget texte lorsqu'il obtiendrait le focus.

public class SelectAllListener implements FocusListener {
  private static INSTANCE = new SelectAllListener();

  public void focusLost(FocusEvent e) { }

  public void focusGained(FocusEvent e) {
    if (e.getSource() instanceof JTextComponent) {  
      ((JTextComponent)e.getSource()).selectAll();
    }
  };

  public static void addSelectAllListener(JTextComponent tc) {
    tc.addFocusListener(INSTANCE);
  }

  public static void removeSelectAllListener(JTextComponent tc) {
    tc.removeFocusListener(INSTANCE);
  }
}

En acceptant un JTextComponent en tant qu'argument, ce comportement peut être ajouté à JTextArea, JPasswordField et à tous les autres composants d'édition de texte directement. Cela permet également à la classe d’ajouter tout sélectionner aux boîtes à liste modifiables et JSpinners, où votre contrôle sur le composant éditeur de texte peut être plus limité. Des méthodes pratiques peuvent être ajoutées:

public static void addSelectAllListener(JSpinner spin) {
  if (spin.getEditor() instanceof JTextComponent) {
    addSelectAllListener((JTextComponent)spin.getEditor());
  }
}

public static void addSelectAllListener(JComboBox combo) {
  JComponent editor = combo.getEditor().getEditorComponent();
  if (editor instanceof JTextComponent) {
    addSelectAllListener((JTextComponent)editor);
  }
}

De plus, les méthodes de suppression d'écouteur sont probablement inutiles, car l'écouteur ne contient aucune référence externe à une autre instance, mais elles peuvent être ajoutées pour rendre les révisions de code plus fluides.

Le seul moyen que je connaisse est de créer un FocusListener et de l'attacher à votre composant. Si vous souhaitez que ce FocusListener soit global à tous les composants de votre application, vous pouvez envisager d'utiliser la programmation orientée aspect (AOP). Avec AOP, il est possible de le coder une fois et d'appliquer votre auditeur de focus à tous les composants instanciés dans votre application sans avoir à copier-coller le code composant.addFocusListener (écouteur) dans l'ensemble de votre application ..

Votre aspect devrait intercepter la création d'un JComponent (ou des sous-classes auxquelles vous souhaitez ajouter ce comportement) et ajouter l'écouteur de focus à l'instance nouvellement créée. L’approche AOP est préférable au copier-coller de FocusListener sur l’ensemble de votre code, car vous conservez tout cela dans un seul élément de code et ne créez pas de cauchemar de maintenance une fois que vous décidez de modifier votre comportement global, comme supprimer l’écouteur pour. JSpinners.

Il existe de nombreux frameworks AOP parmi lesquels choisir. J'aime JBossAOP , car c'est du Java pur à 100%, mais vous voudrez peut-être jeter un oeil à AspectJ .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top