Is there an easy way to change the behavior of a Java/Swing control when it gets focus?

For most GUI's I've used, when a control that contains text gets the focus, the entire contents of the control are selected. This means if you just start typing, you completely replace the former contents.

Example: You have spin control that is initialized with the value zero. You tab to it and type "1" The value in the control is now 1.

With Swing, this doesn't happen. The text in the control is not selected and the carat appears at one end or another of the existing text. Continuing the above example:

With a Swing JSpinner, when you tab to the spin control, the carat is at the left. You type "1" and the value in the control is now 10.

This drives me, (and my users) up a wall, and I'd like to change it. Even more important, I'd like to change it globally so the new behavior applies to JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner, and so on. The only way I have found to do this to add a FocusAdapter to each control and override the focusGained() method to Do The Right Thing[tm].

There's gotta be an easier, and less fragile way. Please?

EDIT: One additional piece of information for this particular case. The form I am working with was generated using Idea's form designer. That means I normally don't actually write the code to create the components. It is possible to tell Idea that you want to create them yourself, but that's a hassle I'd like to avoid.

Motto: All good programmers are basically lazy.

Answers


When I've needed this in the past, I've created subclasses of the components I wanted to add "auto-clearing" functionality too. eg:

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

The biggest problem is that I haven't found a "good" way to get all the standard constructors without writing overrides. Adding them, and forcing a call to addListener is the most general approach I've found.

Another option is to watch for ContainerEvents on a top-level container with a ContainerListeer to detect the presence of new widgets, and add a corresponding focus listener based on the widgets that have been added. (eg: if the container event is caused by adding a TextField, then add a focus listener that knows how to select all the text in a TextField, and so on.) If a Container is added, then you need to recursively add the ContainerListener to that new sub-container as well.

Either way, you won't need to muck about with focus listeners in your actual UI code -- it will all be taken care of at a higher level.


I haven't tried this myself (only dabbled in it a while ago), but you can probably get the current focused component by using: KeyboardFocusManager (there is a static method getCurrentKeyboardFocusManager()) an adding a PropertyChangeListener to it. From there, you can find out if the component is a JTextComponent and select all text.


A separate class that attaches a FocusListener to the desired text field can be written. All the focus listener would do is call selectAll() on the text widget when it gains the 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);
  }
}

By accepting a JTextComponent as an argument this behavior can be added to JTextArea, JPasswordField, and all of the other text editing components directly. This also allows the class to add select all to editable combo boxes and JSpinners, where your control over the text editor component may be more limited. Convenience methods can be added:

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

Also, the remove listener methods are likely unneeded, since the listener contains no exterior references to any other instances, but they can be added to make code reviews go smoother.


Need Your Help

How can I embed a Unity project into an existing activity in an Android Studio project?

android unity3d

I have a problem: i need to embed a Unity Project inside an existing activity of an Android Studio project. The Unity project is made of only a single Scene. That scene is a 3D ambient with some sc...

RMarkdown: citecolor LaTeX option not being used

r latex markdown pandoc rmarkdown

I am trying to create a JSS article using RMarkdown, but am not able to get options that typically get used with pdf_document, in particular, the citecolor option.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.