web-dev-qa-db-fra.com

Comment sélectionner tout le texte dans un JFormattedTextField lorsqu'il obtient le focus?

J'ai une petite Java application de bureau qui utilise Swing. Il y a une boîte de dialogue de saisie de données avec des champs d'entrée de différents types (JTextField, JComboBox, JSpinner, JFormattedTextField). Lorsque j'active le JFormattedTextFields soit en en parcourant le formulaire ou en cliquant dessus avec la souris, je voudrais qu'il sélectionne tout le texte qu'il contient actuellement. De cette façon, les utilisateurs pourraient simplement commencer à taper et écraser les valeurs par défaut.

Comment puis je faire ça? J'ai utilisé un FocusListener/FocusAdapter qui appelle selectAll () sur le JFormattedTextField, mais il ne sélectionne rien, bien que la méthode focusGained () de FocusAdapter soit appelée (voir l'exemple de code ci-dessous).

private javax.swing.JFormattedTextField pricePerLiter;
// ...
pricePerLiter.setFormatterFactory(
    new JFormattedTextField.AbstractFormatterFactory() {
    private NumberFormatter formatter = null;
    public JFormattedTextField.AbstractFormatter 
        getFormatter(JFormattedTextField jft) {
        if (formatter == null) {
            formatter = new NumberFormatter(new DecimalFormat("#0.000"));
            formatter.setValueClass(Double.class);
        }
        return formatter;
    }
});
// ...
pricePerLiter.addFocusListener(new Java.awt.event.FocusAdapter() {
    public void focusGained(Java.awt.event.FocusEvent evt) {
        pricePerLiter.selectAll();
    }
});

Des idées? Ce qui est drôle, c'est que sélectionner tout son texte est apparemment le comportement par défaut pour JTextField et JSpinner, du moins lors de la tabulation dans le formulaire.

33
Robert Petermeier

Enveloppez votre appel avec SwingUtilities.invokeLater afin qu'il se produise une fois que tous les événements AWT en attente ont été traités:

pricePerLiter.addFocusListener(new Java.awt.event.FocusAdapter() {
    public void focusGained(Java.awt.event.FocusEvent evt) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                pricePerLiter.selectAll();
            }
        });
    }
});
66
Eugene Ryzhikov

En plus de ce qui précède, si vous le souhaitez pour tous les champs de texte, vous pouvez simplement faire:

KeyboardFocusManager.getCurrentKeyboardFocusManager()
    .addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener()
{
    public void propertyChange(final PropertyChangeEvent e)
    {
        if (e.getNewValue() instanceof JTextField)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    JTextField textField = (JTextField)e.getNewValue();
                    textField.selectAll();
                }
            });

        }
    }
});
14
camickr

Je sais que c'est un peu vieux, mais j'ai trouvé une solution plus propre, sans invokeLater:

private class SelectAllOfFocus extends FocusAdapter {

    @Override
    public void focusGained(FocusEvent e) {
        if (! e.isTemporary()) {
            JFormattedTextField textField = (JFormattedTextField)e.getComponent();
            // This is needed to put the text field in edited mode, so that its processFocusEvent doesn't
            // do anything. Otherwise, it calls setValue, and the selection is lost.
            textField.setText(textField.getText());
            textField.selectAll();
        }
    }

}
7
Adrien Clerc

C'est parce que le JFormattedTextfield remplace processFocusEvent pour formater le focus gagné/focus perdu.

Une méthode sûre consiste à étendre JFormattedTextField et à remplacer la méthode processFocusEvent:

new JFormattedTextField("...") {  
        protected void processFocusEvent(FocusEvent e) {  
            super.processFocusEvent(e);  
            if (e.isTemporary())  
                return;  
            SwingUtilities.invokeLater(new Runnable() {  
                @Override  
                public void run() {  
                    selectAll();  
                }   
            });  
        }  
    };

L'utilisation d'un focusListener peut ne pas toujours fonctionner ... car cela dépend du moment auquel il est appelé par rapport à processFocusEvent.

6
pavan

Le code de camickr peut être légèrement amélioré. Lorsque le focus passe d'un JTextField à un autre type de composant (tel qu'un bouton), la dernière sélection automatique n'est pas effacée. Il peut être résolu de cette façon:

    KeyboardFocusManager.getCurrentKeyboardFocusManager()
        .addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener()
    {
        @Override
        public void propertyChange(final PropertyChangeEvent e)
        {

            if (e.getOldValue() instanceof JTextField)
            {
                    SwingUtilities.invokeLater(new Runnable()
                    {
                            @Override
                            public void run()
                            {
                                    JTextField oldTextField = (JTextField)e.getOldValue();
                                    oldTextField.setSelectionStart(0);
                                    oldTextField.setSelectionEnd(0);
                            }
                    });

            }

            if (e.getNewValue() instanceof JTextField)
            {
                    SwingUtilities.invokeLater(new Runnable()
                    {
                            @Override
                            public void run()
                            {
                                    JTextField textField = (JTextField)e.getNewValue();
                                    textField.selectAll();
                            }
                    });

            }
        }
    });
2
user231765