Java Swing 拼写检查器

Java Swing Spell Checker

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

how to get the red squiggly line under misspelled words.

您可以突出显示文本并使用自定义 Painter 绘制红色波浪线。

查看 Squiggle Painter 自定义绘画代码。

基本用法是:

SquigglePainter red = new SquigglePainter( Color.RED );

try
{
    textField.getHighlighter().addHighlight( ?, ?, red );
}
catch(BadLocationException ble) {}

“?”在哪里?将是您要加下划线的文本的 start/end 偏移量。

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

首先,使用 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. How to Use Editor Panes and Text Panes
  2. making text underline font by using JTextPane?
  3. How to get selection from JTextPane
  4. How to clear all styling from StyledDocument?
  5. Getting 'Attempt to mutate notification' exception
  6. How do I set different colors for text and underline in JTextPane?
  7. Underline StyleConstant in a different colour with AttributeSet
  8. Deselect selected text in JTextPane