How to list suggestions to when typing inside the

2020-01-31 12:33发布

问题:

Hi in my Java swing application I need to show all possible existing entries with same initial characters while user typing in a text field. Lets say user type letter 'A' in a text field which should be a country 'America' and 'Africa' would be suggestions. So that user can select one from the list. Country list resides in my database. I know how to retrieve data from DB. But I don't know how to list them and which components I should use to achieve. Can any one guide me? Or if you can provide an example, that would be great.

回答1:

You could use the autocomplete package from SwingX. Google for "swingx autocomplete" if you need more real life examples, but the simplest way is creating a JComboBox and calling AutoCompleteDecorator.decorate(comboBox); on it.



回答2:

You should try JComboBox as an autosuggest box instead of JTextField. But if you still want it to be done using JTextField then...

  1. Make a JPanel containing list of suggestion.Initially it will be not visible.
  2. Whenever user types something search for it and add results to the list in JPanel.
  3. Show that JPanel at the bottom of textfield in upper layer of frame.
  4. Implement click event on list so that when ever user clicks on it the text is copied to textfield.


回答3:

there are two classes (you are needed both for correct funcionalities), Auto Complete JTextField and AutoComplete JComboBox, excelent is that you can set if is strict (allows typing if List doesn't contains ) or not



回答4:

I had a similar problem:
I wanted a Textfield for free entering text, but with the possibility to suggest existing values.

I first found this post, but swingX hasn't allowed to enter text other than the suggested ones. Then I found an other post linking to this page: http://www.jroller.com/santhosh/date/20050620

Some modifications and I changed from directory selection to my own Strings. Might post this here for completion and the help for later searchers:

He made an abstract class AutoCompleter which handels the events:

// @author Santhosh Kumar T - santhosh@in.fiorano.com 
public abstract class AutoCompleter{ 
    JList list = new JList(); 
    JPopupMenu popup = new JPopupMenu(); 
    JTextComponent textComp; 
    private static final String AUTOCOMPLETER = "AUTOCOMPLETER"; //NOI18N 

    public AutoCompleter(JTextComponent comp){ 
        textComp = comp; 
        textComp.putClientProperty(AUTOCOMPLETER, this); 
        JScrollPane scroll = new JScrollPane(list); 
        scroll.setBorder(null); 

        list.setFocusable( false ); 
        scroll.getVerticalScrollBar().setFocusable( false ); 
        scroll.getHorizontalScrollBar().setFocusable( false ); 

        popup.setBorder(BorderFactory.createLineBorder(Color.black)); 
        popup.add(scroll); 

        if(textComp instanceof JTextField){ 
            textComp.registerKeyboardAction(showAction, KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), JComponent.WHEN_FOCUSED); 
            textComp.getDocument().addDocumentListener(documentListener); 
        }else 
            textComp.registerKeyboardAction(showAction, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_MASK), JComponent.WHEN_FOCUSED); 

        textComp.registerKeyboardAction(upAction, KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), JComponent.WHEN_FOCUSED); 
        textComp.registerKeyboardAction(hidePopupAction, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_FOCUSED); 

        popup.addPopupMenuListener(new PopupMenuListener(){ 
            public void popupMenuWillBecomeVisible(PopupMenuEvent e){ 
            } 

            public void popupMenuWillBecomeInvisible(PopupMenuEvent e){ 
                textComp.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)); 
            } 

            public void popupMenuCanceled(PopupMenuEvent e){ 
            } 
        }); 
        list.setRequestFocusEnabled(false); 
    } 

    static Action acceptAction = new AbstractAction(){ 
        public void actionPerformed(ActionEvent e){ 
            JComponent tf = (JComponent)e.getSource(); 
            AutoCompleter completer = (AutoCompleter)tf.getClientProperty(AUTOCOMPLETER); 
            completer.popup.setVisible(false); 
            completer.acceptedListItem((String)completer.list.getSelectedValue()); 
        } 
    }; 

    DocumentListener documentListener = new DocumentListener(){ 
        public void insertUpdate(DocumentEvent e){ 
            showPopup(); 
        } 

        public void removeUpdate(DocumentEvent e){ 
            showPopup(); 
        } 

        public void changedUpdate(DocumentEvent e){} 
    }; 

    private void showPopup(){ 
        popup.setVisible(false); 
        if(textComp.isEnabled() && updateListData() && list.getModel().getSize()!=0){ 
            if(!(textComp instanceof JTextField)) 
                textComp.getDocument().addDocumentListener(documentListener); 
            textComp.registerKeyboardAction(acceptAction, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED); 
            int size = list.getModel().getSize(); 
            list.setVisibleRowCount(size<10 ? size : 10); 

            int x = 0; 
            try{ 
                int pos = Math.min(textComp.getCaret().getDot(), textComp.getCaret().getMark()); 
                x = textComp.getUI().modelToView(textComp, pos).x; 
            } catch(BadLocationException e){ 
                // this should never happen!!! 
                e.printStackTrace(); 
            } 
            popup.show(textComp, x, textComp.getHeight()); 
        }else 
            popup.setVisible(false); 
        textComp.requestFocus(); 
    } 

    static Action showAction = new AbstractAction(){ 
        public void actionPerformed(ActionEvent e){ 
            JComponent tf = (JComponent)e.getSource(); 
            AutoCompleter completer = (AutoCompleter)tf.getClientProperty(AUTOCOMPLETER); 
            if(tf.isEnabled()){ 
                if(completer.popup.isVisible()) 
                    completer.selectNextPossibleValue(); 
                else 
                    completer.showPopup(); 
            } 
        } 
    }; 

    static Action upAction = new AbstractAction(){ 
        public void actionPerformed(ActionEvent e){ 
            JComponent tf = (JComponent)e.getSource(); 
            AutoCompleter completer = (AutoCompleter)tf.getClientProperty(AUTOCOMPLETER); 
            if(tf.isEnabled()){ 
                if(completer.popup.isVisible()) 
                    completer.selectPreviousPossibleValue(); 
            } 
        } 
    }; 

    static Action hidePopupAction = new AbstractAction(){ 
        public void actionPerformed(ActionEvent e){ 
            JComponent tf = (JComponent)e.getSource(); 
            AutoCompleter completer = (AutoCompleter)tf.getClientProperty(AUTOCOMPLETER); 
            if(tf.isEnabled()) 
                completer.popup.setVisible(false); 
        } 
    }; 

    /** 
     * Selects the next item in the list.  It won't change the selection if the 
     * currently selected item is already the last item. 
     */ 
    protected void selectNextPossibleValue(){ 
        int si = list.getSelectedIndex(); 

        if(si < list.getModel().getSize() - 1){ 
            list.setSelectedIndex(si + 1); 
            list.ensureIndexIsVisible(si + 1); 
        } 
    } 

    /** 
     * Selects the previous item in the list.  It won't change the selection if the 
     * currently selected item is already the first item. 
     */ 
    protected void selectPreviousPossibleValue(){ 
        int si = list.getSelectedIndex(); 

        if(si > 0){ 
            list.setSelectedIndex(si - 1); 
            list.ensureIndexIsVisible(si - 1); 
        } 
    } 

    // update list model depending on the data in textfield 
    protected abstract boolean updateListData(); 

    // user has selected some item in the list. update textfield accordingly... 
    protected abstract void acceptedListItem(String selected); 
}

And an Instance to handle the Content of the PopUp:

// @author Santhosh Kumar T - santhosh@in.fiorano.com 
public class FileAutoCompleter extends AutoCompleter{ 
    public FileAutoCompleter(JTextComponent comp){ 
        super(comp); 
    } 

    protected boolean updateListData(){ 
        String value = textComp.getText(); 
        int index1 = value.lastIndexOf('\\'); 
        int index2 = value.lastIndexOf('/'); 
        int index = Math.max(index1, index2); 
        if(index==-1) 
            return false; 
        String dir = value.substring(0, index+1); 
        final String prefix = index==value.length()-1 ? null : value.substring(index + 1).toLowerCase(); 
        String[] files = new File(dir).list(new FilenameFilter(){ 
            public boolean accept(File dir, String name){ 
                return prefix!=null ? name.toLowerCase().startsWith(prefix) : true; 
            } 
        }); 
        if(files == null){ 
            list.setListData(new String[0]); 
            return true; 
        } else{ 
            if(files.length==1 && files[0].equalsIgnoreCase(prefix)) 
                list.setListData(new String[0]); 
            else 
                list.setListData(files); 
            return true; 
        } 
    } 

    protected void acceptedListItem(String selected){ 
        if(selected==null) 
            return; 

        String value = textComp.getText(); 
        int index1 = value.lastIndexOf('\\'); 
        int index2 = value.lastIndexOf('/'); 
        int index = Math.max(index1, index2); 
        if(index==-1) 
            return; 
        int prefixlen = textComp.getDocument().getLength()-index-1; 
        try{ 
            textComp.getDocument().insertString(textComp.getCaretPosition(), selected.substring(prefixlen), null); 
        } catch(BadLocationException e){ 
            e.printStackTrace(); 
        } 
    } 
}

All is called in the program with

new FileAutoCompleter(yourJTextField);