首页 > 解决方案 > Java Swing 拼写检查器

问题描述

我有一个关于在 Swing 文本编辑器中实现 SpellChecker 的快速问题。我试图四处搜索,但找不到任何关于如何在拼写错误的单词下获得红色波浪线的信息。有什么我可以导入然后调用那些拼写错误的东西吗?另外,当我右键单击那些拼写错误的单词时,如何弹出菜单?谢谢

标签: javaswinguser-interfacespell-checking

解决方案


有很多材料取决于你想做什么......

首先,使用 a JTextPane,它支持漂亮的文本格式选项。

如何给文字加下划线:

包括注释作为解释。

import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;

public class WordUnderline {
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> {
            final Style defaultStyle = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
            
            final JTextPane pane = new JTextPane();
            
            //My super-creative text...
            pane.setText("These are words...\nHere come more words!\nWord word word.");
            
            final StyledDocument doc = pane.getStyledDocument();
            doc.addDocumentListener(new DocumentListener() {
                private void clearStyle(final DocumentEvent e) {
                    SwingUtilities.invokeLater(() -> doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, true));
                }
                
                @Override
                public void insertUpdate(final DocumentEvent e) {
                    //When you type a new letter, we want to (lets say) clear all the styles from the whole document...
                    clearStyle(e);
                }

                @Override
                public void removeUpdate(final DocumentEvent e) {
                    //When you erase a letter, we want to (lets say) clear all styles from the whole document...
                    clearStyle(e);
                }

                @Override
                public void changedUpdate(final DocumentEvent e) {
                    //When changing the style of the document, we want to do nothing else (but the change will happen).
                }
            });
            
            final JButton doit = new JButton("Underline selected text!");
            doit.addActionListener(e -> {
                final SimpleAttributeSet sas = new SimpleAttributeSet();
                StyleConstants.setUnderline(sas, true);
                /*I would suggest here to experiment a bit with the StyleConstants
                class... For example: StyleConstants.setBackground(sas, Color.RED);*/
                final int start = pane.getSelectionStart();
                final int end = pane.getSelectionEnd();
                doc.setCharacterAttributes(start, end - start, sas, true);
            });
            
            final JPanel contents = new JPanel(new BorderLayout());
            contents.add(doit, BorderLayout.PAGE_START);
            contents.add(pane, BorderLayout.CENTER);
            
            final JFrame frame = new JFrame("Word underline.");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(contents);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

如何在单词选择上弹出菜单:

包括注释作为解释。

import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
import javax.swing.text.Utilities;

public class WordPopUp {
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> {
            final JTextPane pane = new JTextPane();
            
            //My super-creative text...
            pane.setText("These are words...\nHere come more words!\nWord word word.");
            
            pane.addMouseListener(new MouseAdapter() {
                private boolean pendingPopUp = false; //Indicates whether we have already a popup popped up...
                
                private void pop(final MouseEvent mevt) {
                    if (SwingUtilities.isRightMouseButton(mevt)) {
                        try {
                            final StyledDocument doc = pane.getStyledDocument();

                            //Get the location of the document where the user clicked:
                            final int offset = pane.viewToModel(mevt.getPoint());
                            
                            //Find what word is at the location of the document where the user clicked:
                            final int start = Utilities.getWordStart(pane, offset),
                                      end = Utilities.getWordEnd(pane, offset);
                            
                            //Set the selection to be that word:
                            pane.setSelectionStart(start);
                            pane.setSelectionEnd(end);
                            
                            //Obtain the value of the selected word:
                            final String word = doc.getText(start, end - start);

                            //Create the contents of the popup:
                            final JPanel popupPanel = new JPanel();

                            //Create the alternative words (via JButtons):
                            final int cnt = 4;
                            final ArrayList<JButton> words = new ArrayList<>();
                            for (int i = 0; i < cnt; ++i) {
                                final JButton button = new JButton(word + (i + 1));
                                popupPanel.add(button);
                                words.add(button);
                            }
                            final JButton cancel = new JButton("Cancel");
                            popupPanel.add(cancel);

                            //Create the popup itself:
                            final Popup popup = PopupFactory.getSharedInstance().getPopup(pane, popupPanel, mevt.getXOnScreen(), mevt.getYOnScreen());

                            //Hook action listenere to the word and cancel buttons:
                            words.forEach(button -> button.addActionListener(e -> {
                                try {
                                    //Get the text of that button (it is going to be the new word):
                                    final String newWord = ((JButton) e.getSource()).getText();
                                    
                                    //Replace the old text with the new one:
                                    doc.remove(start, end - start);
                                    doc.insertString(start, newWord, null);
                                    
                                    //Prepare caret position, so the user can keep on writing:
                                    pane.setCaretPosition(start + newWord.length());
                                }
                                catch (final BadLocationException | RuntimeException x) {
                                    JOptionPane.showMessageDialog(pane, "Oups!");
                                }
                                finally {
                                    popup.hide();
                                    pendingPopUp = false;
                                }
                            }));

                            //On cancel, deselect the selected text and close the popup:
                            cancel.addActionListener(e -> {
                                popup.hide();
                                pane.setSelectionStart(offset);
                                pane.setSelectionEnd(offset);
                                pendingPopUp = false;
                            });
                            
                            pendingPopUp = true;
                            popup.show();
                        }
                        catch (final BadLocationException | RuntimeException x) {
                            JOptionPane.showMessageDialog(pane, "Oups! No word found?...");
                        }
                    }
                }
                
                private void maybePop(final MouseEvent mevt) {
                    if (mevt.isPopupTrigger()) {
                        if (pendingPopUp)
                            System.err.println("A popup is already popped. Close it to pop a new one.");
                        else
                            pop(mevt);
                    }
                }
                
                @Override
                public void mouseClicked(final MouseEvent mevt) {
                    maybePop(mevt);
                }
                
                @Override
                public void mousePressed(final MouseEvent mevt) {
                    maybePop(mevt);
                }
                
                @Override
                public void mouseReleased(final MouseEvent mevt) {
                    maybePop(mevt);
                }
            });
            
            final JFrame frame = new JFrame("Word underline.");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(new JScrollPane(pane));
            
            //Give some room to spare:
            final Dimension dim = frame.getPreferredSize();
            dim.width += 100;
            dim.height += 100;
            frame.setPreferredSize(dim);
            
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

资源和参考:

  1. 如何使用编辑器窗格和文本窗格
  2. 来自 jTextPane 的可点击文本
  3. 使用 JTextPane 制作文本下划线字体?
  4. 如何从 JTextPane 中获取选择
  5. 如何从 StyledDocument 中清除所有样式?
  6. 获取“尝试改变通知”异常
  7. 如何在 JTextPane 中为文本和下划线设置不同的颜色?
  8. 使用 AttributeSet 在不同颜色下划线 StyleConstant
  9. 取消选择 JTextPane 中的选定文本

推荐阅读