2013-01-16 83 views
0

我已将自动完成功能应用于两个textFields。为此,我使用了AutocompleteDecorator。我观察到它减慢到我无法输入单个字符的程度。任何解决方案?来自自动完成功能的响应缓慢

感谢

JTextArea textArea = main.getEditor(); 
    String content = textArea.getText(); 

    try { 
     if (content.length() > 0) { 
      String[] lines = content.split("\n"); 
      String txt1 = null; 
      String txt2 = null; 

      for (String line : lines) { 
       txt1= line.substring(0, 10); 
       txt2 = line.substring(11, 15); 

       listTxt1.add(txt1); 
       listTxt2.add(txt2); 
      } 
      AutoCompleteDecorator.decorate(txtField1, listTxt1, false); 
      AutoCompleteDecorator.decorate(txtField2, listTxt2, false); 
     } 
    } catch (Exception ex) { 
     System.out.println(ex); 
    } 
+1

为了更好地帮助越早,张贴[SSCCE](HTTP ://sscce.org/)。 –

+2

@AndrewThompson:这个问题可能很难做到,因为这个问题有90%是关于第三方库的使用。 –

+0

@HovercraftFullOfEels好点。 :) –

回答

2

从我的评论,我决定验证这一点。

我通过通过我的字典增加1000个随机字母String S:

for (int i = 0; i < 1000; i++) { 
    words.add(generateString(r, "abcdefghijklmnopqrstuvwxyz", 10)); 
} 

... 

public static String generateString(Random rng, String characters, int length) { 
    char[] text = new char[length]; 
    for (int i = 0; i < length; i++) { 
     text[i] = characters.charAt(rng.nextInt(characters.length())); 
    } 
    return new String(text); 
} 

,并没有明显减慢的。

enter image description here

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 java.util.Random; 
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 { 

    Random r = new Random(); 

    public Test() { 

     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 


     JTextField f = new JTextField(10); 

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


     for (int i = 0; i < 1000; i++) { 
      words.add(generateString(r, "abcdefghijklmnopqrstuvwxyz", 10)); 
     } 

     AutoSuggestor autoSuggestor = new AutoSuggestor(f, frame, words, Color.WHITE.brighter(), Color.BLUE, Color.RED, 0.75f); 

     JPanel p = new JPanel(); 

     p.add(f); 

     frame.add(p); 

     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static String generateString(Random rng, String characters, int length) { 
     char[] text = new char[length]; 
     for (int i = 0; i < length; i++) { 
      text[i] = characters.charAt(rng.nextInt(characters.length())); 
     } 
     return new String(text); 
    } 

    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(tmp); 
      } 
     } 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 + " "); 
    } 
} 

即使把它高达50000个随机String s乃至不仅仅是一个微小的停顿可以看出/ 觉得