How to list suggestions to when typing inside the text field

前端 未结 4 1856

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\'

相关标签:
4条回答
  • 2020-12-06 03:56

    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);
    
    0 讨论(0)
  • 2020-12-06 03:59

    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.

    0 讨论(0)
  • 2020-12-06 04:07

    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

    0 讨论(0)
  • 2020-12-06 04:12

    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.
    0 讨论(0)
提交回复
热议问题