JSuggestionPanel (AKA JSuggestionField, CompletionTextField)
Also known as a JTextField that magically have a list appear after you hit ENTER or CompletionTextField.
Since I have not found a open source or version that is purchasable I decided to hack one together today and give it freely to the world. Hopefully this helps some one.
Here are my sources:
Java 1.5 API (Of Course)
Ok starting with the SuggestionPanel itself:
1 2 3 4 5 6 7 8 9 | package com.mdb.widgets; import com.mdb.interfaces.SearchableListModel; import com.mdb.objects.DefaultSearchableListModel; import java.awt.event.KeyEvent; import java.io.Serializable; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.ListSelectionModel; import org.jdesktop.layout.GroupLayout; |
1 2 3 4 5 | /** * @author David Durst */ public class SuggestionPanel extends JPanel implements Serializable { |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | private JList list; private Object selectedItem; private boolean list_visible = false; private SearchableListModel model = new DefaultSearchableListModel(); public SuggestionPanel() { initComponents(); list = new JList(); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); list.setModel(model); list.addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent evt) { jListKeyPressed(evt); } }); jPopupMenu1.add(list); } private void initComponents() { jPopupMenu1 = new javax.swing.JPopupMenu(); searchStringTextField = new javax.swing.JTextField(); searchStringTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent evt) { searchStringTextFieldKeyPressed(evt); } }); GroupLayout layout = new GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(searchStringTextField,GroupLayout.DEFAULT_SIZE, 197, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.LEADING) .add(searchStringTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ); } private void jListKeyPressed(KeyEvent evt) { int kc = evt.getKeyCode(); if(kc == KeyEvent.VK_ENTER) { jPopupMenu1.setVisible(false); selectedItem = model.getElementAt(list.getSelectedIndex()); searchStringTextField.setText(selectedItem.toString()); list_visible = false; } } private void searchStringTextFieldKeyPressed(java.awt.event.KeyEvent evt) { int kc = evt.getKeyCode(); if(kc == KeyEvent.VK_ENTER) { String searchString = searchStringTextField.getText(); model.search(searchString); jPopupMenu1.show(this,searchStringTextField.getX(),searchStringTextField.getY()+searchStringTextField.getHeight()); list_visible = true; list.requestFocus(); list.setSelectedIndex(list.getMinSelectionIndex()); } else if(kc == KeyEvent.VK_DOWN && list_visible) { list.requestFocus(); int index = list.getSelectedIndex(); index++; if(index > list.getMaxSelectionIndex()) list.setSelectedIndex(list.getMinSelectionIndex()); else list.setSelectedIndex(index); } else if(kc == KeyEvent.VK_UP && list_visible) { list.requestFocus(); int index = list.getSelectedIndex(); index--; if(index < list.getMinSelectionIndex()) list.setSelectedIndex(list.getMaxSelectionIndex()); else list.setSelectedIndex(index); } } private javax.swing.JPopupMenu jPopupMenu1; private javax.swing.JTextField searchStringTextField; public SearchableListModel getModel() { return model; } public void setModel(SearchableListModel model) { list.setModel(model); this.model = model; } public Object getSelectedItem() { return selectedItem; } } |
Now on to the Interface for extending ListModel:
1 2 3 4 5 6 7 8 9 | package com.mdb.interfaces; import javax.swing.ListModel; /** * @author David Durst */ public interface SearchableListModel extends ListModel { public void search(String text); } |
And now to the implementing class DefaultSearchableListModel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package com.mdb.objects; import com.mdb.interfaces.SearchableListModel; import java.util.List; import java.util.Vector; import javax.swing.DefaultListModel; /** * @author David Durst */ public class DefaultSearchableListModel extends DefaultListModel implements SearchableListModel { private List list = new Vector(); public DefaultSearchableListModel() { list.add("Testing"); list.add("David Smith"); list.add("Ron Johnson"); list.add("Nick Smith"); } public void clear() { while(getSize() != 0) { remove(getSize()-1); } } public void search(final String text) { clear(); String searchString = text.toLowerCase(); for(Object o : list) { String os = o.toString(); os = os.toLowerCase(); if(os.contains(searchString)) { addElement(o); } } } } |
Attaching this to a Database should be fairly simple, you can hack that into a class that implements SearchableListModel, or
do some other type of magical binding vodoo.
Here is a Screen Shot