如何在 JTextArea 摆动中实现自动插入 [英] how would be implements autosugesion in JTextArea swing

查看:22
本文介绍了如何在 JTextArea 摆动中实现自动插入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果有人回答,请让我回答.基本上需要像谷歌搜索引擎一样,当我们按下任意键时,就会显示与按键相关的建议.

关注萨蒂什·迪曼

解决方案

来自我的评论/以前的代码 查看此更新:

JTextFieldAutoSuggestor 结合使用:

使用 JTextArea(或除 JTextField 之外的任何其他 JTextComponent 将导致弹出窗口显示在插入符号下)和 AutoSuggestor:

import java.awt.Color;导入 java.awt.Dimension;导入 java.awt.GridLayout;导入 java.awt.Rectangle;导入 java.awt.Window;导入 java.awt.event.ActionEvent;导入 java.awt.event.KeyEvent;导入 java.awt.event.MouseAdapter;导入 java.awt.event.MouseEvent;导入 java.util.ArrayList;导入 javax.swing.AbstractAction;导入 javax.swing.JComponent;导入 javax.swing.JEditorPane;导入 javax.swing.JFrame;导入 javax.swing.JLabel;导入 javax.swing.JPanel;导入 javax.swing.JTextArea;导入 javax.swing.JTextField;导入 javax.swing.JWindow;导入 javax.swing.KeyStroke;导入 javax.swing.SwingUtilities;导入 javax.swing.border.LineBorder;导入 javax.swing.event.DocumentEvent;导入 javax.swing.event.DocumentListener;导入 javax.swing.text.BadLocationException;导入 javax.swing.text.JTextComponent;/*** @作者大卫*/公共类测试{公共测试(){JFrame frame = new JFrame();frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//JTextField f = new JTextField(10);JTextArea f = new JTextArea(10, 10);//JEditorPane f = new JEditorPane();//为字典创建单词也可以使用 null 作为 AutoSuggestor(..,..,null,..,..,..,..) 的参数,然后在创建 AutoSuggestr insatnce 后调用 AutoSuggestor#setDictionaryArrayListwords = new ArrayList<>();word.add("你好");word.add("遗产");word.add("幸福");word.add("再见");word.add("残忍");word.add("汽车");word.add("战争");word.add("将");word.add("世界");word.add("墙");AutoSuggestor autoSuggestor = new AutoSuggestor(f, frame, words, Color.WHITE.brighter(), Color.BLUE, Color.RED, 0.75f) {@覆盖boolean wordTyped(String typedWord) {System.out.println(typedWord);return super.wordTyped(typedWord);//检查字典中是否匹配,如果找到则返回真或假}};JPanel p = new JPanel();p.add(f);框架.add(p);框架.pack();frame.setVisible(true);}公共静态无效主(字符串 [] args){SwingUtilities.invokeLater(new Runnable() {@覆盖公共无效运行(){新测试();}});}}类 AutoSuggestor {私有最终 JTextComponent textComp;私有最终窗口容器;私人 JPanel 建议面板;私有 JWindow autoSuggestionPopUpWindow;私有字符串 typedWord;私有最终 ArrayList字典 = 新的 ArrayList<>();私人 int currentIndexOfSpace, tW, tH;private DocumentListener documentListener = new DocumentListener() {@覆盖public void insertUpdate(DocumentEvent de) {checkForAndShowSuggestions();}@覆盖public void removeUpdate(DocumentEvent de) {checkForAndShowSuggestions();}@覆盖public void changedUpdate(DocumentEvent de) {checkForAndShowSuggestions();}};私人最终颜色建议TextColor;私人最终颜色建议FocusedColor;public AutoSuggestor(JTextComponent textComp, Window mainWindow, ArrayList words, Color popUpBackground, Color textColor, Color RecommendationFocusedColor, float opacity) {this.textComp = textComp;this.suggestionsTextColor = textColor;this.container = mainWindow;this.suggestionFocusedColor =SuggestedFocusedColor;this.textComp.getDocument().addDocumentListener(documentListener);setDictionary(words);typedWord = "";currentIndexOfSpace = 0;tW = 0;tH = 0;autoSuggestionPopUpWindow = new JWindow(mainWindow);autoSuggestionPopUpWindow.setOpacity(opacity);建议面板 = 新的 JPanel();RecommendationPanel.setLayout(new GridLayout(0, 1));SuggestionsPanel.setBackground(popUpBackground);addKeyBindingToRequestFocusInPopUpWindow();}私有无效 addKeyBindingToRequestFocusInPopUpWindow() {textComp.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "向下释放");textComp.getActionMap().put("向下发布", new AbstractAction() {@覆盖public void actionPerformed(ActionEvent ae) {//聚焦弹出窗口的第一个标签for (int i = 0; i < RecommendationPanel.getComponentCount(); i++) {if (suggestionsPanel.getComponent(i) instanceof SuggestionLabel) {((SuggestionLabel)SuggestionPanel.getComponent(i)).setFocused(true);autoSuggestionPopUpWindow.toFront();autoSuggestionPopUpWindow.requestFocusInWindow();SuggestionsPanel.requestFocusInWindow();SuggestionsPanel.getComponent(i).requestFocusInWindow();休息;}}}});SuggestionsPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "向下释放");SuggestionsPanel.getActionMap().put("Downreleased", new AbstractAction() {int lastFocusableIndex = 0;@覆盖public void actionPerformed(ActionEvent ae) {//允许在弹出窗口中滚动标签(我现在知道很hacky :))ArrayListsls = getAddedSuggestionLabels();int max = sls.size();if (max > 1) {//超过 1 个建议for (int i = 0; i < max; i++) {SuggestionLabel sl = sls.get(i);如果(sl.isFocused()){if (lastFocusableIndex == max - 1) {lastFocusableIndex = 0;sl.setFocused(false);autoSuggestionPopUpWindow.setVisible(false);setFocusToTextField();checkForAndShowSuggestions();//触发方法,就好像文档监听器改变发生一样并触发它} 别的 {sl.setFocused(false);lastFocusableIndex = i;}} else if (lastFocusableIndex <= i) {如果(我<最大){sl.setFocused(true);autoSuggestionPopUpWindow.toFront();autoSuggestionPopUpWindow.requestFocusInWindow();SuggestionsPanel.requestFocusInWindow();SuggestionsPanel.getComponent(i).requestFocusInWindow();lastFocusableIndex = i;休息;}}}} else {//只给出了一个建议autoSuggestionPopUpWindow.setVisible(false);setFocusToTextField();checkForAndShowSuggestions();//触发方法,就好像文档监听器改变发生一样并触发它}}});}私有无效 setFocusToTextField() {容器.toFront();container.requestFocusInWindow();textComp.requestFocusInWindow();}公共 ArrayListgetAddedSuggestionLabels() {ArrayListsls = new ArrayList<>();for (int i = 0; i < RecommendationPanel.getComponentCount(); i++) {if (suggestionsPanel.getComponent(i) instanceof SuggestionLabel) {SuggestionLabel sl = (SuggestionLabel)SuggestionPanel.getComponent(i);sls.add(sl);}}返回 sls;}私有无效 checkForAndShowSuggestions() {typedWord = getCurrentlyTypedWord();SuggestionsPanel.removeAll();//删除之前添加的词/jlabels//用于在添加新Jlabels时计算JWindow的大小tW = 0;tH = 0;布尔添加 = wordTyped(typedWord);如果(!添加){如果(autoSuggestionPopUpWindow.isVisible()){autoSuggestionPopUpWindow.setVisible(false);}} 别的 {showPopUpWindow();setFocusToTextField();}}protected void addWordToSuggestions(String word) {SuggestionLabelSuggestionLabel = new SuggestionLabel(word,SuggestionFocusedColor,suggestTextColor,this);计算弹出窗口大小(建议标签);建议面板.添加(建议标签);}public String getCurrentlyTypedWord() {//获取最后一个空格后的最新单词(如果有)或第一个单词(如果没有空格)String text = textComp.getText();字符串 wordBeingTyped = "";text = text.replaceAll("(\r|\n)", " ");如果(文本.包含(")){int tmp = text.lastIndexOf(" ");if (tmp >= currentIndexOfSpace) {currentIndexOfSpace = tmp;wordBeingTyped = text.substring(text.lastIndexOf(" "));}} 别的 {wordBeingTyped = 文本;}返回 wordBeingTyped.trim();}私有无效计算PopUpWindowSize(JLabel标签){//这样我们就可以正确调整JWindow的大小if (tW < label.getPreferredSize().width) {tW = label.getPreferredSize().width;}tH += label.getPreferredSize().height;}私有无效 showPopUpWindow() {autoSuggestionPopUpWindow.getContentPane().add(suggestionsPanel);autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textComp.getWidth(), 30));autoSuggestionPopUpWindow.setSize(tW, tH);autoSuggestionPopUpWindow.setVisible(true);int windowX = 0;int windowY = 0;if (textComp instanceof JTextField) {//为 JTextField 底部的 JWindow 计算 x 和 ywindowX = container.getX() + textComp.getX() + 5;如果 (suggestionsPanel.getHeight() > autoSuggestionPopUpWindow.getMinimumSize().height) {windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getMinimumSize().height;} 别的 {windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getHeight();}} else {//使用插入符号位置为任何 JTextComponent 上的 JWindow 计算 x 和 y矩形 rect = null;尝试 {rect = textComp.getUI().modelToView(textComp, textComp.getCaret().getDot());//获取脱字符位置} catch (BadLocationException ex) {ex.printStackTrace();}windowX = (int) (rect.getX() + 15);windowY = (int) (rect.getY() + (rect.getHeight() * 3));}//显示弹出窗口autoSuggestionPopUpWindow.setLocation(windowX, windowY);autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textComp.getWidth(), 30));autoSuggestionPopUpWindow.revalidate();autoSuggestionPopUpWindow.repaint();}public void setDictionary(ArrayList words) {字典.清除();如果(单词 == 空){return;//这样我们就可以为字典调用空值的构造函数而不会抛出异常}for(字符串词:词){字典.添加(字);}}公共 JWindow getAutoSuggestionPopUpWindow() {返回 autoSuggestionPopUpWindow;}公共窗口 getContainer() {返回容器;}公共 JTextComponent getTextField() {返回 textComp;}public void addToDictionary(String word) {字典.添加(字);}boolean wordTyped(String typedWord) {if (typedWord.isEmpty()) {返回假;}//System.out.println("Typed word: " + typedWord);布尔建议添加 = 假;for (String word : dictionary) {//获取我们添加的字典中的单词布尔完全匹配 = 真;for (int i = 0; i < typedWord.length(); i++) {//每个字串if (!typedWord.toLowerCase().startsWith(String.valueOf(word.toLowerCase().charAt(i)), i)) {//检查匹配完全匹配 = 假;休息;}}如果(完全匹配){addWordToSuggestions(word);建议添加 = 真;}}退货建议已添加;}}类 SuggestionLabel 扩展 JLabel {私有布尔集中 = false;私人最终 JWindow autoSuggestionsPopUpWindow;私有最终 JTextComponent 文本组件;私人最终 AutoSuggestor autoSuggestor;私人颜色建议TextColor,建议BorderColor;公共建议标签(字符串字符串,最终颜色边框颜色,颜色建议文本颜色,AutoSuggestor autoSuggestor){超级(字符串);this.suggestionsTextColor =SuggestionsTextColor;this.autoSuggestor = autoSuggestor;this.textComponent = autoSuggestor.getTextField();this.suggestionBorderColor = borderColor;this.autoSuggestionsPopUpWindow = autoSuggestor.getAutoSuggestionPopUpWindow();初始化组件();}私有无效initComponent(){setFocusable(true);设置前景(建议文本颜色);addMouseListener(新鼠标适配器(){@覆盖public void mouseClicked(MouseEvent me) {super.mouseClicked(me);replaceWithSuggestedText();autoSuggestionsPopUpWindow.setVisible(false);}});getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), "输入释放");getActionMap().put("回车释放", new AbstractAction() {@覆盖public void actionPerformed(ActionEvent ae) {replaceWithSuggestedText();autoSuggestionsPopUpWindow.setVisible(false);}});}公共无效setFocused(布尔集中){如果(重点){setBorder(new LineBorder(suggestionBorderColor));} 别的 {设置边界(空);}重绘();this.focused = 专注;}公共布尔 isFocused() {专注回归;}私有无效 replaceWithSuggestedText() {StringSuggestWord = getText();String text = textComponent.getText();String typedWord = autoSuggestor.getCurrentlyTypedWord();String t = text.substring(0, text.lastIndexOf(typedWord));String tmp = t + text.substring(text.lastIndexOf(typedWord)).replace(typedWord,SuggestWord);textComponent.setText(tmp + " ");}}

如您所见,我通过使其构造函数接受 JTextComponent 而不是 JTextFieldJTextArea 等来更改代码.

我们剩下的问题是我们必须根据传递的 JTextComponent 即一个 JTextField 在不同的位置显示弹出的 JWindow> 将在底部弹出自动建议窗口,而 JTextArea/JEditorPane 等将在插入符号/单词下弹出 JWindow.

看看AutoSuggestor类中的这个特定方法showPopUpWindow():

private void showPopUpWindow() {autoSuggestionPopUpWindow.getContentPane().add(suggestionsPanel);autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textComp.getWidth(), 30));autoSuggestionPopUpWindow.setSize(tW, tH);autoSuggestionPopUpWindow.setVisible(true);int windowX = 0;int windowY = 0;if (textComp instanceof JTextField) {//为 JTextField 底部的 JWindow 计算 x 和 ywindowX = container.getX() + textComp.getX() + 5;如果 (suggestionsPanel.getHeight() > autoSuggestionPopUpWindow.getMinimumSize().height) {windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getMinimumSize().height;} 别的 {windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getHeight();}} else {//使用插入符号位置为任何 JTextComponent 上的 JWindow 计算 x 和 y矩形 rect = null;尝试 {rect = textComp.getUI().modelToView(textComp, textComp.getCaret().getDot());//获取脱字符位置} catch (BadLocationException ex) {ex.printStackTrace();}windowX = (int) (rect.getX() + 15);windowY = (int) (rect.getY() + (rect.getHeight() * 3));}//显示弹出窗口autoSuggestionPopUpWindow.setLocation(windowX, windowY);autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textComp.getWidth(), 30));autoSuggestionPopUpWindow.revalidate();autoSuggestionPopUpWindow.repaint();}

如您所见,我们检查 JTextComponent 是什么实例,如果它不是 JTextField,只需获取插入符号位置(通过 RectangleJTextComponentJWindow 的插入符号的代码> 和位置 JWindow 从那里弹出(在我的例子中插入符号下方).

let me if have you anyone answer, this ans. basically required like as google search engine , when we press any key then it would be display suggestion related pressed key.

regard Satish Dhiman

解决方案

From my comment/previous code see this update:

Using JTextField with AutoSuggestor:

Using JTextArea (or any other JTextComponent besides JTextField will result in Pop up window being shown under caret) with AutoSuggestor:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Rectangle;
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 javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
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;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;

/**
 * @author David
 */
public class Test {

    public Test() {

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

        //JTextField f = new JTextField(10);
        JTextArea f = new JTextArea(10, 10);
        //JEditorPane f = new JEditorPane();

        //create words for dictionary could also use null as parameter for AutoSuggestor(..,..,null,..,..,..,..) and than call AutoSuggestor#setDictionary after AutoSuggestr insatnce has been created
        ArrayList<String> words = new ArrayList<>();
        words.add("hello");
        words.add("heritage");
        words.add("happiness");
        words.add("goodbye");
        words.add("cruel");
        words.add("car");
        words.add("war");
        words.add("will");
        words.add("world");
        words.add("wall");

        AutoSuggestor autoSuggestor = new AutoSuggestor(f, frame, words, Color.WHITE.brighter(), Color.BLUE, Color.RED, 0.75f) {
            @Override
            boolean wordTyped(String typedWord) {
                System.out.println(typedWord);
                return super.wordTyped(typedWord);//checks for a match in dictionary and returns true or false if found or not
            }
        };

        JPanel p = new JPanel();

        p.add(f);

        frame.add(p);

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

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test();
            }
        });
    }
}

class AutoSuggestor {

    private final JTextComponent textComp;
    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(JTextComponent textComp, Window mainWindow, ArrayList<String> words, Color popUpBackground, Color textColor, Color suggestionFocusedColor, float opacity) {
        this.textComp = textComp;
        this.suggestionsTextColor = textColor;
        this.container = mainWindow;
        this.suggestionFocusedColor = suggestionFocusedColor;
        this.textComp.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() {
        textComp.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "Down released");
        textComp.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();
        textComp.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 = textComp.getText();
        String wordBeingTyped = "";
        text = text.replaceAll("(\r|\n)", " ");
        if (text.contains(" ")) {
            int tmp = text.lastIndexOf(" ");
            if (tmp >= currentIndexOfSpace) {
                currentIndexOfSpace = tmp;
                wordBeingTyped = text.substring(text.lastIndexOf(" "));
            }
        } 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(textComp.getWidth(), 30));
        autoSuggestionPopUpWindow.setSize(tW, tH);
        autoSuggestionPopUpWindow.setVisible(true);

        int windowX = 0;
        int windowY = 0;

        if (textComp instanceof JTextField) {//calculate x and y for JWindow at bottom of JTextField
            windowX = container.getX() + textComp.getX() + 5;
            if (suggestionsPanel.getHeight() > autoSuggestionPopUpWindow.getMinimumSize().height) {
                windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getMinimumSize().height;
            } else {
                windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getHeight();
            }
        } else {//calculate x and y for JWindow on any JTextComponent using the carets position
            Rectangle rect = null;
            try {
                rect = textComp.getUI().modelToView(textComp, textComp.getCaret().getDot());//get carets position
            } catch (BadLocationException ex) {
                ex.printStackTrace();
            }

            windowX = (int) (rect.getX() + 15);
            windowY = (int) (rect.getY() + (rect.getHeight() * 3));
        }

        //show the pop up
        autoSuggestionPopUpWindow.setLocation(windowX, windowY);
        autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textComp.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 JTextComponent getTextField() {
        return textComp;
    }

    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 JTextComponent textComponent;
    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.textComponent = 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 = textComponent.getText();
        String typedWord = autoSuggestor.getCurrentlyTypedWord();
        String t = text.substring(0, text.lastIndexOf(typedWord));
        String tmp = t + text.substring(text.lastIndexOf(typedWord)).replace(typedWord, suggestedWord);
        textComponent.setText(tmp + " ");
    }
}

As you can see I changed the code by making its constructor accept a JTextComponent rather than a JTextField or JTextArea etc.

The problem we are left with is we have to show the pop up JWindow at a different position depending on the JTextComponent passed i.e a JTextField will have autosuggest window pop up at the bottom while JTextArea/JEditorPane etc would have the JWindow pop up under the caret/word.

Have a look at this specific method showPopUpWindow() in AutoSuggestor class:

private void showPopUpWindow() {
    autoSuggestionPopUpWindow.getContentPane().add(suggestionsPanel);
    autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textComp.getWidth(), 30));
    autoSuggestionPopUpWindow.setSize(tW, tH);
    autoSuggestionPopUpWindow.setVisible(true);

    int windowX = 0;
    int windowY = 0;

    if (textComp instanceof JTextField) {//calculate x and y for JWindow at bottom of JTextField
        windowX = container.getX() + textComp.getX() + 5;
        if (suggestionsPanel.getHeight() > autoSuggestionPopUpWindow.getMinimumSize().height) {
            windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getMinimumSize().height;
        } else {
            windowY = container.getY() + textComp.getY() + textComp.getHeight() + autoSuggestionPopUpWindow.getHeight();
        }
    } else {//calculate x and y for JWindow on any JTextComponent using the carets position
        Rectangle rect = null;
        try {
            rect = textComp.getUI().modelToView(textComp, textComp.getCaret().getDot());//get carets position
        } catch (BadLocationException ex) {
            ex.printStackTrace();
        }

        windowX = (int) (rect.getX() + 15);
        windowY = (int) (rect.getY() + (rect.getHeight() * 3));
    }

    //show the pop up
    autoSuggestionPopUpWindow.setLocation(windowX, windowY);
    autoSuggestionPopUpWindow.setMinimumSize(new Dimension(textComp.getWidth(), 30));
    autoSuggestionPopUpWindow.revalidate();
    autoSuggestionPopUpWindow.repaint();

}

As you can see we check to see what instance the JTextComponent is and if its not a JTextField simply get the caret position (via the Rectangle of the caret) of the JTextComponent and position JWindow pop up from there (underneath the caret in my case).

这篇关于如何在 JTextArea 摆动中实现自动插入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆