tags:

views:

1704

answers:

4

I have a small Java desktop app that uses Swing. There is a data entry dialog with some input fields of different types (JTextField, JComboBox, JSpinner, JFormattedTextField). When I activate the JFormattedTextFields either by tabbing through the form or by clicking it with the mouse, I would like it to select all the text that it currently contains. That way, users could just start typing and overwrite the default values.

How can I do that? I did use a FocusListener/FocusAdapter that calls selectAll() on the JFormattedTextField, but it doesn't select anything, although the FocusAdapter's focusGained() method is called (see code sample below).

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();
    }
});

Any ideas? The funny thing is that selecting all of its text apparently is the default behavior for both JTextField and JSpinner, at least when tabbing through the form.

+8  A: 

Wrap your call with SwingUtilities.invokeLater so it will happen after all pending AWT events have been processed :

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();  
        }
       });
         }
     });
eugener
Thanks, that's it. I can only guess that the NumberFormatter is doing something that undoes the selectAll()?
Robert Petermeier
Yes it does. It formats the value and resets the text.
eugener
+1 Needed this, could not remember instantly how to do this my self, googled and immediately found this answer. Thanks!
cg
+2  A: 

Thats because the JFormattedTextfield overrides processFocusEvent to format on focus gained/focus lost.

One sure shot way is to extend JFormattedTextField and override the processFocusEvent method :

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

Using a focusListener might not always work..since it would depend on the time at which it is called relative to the processFocusEvent.

pavan
+2  A: 

In addition to the above, if you want this for all text fields you can just do:

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();
       }
      });

     }
    }
});
camickr
A: 

The code of camickr can be slightly improved. When the focus passes from a JTextField to another kind of component (such a button), the last automatic selection does not get cleared. It can be fixed this way:

    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();
                            }
                    });

            }
        }
    });