java AutoComplete JTextField / JTextArea

Daniel Traub

Grünschnabel
Hallo,

wer seine GUI benutzerfreundlich gestalten möchte, hat sich sicher schon gefragt, wie er eine Texteingabe automatisch komplettieren kann. Es gibt ein Modul von SwingLabs, das eine Liste möglicher Treffer in einer JCheckBox anzeigt (habe gerade leider keinen Link zur Hand). Muss man aber eine grosse Menge an Daten eingeben, zB in eine Datenbank, kann es schneller sein, wenn der erste Treffer gleich im Textfeld steht. Hier stelle ich eine experimentelle Implementierung vor:

1. eine Liste möglicher Treffer wird erstellt
2. bei Texteingabe wird diese nach einem Treffer durchsucht
3. der fehlende Text wird angehängt
4. der angehängte Text wird selektiert, damit man auch ein neues Wort problemlos eingeben kann.

Bei einer grossen Datenmenge und einer schnellen Schreibgeschwindigkeit wird diese Implementieruing ziemlich buggy, für kleinere Apps funktioniert sie auf gängigen Rechnern aber einigermassen zufriedenstellend.

Java:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
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 {
    static JTextField textfield;

    static List<String> treffer;

    public static void main(String args[]) {

        treffer = new ArrayList<String>();
        treffer.add("auto complete");
        treffer.add("autobahn");
        treffer.add("benutzerfreundlichkeit");
        Collections.sort(treffer);

        JFrame frame = new JFrame("autocomplete");
        JPanel panel = new JPanel();
        textfield = new JTextField(20);
        panel.add(textfield);
        frame.add(panel);
        frame.setVisible(true);
        frame.pack();
        
        String tt = "<html><b>AutoComplete JTextField</b><br>please type \"<b>autobahn</b>\" or \"<b>benutzerkontrollzentrum</b>\"";
        textfield.setToolTipText(tt);

        autoComplete();
    }

    private static void autoComplete() {
        // TODO Auto-generated method stub
        textfield.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void changedUpdate(DocumentEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void insertUpdate(DocumentEvent ev) {
                // TODO Auto-generated method stub
                String completion;
                int pos = ev.getOffset();
                String content = null;
                try {
                    content = textfield.getText(0, pos + 1);
                } catch (BadLocationException ex) {
                    // TODO Auto-generated catch block
                    ex.printStackTrace();
                }

                int w;
                for (w = pos; w >= 0; w--) {
                }
                if (pos - w < 2) {
                    return;
                }

                String prefix = content.substring(w + 1);
                int n = Collections.binarySearch(treffer, prefix);
                if (n < 0 && -n <= treffer.size()) {
                    String match = treffer.get(-n - 1);
                    if (match.startsWith(prefix)) {
                        completion = match.substring(pos - w);
                        SwingUtilities.invokeLater(new CompletionTask(
                                completion, pos + 1));
                    }
                }

            }

            @Override
            public void removeUpdate(DocumentEvent arg0) {
                // TODO Auto-generated method stub

            }

        });

    }

    private static class CompletionTask implements Runnable {

        String completion;

        int position;

        CompletionTask(String completion, int position) {
            this.completion = completion;
            this.position = position;
        }

        public void run() {
            textfield.setText(textfield.getText() + completion);
            textfield.setCaretPosition(position + completion.length());
            textfield.moveCaretPosition(position);
        }
    }

}
 
Zurück