How to list suggestions to when typing inside the text field

前端 未结 4 1882

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);
    

提交回复
热议问题