Ejemplo: agregar autocompletar a JTextField

    El autocompletar puede ser muy útil en casi cualquier aplicación, pero no es trivial de implementar. Así que aquí hay un ejemplo rápido de cómo podría hacerlo en el marco Swing de Java con JTextField (también debería funcionar con JTextArea con solo unas pocas modificaciones). Este ejemplo es una versión modificada de El ejemplo de Oracle.

    El código

    package com.example.myapp.console;
    
    import java.awt.event.ActionEvent;
    import java.util.Collections;
    import java.util.List;
    
    import javax.swing.AbstractAction;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    import javax.swing.event.DocumentEvent;
    import javax.swing.event.DocumentListener;
    import javax.swing.text.BadLocationException;
    
    public class Autocomplete implements DocumentListener {
    
      private static enum Mode {
        INSERT,
        COMPLETION
      };
    
      private JTextField textField;
      private final List<String> keywords;
      private Mode mode = Mode.INSERT;
    
      public Autocomplete(JTextField textField, List<String> keywords) {
        this.textField = textField;
        this.keywords = keywords;
        Collections.sort(keywords);
      }
    
      @Override
      public void changedUpdate(DocumentEvent ev) { }
    
      @Override
      public void removeUpdate(DocumentEvent ev) { }
    
      @Override
      public void insertUpdate(DocumentEvent ev) {
        if (ev.getLength() != 1)
          return;
     
        int pos = ev.getOffset();
        String content = null;
        try {
          content = textField.getText(0, pos + 1);
        } catch (BadLocationException e) {
          e.printStackTrace();
        }
     
        // Find where the word starts
        int w;
        for (w = pos; w >= 0; w--) {
          if (!Character.isLetter(content.charAt(w))) {
            break;
          }
        }
    
        // Too few chars
        if (pos - w < 2)
          return;
     
        String prefix = content.substring(w + 1).toLowerCase();
        int n = Collections.binarySearch(keywords, prefix);
        if (n < 0 && -n <= keywords.size()) {
          String match = keywords.get(-n - 1);
          if (match.startsWith(prefix)) {
            // A completion is found
            String completion = match.substring(pos - w);
            // We cannot modify Document from within notification,
            // so we submit a task that does the change later
            SwingUtilities.invokeLater(new CompletionTask(completion, pos + 1));
          }
        } else {
          // Nothing found
          mode = Mode.INSERT;
        }
      }
    
      public class CommitAction extends AbstractAction {
        /**
         * 
         */
        private static final long serialVersionUID = 5794543109646743416L;
    
        @Override
        public void actionPerformed(ActionEvent ev) {
          if (mode == Mode.COMPLETION) {
            int pos = textField.getSelectionEnd();
            StringBuffer sb = new StringBuffer(textField.getText());
            sb.insert(pos, " ");
            textField.setText(sb.toString());
            textField.setCaretPosition(pos + 1);
            mode = Mode.INSERT;
          } else {
            textField.replaceSelection("t");
          }
        }
      }
    
      private class CompletionTask implements Runnable {
        private String completion;
        private int position;
     
        CompletionTask(String completion, int position) {
          this.completion = completion;
          this.position = position;
        }
     
        public void run() {
          StringBuffer sb = new StringBuffer(textField.getText());
          sb.insert(position, completion);
          textField.setText(sb.toString());
          textField.setCaretPosition(position + completion.length());
          textField.moveCaretPosition(position);
          mode = Mode.COMPLETION;
        }
      }
    
    }
    

    Usando el código

    private static final String COMMIT_ACTION = "commit";
    JTextField mainTextField = new JTextField();
    
    // Without this, cursor always leaves text field
    mainTextField.setFocusTraversalKeysEnabled(false);
    ...
    // Our words to complete
    keywords = new ArrayList<String>(5);
            keywords.add("example");
            keywords.add("autocomplete");
            keywords.add("Pharos.sh");
            keywords.add("java");
    Autocomplete autoComplete = new Autocomplete(mainTextField, keywords);
    mainTextField.getDocument().addDocumentListener(autoComplete);
    
    // Maps the tab key to the commit action, which finishes the autocomplete
    // when given a suggestion
    mainTextField.getInputMap().put(KeyStroke.getKeyStroke("TAB"), COMMIT_ACTION);
    mainTextField.getActionMap().put(COMMIT_ACTION, autoComplete.new CommitAction());
    

    Si desea que la lista de palabras clave cambie con el tiempo en su aplicación (por ejemplo, si está completando automáticamente los nombres de amigos en línea en una aplicación de chat), todo lo que necesita hacer es agregar un método de establecimiento a Autocomplete para List<String> keywords y actualice la lista de palabras clave con la lista de Strings usted quiere.

     

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *