java - 键入时,从存储的现有文本中将单词(文本)插入到 JTextArea 中

标签 java swing jframe jtextarea

我正在寻求您的帮助来解决我目前正在解决的问题。

有没有办法在文本区域中键入内容时,从存储的现有文本(如字典)中逐字(文本)插入到 JTextArea 中?

应该使用KeyTyped或其他一些技术......

最佳答案

基于 @GuillaumePolet 提供的可运行代码,位于此 SO Post .

我对这段代码进行了一点修改,以便它可以从单词列表文件中提取 10 个特定单词,并将它们显示在编辑插入符当前位置附近的弹出列表中。您可以完成输入或使用鼠标从显示的弹出列表中双击所需的单词,也可以使用光标和 Enter 键执行相同的操作。

enter image description here

您使用的单词列表由您决定。我只是从网上抄了一篇,共124390字。只需向 dictionaryFilePath String 成员变量提供要使用的字典文本文件的路径和文件名即可。该变量位于 SuggestionPanel 内部类中。这是完整的可运行代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.BadLocationException;


public class WordAssist {

public class SuggestionPanel {

    private final JList<String> list;
    private final JPopupMenu popupMenu;
    private final String subWord;
    private final int insertionPosition;

    private String dictionaryFilePath = "French_Dictionary.txt";
    private int numberOfWordsInList = 10;
    private Color colorOfList = Color.decode("#FBFEC3");  // Light-Yellow (default)
    private Color colorOfListText = Color.decode("#000000");  // Black (default)
    private String listFontName = Font.SANS_SERIF;
    private int listFontStyle = Font.PLAIN;
    private int listFontSize = 11;
    private Font listFont = new Font(listFontName, listFontStyle, listFontSize);
    private Locale locale = Locale.FRANCE;
    public String characterEncoding = "UTF-8";

    public SuggestionPanel(JTextArea textarea, int position, String subWord, Point location) {
        this.insertionPosition = position;
        this.subWord = subWord;
        popupMenu = new JPopupMenu();
        popupMenu.removeAll();
        popupMenu.setOpaque(false);
        popupMenu.setBorder(null);
        popupMenu.add(list = createSuggestionList(position, subWord), BorderLayout.CENTER);
        popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y);
    }

    public void hide() {
        popupMenu.setVisible(false);
        if (suggestion == this) {
            suggestion = null;
        }
    }

    private JList<String> createSuggestionList(final int position, final String subWord) {
        String[] data = searchForWord(dictionaryFilePath, subWord + "*", numberOfWordsInList);
        if (data.length == 0) {
            data = new String[2];
            data[0] = " : Unknown Word : ";
            data[1] = "Add To Dictionary";
        }
        JList<String> assistList = new JList<>(data);
        assistList.setFont(new Font(listFontName, listFontStyle, listFontSize));
        assistList.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
        assistList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        assistList.setBackground(colorOfList);
        assistList.setForeground(colorOfListText);
        if (data.length == 2 && data[0].equalsIgnoreCase("unknown word:")) {
            assistList.setSelectedIndex(1);
        }
        else {
            assistList.setSelectedIndex(0);
        }
        assistList.addMouseListener(new MouseAdapter() {
            @Override
            @SuppressWarnings("Convert2Lambda")
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 1 && list.getSelectedValue().equalsIgnoreCase("add to dictionary")) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            addToDictionary(dictionaryFilePath, subWord, characterEncoding, locale);
                        }
                    });
                    hideSuggestion();
                    textarea.requestFocus();
                }
                if (e.getClickCount() == 2) {
                    insertSelection();
                    hideSuggestion();
                    textarea.requestFocus();
                }
            }
        });
        return assistList;
    }

    /**
     * Adds the supplied word to the supplied Dictionary text file but only
     * if it doesn't already exist. The dictionary text file must be
     * formated in such a manner that each line of that file must contain
     * only one word.
     *
     * @param dictionaryPath    (String) The path and file name to the
     *                          Dictionary text file.<br>
     *
     * @param wordToAdd         (String) The word to add to dictionary.<br>
     *
     * @param characterEncoding (String) The Character encoding to use for Dictionary:<pre>
     *
     *         Example:  "UTF-8"</pre><br>
     *
     * See:
     * <b>https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html</b>
     * for all the supported Encodings.<br>
     *
     * @param locale            (Locale) The Locale of the dictionary file.
     *                          This is also important for sorting so that
     *                          it too is done according to the proper locale.<pre>
     *         Example: Locale.FRANCE or Locale.US;</pre>
     *
     */
    public void addToDictionary(String dictionaryPath, String wordToAdd, String characterEncoding, Locale locale) {
        if (dictionaryPath.trim().equals("") || wordToAdd.trim().equals("")) {
            return;
        }
        wordToAdd = wordToAdd.trim();

        String savePath = new File(dictionaryPath).getAbsolutePath();
        savePath = savePath.substring(0, savePath.lastIndexOf(File.separator))
                + File.separator + "tmpDictFile.txt";

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(dictionaryPath), characterEncoding))) {
            OutputStream os = new FileOutputStream(savePath);
            // PrintWriter writer = new PrintWriter(savePath)) {
            try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, characterEncoding))) {
                // PrintWriter writer = new PrintWriter(savePath)) {
                String addwordFirstChar = wordToAdd.substring(0, 1);

                Collator collator = Collator.getInstance(locale);
                collator.setStrength(Collator.PRIMARY);

                List<String> wordList = new ArrayList<>();
                String line;
                while ((line = reader.readLine()) != null) {
                    line = line.trim();
                    if (line.equals("")) {
                        continue;
                    }
                    String firstChar = line.substring(0, 1);
                    if (firstChar.equals(firstChar.toUpperCase())
                            && addwordFirstChar.equals(addwordFirstChar.toUpperCase())
                            && collator.equals(firstChar, addwordFirstChar)) {
                        wordList.clear();
                        wordList.add(wordToAdd);
                        wordList.add(line);
                        // Add to uppercase section of file...
                        while ((line = reader.readLine()) != null || !firstChar.equals(firstChar.toUpperCase())) {
                            firstChar = line.substring(0, 1);
                            if (firstChar.equals(firstChar.toUpperCase())
                                    && !collator.equals(firstChar, addwordFirstChar)) {
                                break;
                            }
                            wordList.add(line);
                        }
                        Set<String> strSet = new HashSet<>(wordList);
                        wordList.clear();
                        wordList.addAll(strSet);

                        Collections.sort(wordList, collator);

                        for (String wrds : wordList) {
                            writer.println(wrds);
                        }
                        writer.println(line);
                    }
                    else if (firstChar.equals(firstChar.toLowerCase())
                            && addwordFirstChar.equals(addwordFirstChar.toUpperCase())
                            && collator.equals(firstChar, addwordFirstChar.toLowerCase())) {
                        wordList.clear();
                        if (!wordList.contains(wordToAdd.toLowerCase())) {
                            wordList.add(wordToAdd.toLowerCase());
                        }
                        wordList.add(line.toLowerCase());
                        // Add to lowercase section of file...
                        while ((line = reader.readLine()) != null) {
                            firstChar = line.substring(0, 1);
                            if (collator.equals(firstChar, addwordFirstChar.toLowerCase())) {
                                break;
                            }
                            wordList.add(line);
                        }
                        Set<String> strSet = new HashSet<>(wordList);
                        wordList.clear();
                        wordList.addAll(strSet);

                        Collections.sort(wordList, collator);

                        for (String wrds : wordList) {
                            writer.println(wrds);
                        }
                        writer.println(line);
                    }
                    else if (firstChar.equals(firstChar.toLowerCase())
                            && addwordFirstChar.equals(addwordFirstChar.toLowerCase())
                            && collator.equals(firstChar, addwordFirstChar)) {
                        wordList.clear();
                        if (!wordList.contains(wordToAdd)) {
                            wordList.add(wordToAdd);
                        }
                        wordList.add(line);
                        // Add to dictionary file...
                        while ((line = reader.readLine()) != null || !firstChar.equals(firstChar.toUpperCase())) {
                            firstChar = line.substring(0, 1);
                            if (!collator.equals(firstChar, addwordFirstChar)) {
                                break;
                            }
                            wordList.add(line);
                        }
                        Set<String> strSet = new HashSet<>(wordList);
                        wordList.clear();
                        wordList.addAll(strSet);

                        Collections.sort(wordList, collator);

                        for (String wrds : wordList) {
                            writer.println(wrds);
                        }
                        writer.println(line);
                    }
                    else {
                        writer.println(line);
                    }
                }
            }
        }
        catch (FileNotFoundException ex) {
            System.err.println(ex);
        }
        catch (UnsupportedEncodingException ex) {
            System.err.println(ex);
        }
        catch (IOException ex) {
            System.err.println(ex);
        }

        if (new File(savePath).exists()) {
            if (new File(dictionaryPath).delete()) {
                if (!new File(savePath).renameTo(new File(dictionaryPath))) {
                    System.err.println("Could not add the word: " + wordToAdd
                            + " to Dictionary!");
                }
            }
        }
    }

    @SuppressWarnings({"CallToPrintStackTrace", "Convert2Lambda"})
    public boolean insertSelection() {
        if (list.getSelectedValue() != null) {
            try {
                if (list.getSelectedValue().equalsIgnoreCase("add to dictionary")) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            addToDictionary(dictionaryFilePath, subWord, characterEncoding, locale);
                        }
                    });
                    hideSuggestion();
                    textarea.requestFocus();
                    return true;
                }
                else {
                    final String selectedSuggestion = list.getSelectedValue().substring(subWord.length());
                    textarea.getDocument().insertString(insertionPosition, selectedSuggestion, null);
                    return true;
                }
            }
            catch (BadLocationException e1) {
                e1.printStackTrace();
            }
            hideSuggestion();
        }
        return false;
    }

    public void moveUp() {
        int index = Math.min(list.getSelectedIndex() - 1, 0);
        selectIndex(index);
    }

    public void moveDown() {
        int index = Math.min(list.getSelectedIndex() + 1, list.getModel().getSize() - 1);
        selectIndex(index);
    }

    @SuppressWarnings("Convert2Lambda")
    private void selectIndex(int index) {
        final int position = textarea.getCaretPosition();
        list.setSelectedIndex(index);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                textarea.setCaretPosition(position);
            }
        });
    }

    public String[] searchForWord(String dictionaryFilePath, String searchCriteria, int numberOfWordsToReturn) {
        // This method ignores letter case!
        List<String> foundList = new ArrayList<>();  // To hold all found words.

        // Convert the supplied criteria string to a Regular Expression 
        // for the String#matches() method located in the 'while' loop.
        String regEx = searchCriteria.replace("?", ".").replace("-", ".").replace("*", ".*?").toLowerCase();

        // 'Try With Resources' use here to auto-close the reader.
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(dictionaryFilePath), characterEncoding))) {
            String line = "";
            int counter = 0;
            while ((line = reader.readLine()) != null) {
                line = line.trim().toLowerCase();
                if (line.matches(regEx)) {
                    counter++;
                    foundList.add(line);  // There's a match...add to the List.
                    if (counter == numberOfWordsToReturn) {
                        break;
                    }
                }
            }
        }
        // catch Exceptions (if any).
        catch (FileNotFoundException ex) {
            System.err.println(ex);
        }
        catch (IOException ex) {
            System.err.println(ex);
        }
        return foundList.toArray(new String[0]);  // Return the Array.
    }

    public String getDictionaryFilePath() {
        return dictionaryFilePath;
    }

    public void setDictionaryFilePath(String dictionaryFilePath) {
        this.dictionaryFilePath = dictionaryFilePath;
    }

    public int getNumberOfWordsInList() {
        return numberOfWordsInList;
    }

    public void setNumberOfWordsInList(int numberOfWordsInList) {
        this.numberOfWordsInList = numberOfWordsInList;
    }

    public Color getColorOfList() {
        return colorOfList;
    }

    public void setColorOfList(Color colorOfList) {
        this.colorOfList = colorOfList;
    }

    public Color getColorOfListText() {
        return colorOfListText;
    }

    public void setColorOfListText(Color colorOfListText) {
        this.colorOfListText = colorOfListText;
    }

    public String getListFontName() {
        return listFontName;
    }

    public Font getListFont() {
        return listFont;
    }

    public void setListFont(Font listFont) {
        this.listFont = listFont;
        this.listFontName = listFont.getName();
        this.listFontStyle = listFont.getStyle();
        this.listFontSize = listFont.getSize();
    }

    public void setListFontName(String listFontName) {
        this.listFontName = listFontName;
    }

    public int getListFontStyle() {
        return listFontStyle;
    }

    public void setListFontStyle(int listFontStyle) {
        this.listFontStyle = listFontStyle;
    }

    public int getListFontSize() {
        return listFontSize;
    }

    public void setListFontSize(int listFontSize) {
        this.listFontSize = listFontSize;
    }

    public String getCharacterEncoding() {
        return characterEncoding;
    }

    public void setCharacterEncoding(String characterEncoding) {
        this.characterEncoding = characterEncoding;
    }

    public Locale getLocale() {
        return locale;
    }

    public void setLocale(Locale locale) {
        this.locale = locale;
    }

}

private SuggestionPanel suggestion;
private JTextArea textarea;

@SuppressWarnings("Convert2Lambda")
protected void showSuggestionLater() {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            showSuggestion();
        }

    });
}

@SuppressWarnings({"CallToPrintStackTrace", "Convert2Lambda"})
protected void showSuggestion() {
    hideSuggestion();
    final int position = textarea.getCaretPosition();
    Point location;
    try {
        location = textarea.modelToView(position).getLocation();
    }
    catch (BadLocationException e2) {
        e2.printStackTrace();
        return;
    }
    String text = textarea.getText();
    int start = Math.max(0, position - 1);
    while (start > 0) {
        if (!Character.isWhitespace(text.charAt(start))) {
            start--;
        }
        else {
            start++;
            break;
        }
    }
    if (start > position) {
        return;
    }
    final String subWord = text.substring(start, position);
    if (subWord.length() < 2) {
        return;
    }
    suggestion = new SuggestionPanel(textarea, position, subWord, location);
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            textarea.requestFocusInWindow();
        }
    });
}

private void hideSuggestion() {
    if (suggestion != null) {
        suggestion.hide();
    }
}

protected void initUI() {
    final JFrame frame = new JFrame();
    frame.setTitle("Word Assist");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel panel = new JPanel(new BorderLayout());
    textarea = new JTextArea(24, 80);
    textarea.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
    textarea.addKeyListener(new KeyListener() {

        @Override
        @SuppressWarnings("Convert2Lambda")
        public void keyTyped(KeyEvent e) {
            if (e.getKeyChar() == KeyEvent.VK_ENTER) {
                if (suggestion != null) {
                    if (suggestion.insertSelection()) {
                        e.consume();
                        final int position = textarea.getCaretPosition();
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            @SuppressWarnings("CallToPrintStackTrace")
                            public void run() {
                                try {
                                    textarea.getDocument().remove(position - 1, 1);
                                }
                                catch (BadLocationException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                }
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) {
                suggestion.moveDown();
            }
            else if (e.getKeyCode() == KeyEvent.VK_UP && suggestion != null) {
                suggestion.moveUp();
            }
            else if (Character.isLetterOrDigit(e.getKeyChar())) {
                showSuggestionLater();
            }
            else if (Character.isWhitespace(e.getKeyChar())) {
                hideSuggestion();
            }
        }

        @Override
        public void keyPressed(KeyEvent e) {

        }
    });
    panel.add(textarea, BorderLayout.CENTER);
    frame.add(panel);
    frame.pack();
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);
}

@SuppressWarnings({"CallToPrintStackTrace", "Convert2Lambda"})
public static void main(String[] args) {
    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
    catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
        e.printStackTrace();
    }
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            new WordAssist().initUI();
        }
    });
}

}

只需启动一个名为 WordAssist 的新 Java 应用程序项目并将此代码粘贴到其中即可。它可能不完全是您想要的,但应该可以让您很好地了解如何实现您想要的。

EDIT - Based on the comment regarding the use of UTF-8 (Java7+ required):

我再次修改了上面的代码,以便您可以使用您喜欢的任何字符编码。只需将要使用的编码字符串提供给位于 SuggestionPanel 内部类中的 characterEncoding String 成员变量即可。现在默认编码为“UTF-8”。 读取器和写入器已更改,以适应您决定使用的任何编码。

确保您的文本文件可以容纳您选择的字符编码。如果您想使用法语词典,那么您应该下载这样的词典文本文件,并将其完整路径提供给位于 SuggestionPanel 内部类中的 dictionaryFilePath String 成员变量。

SuggestionPanel 内部类中还提供了多个 Getter 和 Setter 方法。这些 setter 允许您更改:

  • Word 辅助列表的字体;
  • 只是文字辅助列表的字体名称;
  • 仅用于文字辅助列表的字体样式(纯色、粗体、斜体等);
  • 只是文字辅助列表的字体大小;
  • 单词辅助列表背景颜色;
  • 单词辅助列表文本颜色;
  • 要放置在单词辅助列表中的单词数;
  • 字典文件路径;
  • 要使用的所需字符编码。

还可以将未知单词添加到您提供的词典文件中。在 JTextArea 中键入时,在键入过程中无法确定单词,因此无法提供建议,然后将显示以下内容,让您可以选择将该单词添加到当前词典文件中:

enter image description here

添加到词典文件中的单词将被插入到文件中,以保持正确的升序。许多词典(或单词列表)文本文件包含大写部分(通常在文件的开头),如果要添加的单词以全大写形式或该单词的第一个字母大写,则该单词将插入到两者中该文件的大写和小写部分。否则,该单词仅添加到所提供的词典文件的小写部分。当单词添加到词典文件时,该词典文件将修改为您设置的字符编码(默认为 UTF-8)。

所提供的代码只是您可能希望如何完成任务的足迹。现在,您需要自行执行任何进一步的要求,或者开始一个新的 SO 帖子,指出您遇到的具体问题,当然,除非它与上面提供的修改代码的任何具体问题直接相关.

关于java - 键入时,从存储的现有文本中将单词(文本)插入到 JTextArea 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60924850/

相关文章:

java - 如何在 apache 中使用 HttpClient 从 Java Swing 登录页面调用 Servlet?

java - Spring Security - 不是通过 IP 而是通过域/子域进行身份验证?

java - java 13.0.1、mysql 5.7 我应该选择哪个版本的 Connector/J?

Java 移动 JFrames 断断续续的运动

java - fireTableRowsInserted( int , int ) 不起作用(需要重新打开 GUI)

java - 调整 JFrame 及其内部所有内容的大小

java - 使用 Spring Boot 在 Java 中发送异步 HTTP 请求

java - JList渲染不可见 "selection marker"

java - JFrame 大小应减少桌面的最大可用大小

java - 不可扩展的窗口