Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a autocompleting textbox in Java with a dropdown list

I want to create a auto-suggest text box which would query the database at each key release event. That part is easy, but I want to give nice visual to it. Something similar to the auto-suggest text box we see in websites like searching in Facebook.

How to make such an interface ?

A naive idea would be to have a JList placed just below the text box and set it visible with the results in it on finding one.

Any better idea or a standard way of doing it?

like image 745
jairaj Avatar asked Jan 06 '13 21:01

jairaj


People also ask

How do you create a drop down box in Java?

Create a Dropdown Menu Using JComboBox in Java Below, we first create the array of options to display in the dropdown list. JComboBox is a component and needs a frame to reside, so we create a JFrame object. Then, we create the JComboBox object and pass the options array as its argument in the constructor.


3 Answers

@syb0rg's answer is easier, as it uses an 3rd party library.

However I used an alternate approach:

It uses a custom class called AutoSuggestor which accepts a JTextField, its Window an ArrayList<String> of words to check typed words against, a background color and text color, and suggestion focus colour as well as an opacity value. By passing JTextField reference a DocumentListener is added which will do the work of checking what word is typed and whether to display suggestions or not and if so what suggestions to display. When a word is typed the DocumentListener will firewordTyped(String wordTyped) method with the current word being typed or (at least how much ever of the word has been typed), in wordTyped(..) the word will be checked against those in the AutoSuggestors classes dictionary which is a basic ArrayList of String this can be set on the fly as seen in the below example:

enter image description here

(For now you will have to use mouse and click the word you want to be auto completed, or use DOWN to transverse suggestions and the textfield and ENTER to select suggestion when traversing using down key. I have not yet implemented UP yet):

import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.JWindow; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.border.LineBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener;  /**  * @author David  */ public class Test {      public Test() {          JFrame frame = new JFrame();         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);           JTextField f = new JTextField(10);          AutoSuggestor autoSuggestor = new AutoSuggestor(f, frame, null, Color.WHITE.brighter(), Color.BLUE, Color.RED, 0.75f) {             @Override             boolean wordTyped(String typedWord) {                  //create list for dictionary this in your case might be done via calling a method which queries db and returns results as arraylist                 ArrayList<String> words = new ArrayList<>();                 words.add("hello");                 words.add("heritage");                 words.add("happiness");                 words.add("goodbye");                 words.add("cruel");                 words.add("car");                 words.add("war");                 words.add("will");                 words.add("world");                 words.add("wall");                   setDictionary(words);                 //addToDictionary("bye");//adds a single word                  return super.wordTyped(typedWord);//now call super to check for any matches against newest dictionary             }         };          JPanel p = new JPanel();          p.add(f);          frame.add(p);          frame.pack();         frame.setVisible(true);     }      public static void main(String[] args) {         SwingUtilities.invokeLater(new Runnable() {             @Override             public void run() {                 new Test();             }         });     } }  class AutoSuggestor {      private final JTextField textField;     private final Window container;     private JPanel suggestionsPanel;     private JWindow autoSuggestionPopUpWindow;     private String typedWord;     private final ArrayList<String> dictionary = new ArrayList<>();     private int currentIndexOfSpace, tW, tH;     private DocumentListener documentListener = new DocumentListener() {         @Override         public void insertUpdate(DocumentEvent de) {             checkForAndShowSuggestions();         }          @Override         public void removeUpdate(DocumentEvent de) {             checkForAndShowSuggestions();         }          @Override         public void changedUpdate(DocumentEvent de) {             checkForAndShowSuggestions();         }     };     private final Color suggestionsTextColor;     private final Color suggestionFocusedColor;      public AutoSuggestor(JTextField textField, Window mainWindow, ArrayList<String> words, Color popUpBackground, Color textColor, Color suggestionFocusedColor, float opacity) {         this.textField = textField;         this.suggestionsTextColor = textColor;         this.container = mainWindow;         this.suggestionFocusedColor = suggestionFocusedColor;         this.textField.getDocument().addDocumentListener(documentListener);          setDictionary(words);          typedWord = "";         currentIndexOfSpace = 0;         tW = 0;         tH = 0;          autoSuggestionPopUpWindow = new JWindow(mainWindow);         autoSuggestionPopUpWindow.setOpacity(opacity);          suggestionsPanel = new JPanel();         suggestionsPanel.setLayout(new GridLayout(0, 1));         suggestionsPanel.setBackground(popUpBackground);          addKeyBindingToRequestFocusInPopUpWindow();     }      private void addKeyBindingToRequestFocusInPopUpWindow() {         textField.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "Down released");         textField.getActionMap().put("Down released", new AbstractAction() {             @Override             public void actionPerformed(ActionEvent ae) {//focuses the first label on popwindow                 for (int i = 0; i < suggestionsPanel.getComponentCount(); i++) {                     if (suggestionsPanel.getComponent(i) instanceof SuggestionLabel) {                         ((SuggestionLabel) suggestionsPanel.getComponent(i)).setFocused(true);                         autoSuggestionPopUpWindow.toFront();                         autoSuggestionPopUpWindow.requestFocusInWindow();                         suggestionsPanel.requestFocusInWindow();                         suggestionsPanel.getComponent(i).requestFocusInWindow();                         break;                     }                 }             }         });         suggestionsPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "Down released");         suggestionsPanel.getActionMap().put("Down released", new AbstractAction() {             int lastFocusableIndex = 0;              @Override             public void actionPerformed(ActionEvent ae) {//allows scrolling of labels in pop window (I know very hacky for now :))                  ArrayList<SuggestionLabel> sls = getAddedSuggestionLabels();                 int max = sls.size();                  if (max > 1) {//more than 1 suggestion                     for (int i = 0; i < max; i++) {                         SuggestionLabel sl = sls.get(i);                         if (sl.isFocused()) {                             if (lastFocusableIndex == max - 1) {                                 lastFocusableIndex = 0;                                 sl.setFocused(false);                                 autoSuggestionPopUpWindow.setVisible(false);                                 setFocusToTextField();                                 checkForAndShowSuggestions();//fire method as if document listener change occured and fired it                              } else {                                 sl.setFocused(false);                                 lastFocusableIndex = i;                             }                         } else if (lastFocusableIndex <= i) {                             if (i < max) {                                 sl.setFocused(true);                                 autoSuggestionPopUpWindow.toFront();                                 autoSuggestionPopUpWindow.requestFocusInWindow();                                 suggestionsPanel.requestFocusInWindow();                                 suggestionsPanel.getComponent(i).requestFocusInWindow();                                 lastFocusableIndex = i;                                 break;                             }                         }                     }                 } else {//only a single suggestion was given                     autoSuggestionPopUpWindow.setVisible(false);                     setFocusToTextField();                     checkForAndShowSuggestions();//fire method as if document listener change occured and fired it                 }             }         });     }      private void setFocusToTextField() {         container.toFront();         container.requestFocusInWindow();         textField.requestFocusInWindow();     }      public ArrayList<SuggestionLabel> getAddedSuggestionLabels() {         ArrayList<SuggestionLabel> sls = new ArrayList<>();         for (int i = 0; i < suggestionsPanel.getComponentCount(); i++) {             if (suggestionsPanel.getComponent(i) instanceof SuggestionLabel) {                 SuggestionLabel sl = (SuggestionLabel) suggestionsPanel.getComponent(i);                 sls.add(sl);             }         }         return sls;     }      private void checkForAndShowSuggestions() {         typedWord = getCurrentlyTypedWord();          suggestionsPanel.removeAll();//remove previos words/jlabels that were added          //used to calcualte size of JWindow as new Jlabels are added         tW = 0;         tH = 0;          boolean added = wordTyped(typedWord);          if (!added) {             if (autoSuggestionPopUpWindow.isVisible()) {                 autoSuggestionPopUpWindow.setVisible(false);             }         } else {             showPopUpWindow();             setFocusToTextField();         }     }      protected void addWordToSuggestions(String word) {         SuggestionLabel suggestionLabel = new SuggestionLabel(word, suggestionFocusedColor, suggestionsTextColor, this);          calculatePopUpWindowSize(suggestionLabel);          suggestionsPanel.add(suggestionLabel);     }      public String getCurrentlyTypedWord() {//get newest word after last white spaceif any or the first word if no white spaces         String text = textField.getText();         String wordBeingTyped = "";         if (text.contains(" ")) {             int tmp = text.lastIndexOf(" ");             if (tmp >= currentIndexOfSpace) {                 currentIndexOfSpace = tmp;                 wordBeingTyped = text.substring(text.lastIndexOf(" "));             }         } else {             wordBeingTyped = text;         }         return wordBeingTyped.trim();     }      private void calculatePopUpWindowSize(JLabel label) {         //so we can size the JWindow correctly         if (tW < label.getPreferredSize().width) {             tW = label.getPreferredSize().width;         }         tH += label.getPreferredSize().height;     }      private void showPopUpWindow() {         autoSuggestionPopUpWindow.getContentPane().add(suggestionsPanel);         autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textField.getWidth(), 30));         autoSuggestionPopUpWindow.setSize(tW, tH);         autoSuggestionPopUpWindow.setVisible(true);          int windowX = 0;         int windowY = 0;          windowX = container.getX() + textField.getX() + 5;         if (suggestionsPanel.getHeight() > autoSuggestionPopUpWindow.getMinimumSize().height) {             windowY = container.getY() + textField.getY() + textField.getHeight() + autoSuggestionPopUpWindow.getMinimumSize().height;         } else {             windowY = container.getY() + textField.getY() + textField.getHeight() + autoSuggestionPopUpWindow.getHeight();         }          autoSuggestionPopUpWindow.setLocation(windowX, windowY);         autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textField.getWidth(), 30));         autoSuggestionPopUpWindow.revalidate();         autoSuggestionPopUpWindow.repaint();      }      public void setDictionary(ArrayList<String> words) {         dictionary.clear();         if (words == null) {             return;//so we can call constructor with null value for dictionary without exception thrown         }         for (String word : words) {             dictionary.add(word);         }     }      public JWindow getAutoSuggestionPopUpWindow() {         return autoSuggestionPopUpWindow;     }      public Window getContainer() {         return container;     }      public JTextField getTextField() {         return textField;     }      public void addToDictionary(String word) {         dictionary.add(word);     }      boolean wordTyped(String typedWord) {          if (typedWord.isEmpty()) {             return false;         }         //System.out.println("Typed word: " + typedWord);          boolean suggestionAdded = false;          for (String word : dictionary) {//get words in the dictionary which we added             boolean fullymatches = true;             for (int i = 0; i < typedWord.length(); i++) {//each string in the word                 if (!typedWord.toLowerCase().startsWith(String.valueOf(word.toLowerCase().charAt(i)), i)) {//check for match                     fullymatches = false;                     break;                 }             }             if (fullymatches) {                 addWordToSuggestions(word);                 suggestionAdded = true;             }         }         return suggestionAdded;     } }  class SuggestionLabel extends JLabel {      private boolean focused = false;     private final JWindow autoSuggestionsPopUpWindow;     private final JTextField textField;     private final AutoSuggestor autoSuggestor;     private Color suggestionsTextColor, suggestionBorderColor;      public SuggestionLabel(String string, final Color borderColor, Color suggestionsTextColor, AutoSuggestor autoSuggestor) {         super(string);          this.suggestionsTextColor = suggestionsTextColor;         this.autoSuggestor = autoSuggestor;         this.textField = autoSuggestor.getTextField();         this.suggestionBorderColor = borderColor;         this.autoSuggestionsPopUpWindow = autoSuggestor.getAutoSuggestionPopUpWindow();          initComponent();     }      private void initComponent() {         setFocusable(true);         setForeground(suggestionsTextColor);          addMouseListener(new MouseAdapter() {             @Override             public void mouseClicked(MouseEvent me) {                 super.mouseClicked(me);                  replaceWithSuggestedText();                  autoSuggestionsPopUpWindow.setVisible(false);             }         });          getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), "Enter released");         getActionMap().put("Enter released", new AbstractAction() {             @Override             public void actionPerformed(ActionEvent ae) {                 replaceWithSuggestedText();                 autoSuggestionsPopUpWindow.setVisible(false);             }         });     }      public void setFocused(boolean focused) {         if (focused) {             setBorder(new LineBorder(suggestionBorderColor));         } else {             setBorder(null);         }         repaint();         this.focused = focused;     }      public boolean isFocused() {         return focused;     }      private void replaceWithSuggestedText() {         String suggestedWord = getText();         String text = textField.getText();         String typedWord = autoSuggestor.getCurrentlyTypedWord();         String t = text.substring(0, text.lastIndexOf(typedWord));         String tmp = t + text.substring(text.lastIndexOf(typedWord)).replace(typedWord, suggestedWord);         textField.setText(tmp + " ");     } } 

As it stands the only possible needed additions IMO is:

  • UP key Focus traversablity for items within the popup autosuggestions box so we can go in a upward direction.

If there are any kinks lemme know I'll see what I can do. But Seems to be running fine (touch wood).

like image 71
David Kroukamp Avatar answered Sep 30 '22 11:09

David Kroukamp


A really easy way to do this is to use the GlazedList implementation of auto-completion. It's very easy to get up and running. You can find it here.

You can install the auto-complete on a JComboBox with only one line of Glazed code, like this:

JComboBox comboBox = new JComboBox();
Object[] elements = new Object[] {"Cat", "Dog", "Lion", "Mouse"};
AutoCompleteSupport.install(comboBox, GlazedLists.eventListOf(elements));

Also SwingX supports auto-complete and might be easier to use than GlazedList. All you write with SwingX is AutoCompleteDecorator.decorate(comboBox);

like image 35
syb0rg Avatar answered Sep 30 '22 11:09

syb0rg


To use TextAutoCompleter class you need to download a jar file AutoCompleter.jar and add it to library folder of your project and here is the link to download: http://download1689.mediafire.com/4grrthscpsug/7pwzgefiomu392o/AutoCompleter.jar -Nawin

//In the Main class write the following code

package autocomplete;

import com.mxrck.autocompleter.TextAutoCompleter;
import java.sql.SQLException;
import javax.swing.JFrame;
import javax.swing.JTextField;


public class AutoComplete {
    JFrame f=new JFrame();
    JTextField t1;
AutoComplete() throws ClassNotFoundException, SQLException{

    f.setSize(500,500);
    f.setLocation(500,100);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setLayout(null);
    f.setVisible(true);


    t1=new JTextField();
    t1.setBounds(50,80,200,20);
    f.add(t1);


    TextAutoCompleter complete=new TextAutoCompleter(t1);
    DBConn conn=new DBConn();
        conn.connection();
        conn.retrieve();
    while(conn.rs.next()){

        complete.addItem(conn.rs.getString("number"));
    }


}


    public static void main(String[] args) throws ClassNotFoundException,
    SQLException{           

        new AutoComplete();
   }

}


//Create seperate class for database connection and write the following code


package autocomplete;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class DBConn {

    Connection con; ResultSet rs;PreparedStatement stat;

public void connection() throws ClassNotFoundException, SQLException{
    String url="jdbc:mysql://localhost:3306/";
    String driver="com.mysql.jdbc.Driver";   
    String db="demo";
    String username="root";
    String password="root";
    stat =null; 

        Class.forName(driver);
       con=(Connection)DriverManager.getConnection
       (url+db,username,password);              
        System.out.println("Connecttion SuccessFul");
}  

public void retrieve() throws SQLException{

    Statement  stmt=con.createStatement();
    String query="select number from phone";
    rs = stmt.executeQuery(query);

    System.out.println("retrieve succesfully");

}

}

like image 43
nawin khatiwada Avatar answered Sep 30 '22 12:09

nawin khatiwada