title: Java Swing: Controlling focus with textfield and autocompletion dialog/menu
body: <p>I have a <code>JTextField</code> that I'm trying to add an autocompletion menu to. But I'm having issues with how I should handle the focus.</p>
  
  <p>Here's a <a href="http://sscce.org/" rel="nofollow noreferrer">SSCCE</a></p>
  
  <pre><code>package test;
  
  import java.awt.Point;
  
  import javax.swing.JDialog;
  import javax.swing.JFrame;
  import javax.swing.JList;
  import javax.swing.JTextField;
  import javax.swing.SwingUtilities;
  import javax.swing.event.DocumentEvent;
  import javax.swing.event.DocumentListener;
  
  public class SSCCE extends JFrame implements DocumentListener {
      private AutocompletionDialog dialog;
  
      public SSCCE() {
          dialog = new AutocompletionDialog ();
  
          JTextField textField = new JTextField(20);
          textField.getDocument().addDocumentListener(this);
  
          add(textField);
          setDefaultCloseOperation(EXIT_ON_CLOSE);
          pack();
      }
  
      public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                  new SSCCE().setVisible(true);
              }
          });
      }
  
      public void insertUpdate(DocumentEvent e) {
          Point p = this.getLocationOnScreen();
          dialog.setLocation(p.x, p.y + 50);
          dialog.setVisible(true);
      }
  
      public void removeUpdate(DocumentEvent e) { }
      public void changedUpdate(DocumentEvent e) { }
  
      private class AutocompletionDialog extends JDialog {
          JList&lt;String&gt; list = new JList&lt;&gt;(
                  new String[] { "One", "Two", "Three" });
  
          AutocompletionDialog() {
              setSize(100, 100);
              add(list);
          }
      }
  }
  </code></pre>
  
  <p>Of course there's more logic to it in the real program, but the issue I'm having is that I want to show the autocompletion dialog/menu, but still be able to continue typing in the text field. At the same time, I also want to be able to navigate the menu with the up/down arrows and the enter key, as well as with the mouse, to select one of the completion options.</p>
  
  <p>Can someone please help me with how I should proceed here? Thanks!</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>Thanks to <a href="https://stackoverflow.com/users/131872/camickr">@camickr</a>'s reply I played around a bit with <code>setFocusableWindowState</code> together with an InputMap/ActionMap to always keep the focus in the text field, and manually control the selected list item. The problem is that you get a visual difference when doing it that way compared to if the list had proper focus. See the screen shots.</p>
  
  <p>This is what it looks like if I don't mess with the focus (this is what I want).</p>
  
  <p><img src="https://i.stack.imgur.com/jIcgx.png" alt="dialog with proper focus"></p>
  
  <p>This is what it looks like if I run <code>setFocusableWindowState(false)</code></p>
  
  <p><img src="https://i.stack.imgur.com/ie39d.png" alt="dialog with no focus"></p>
  
  <p>The main differences are the highlight border (darker blue) around the selected list item, but also the blue highlight around the entire dialog. Then there's also the differences in the title bar.</p>
  
  <p>(Don't mind the render artifacts, I'm connecting to a three year old virtual Linux installation using an old NX client)</p>
  
  <p><strong>EDIT 2:</strong></p>
  
  <p>I was afraid that it was the Look and Feel or OS that determined how the selected list item should look (with the highlighted border for example). But it turns out that it is indeed just the cell renderer that makes that call. Knowing that I felt much better about writing my own cell renderer, and I now have a solution that I'm happy with.</p>
  
  <p>This is the code I ended up using:</p>
  
  <pre><code>private class CellRenderer extends DefaultListCellRenderer
  {
      @Override
      public Component getListCellRendererComponent(
              JList&lt;?&gt; jlist, Object value, int index,
              boolean isSelected, boolean cellHasFocus) {
          super.getListCellRendererComponent(
                  jlist, value, index, isSelected, cellHasFocus);
  
          if (isSelected) {
              Border border = UIManager.getBorder(
                      "List.focusSelectedCellHighlightBorder");
  
              if (border == null) {
                  border = UIManager.getBorder(
                          "List.focusCellHighlightBorder");
              }
  
              setBorder(border);
          }
  
          return this;
      }
  }
  </code></pre>