Java Swing 拼写检查器

huangapple go评论141阅读模式
英文:

Java Swing Spell Checker

问题

我有一个关于将拼写检查器集成到我的Swing文本编辑器中的快速问题。我尝试搜索了一下,但找不到关于如何在拼写错误的单词下面显示红色波浪线的内容。有什么东西我可以导入然后调用来处理这些拼写错误吗?另外,当我右键单击这些拼写错误的单词时,如何使菜单弹出?谢谢。

英文:

I have a quick question about implementing my SpellChecker into my Swing Text Editor. I tried to search around but couldn't find anything on how to get the red squiggly line under misspelled words. Is there something I could import then call on those misspellings? Also, how would I be able to make a menu pop up when I right-click on those miss spelled words? Thanks

答案1

得分: 3

以下是您提供的代码的翻译:

有很多材料可以根据您想要做什么来使用...

首先,使用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();

            // 我超级有创意的文本...
            pane.setText("这些是单词...\n这里有更多单词!\n单词单词单词。");

            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) {
                    // 当您键入新字母时,我们希望(假设)清除整个文档的所有样式...
                    clearStyle(e);
                }

                @Override
                public void removeUpdate(final DocumentEvent e) {
                    // 当您擦除一个字母时,我们希望(假设)清除整个文档的所有样式...
                    clearStyle(e);
                }

                @Override
                public void changedUpdate(final DocumentEvent e) {
                    // 当更改文档的样式时,我们只想做样式更改,不做其他操作(但更改将发生)。
                }
            });

            final JButton doit = new JButton("下划线选定的文本!");
            doit.addActionListener(e -> {
                final SimpleAttributeSet sas = new SimpleAttributeSet();
                StyleConstants.setUnderline(sas, true);
                /*在这里,我建议尝试一下StyleConstants类...
                例如: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("单词下划线。");
            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();

            // 我超级有创意的文本...
            pane.setText("这些是单词...\n这里有更多单词!\n单词单词单词。");

            pane.addMouseListener(new MouseAdapter() {
                private boolean pendingPopUp = false; // 表示是否已经弹出了一个弹出窗口...

                private void pop(final MouseEvent mevt) {
                    if (SwingUtilities.isRightMouseButton(mevt)) {
                        try {
                            final StyledDocument doc = pane.getStyledDocument();

                            // 获取用户单击的文档位置:
                            final int offset = pane.viewToModel(mevt.getPoint());

                            // 查找用户单击文档位置的单词:
                            final int start = Utilities.getWordStart(pane, offset),
                                      end = Utilities.getWordEnd(pane, offset);

                            // 设置选择为该单词:
                            pane.setSelectionStart(start);
                            pane.setSelectionEnd(end);

                            // 获取所选单词的值:
                            final String word = doc.getText(start, end - start);

                            // 创建弹出窗口的内容:
                            final JPanel popupPanel = new JPanel();

                            // 创建替代单词(通过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("取消");
                            popupPanel.add(cancel);

                            // 创建弹出窗口本身:
                            final Popup popup = PopupFactory.getSharedInstance().getPopup(pane, popupPanel, mevt.getXOnScreen(), mevt.getYOnScreen());

                            // 将动作监听器附加到单词和取消按钮:
                            words.forEach(button -> button.addActionListener(e -> {
                                try {
                                    // 获取该按钮的文本(它将是新单词):
                                    final String newWord = ((JButton) e.getSource()).getText();

                                    // 用新文本替换旧文本:
                                    doc.remove(start, end - start);
                                    doc.insertString(start, newWord, null);

                                    // 准备光标位置,以便用户可以继续写作:
                                    pane.setCaretPosition(start + newWord.length());
                                }
                                catch (final BadLocationException | RuntimeException x) {
                                    JOptionPane.showMessageDialog(pane, "哎呀!");
                                }
                                finally {
                                    popup.hide();
                                    pendingPopUp = false;
                                }
                            }));

                            // 在取消时,取消选择的文本并关闭弹出窗口:
                            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, "哎呀!找不到单词?...");
                        }
                    }
                }

                private void maybePop(final MouseEvent mevt)

<details>
<summary>英文:</summary>

There is plenty of material out there depending on what you want to do...

First of, use a `JTextPane`, which supports nice text formatting options.

How to underline text:
----------------------

Comments are included as explanations.

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(&quot;These are words...\nHere come more words!\nWord word word.&quot;);
final StyledDocument doc = pane.getStyledDocument();
doc.addDocumentListener(new DocumentListener() {
private void clearStyle(final DocumentEvent e) {
SwingUtilities.invokeLater(() -&gt; 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(&quot;Underline selected text!&quot;);
doit.addActionListener(e -&gt; {
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(&quot;Word underline.&quot;);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}

}


&lt;hr/&gt;
How to pop a menu on word selection:
------------------------------------
Comments are included as explanations.

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(&quot;These are words...\nHere come more words!\nWord word word.&quot;);
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&lt;JButton&gt; words = new ArrayList&lt;&gt;();
for (int i = 0; i &lt; cnt; ++i) {
final JButton button = new JButton(word + (i + 1));
popupPanel.add(button);
words.add(button);
}
final JButton cancel = new JButton(&quot;Cancel&quot;);
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 -&gt; button.addActionListener(e -&gt; {
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, &quot;Oups!&quot;);
}
finally {
popup.hide();
pendingPopUp = false;
}
}));
//On cancel, deselect the selected text and close the popup:
cancel.addActionListener(e -&gt; {
popup.hide();
pane.setSelectionStart(offset);
pane.setSelectionEnd(offset);
pendingPopUp = false;
});
pendingPopUp = true;
popup.show();
}
catch (final BadLocationException | RuntimeException x) {
JOptionPane.showMessageDialog(pane, &quot;Oups! No word found?...&quot;);
}
}
}
private void maybePop(final MouseEvent mevt) {
if (mevt.isPopupTrigger()) {
if (pendingPopUp)
System.err.println(&quot;A popup is already popped. Close it to pop a new one.&quot;);
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(&quot;Word underline.&quot;);
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);
});
}

}


&lt;hr/&gt;
Resources and references:
-------------------------
1. [How to Use Editor Panes and Text Panes][1]
2. https://stackoverflow.com/questions/30898039/clickable-text-from-jtextpane
3. https://stackoverflow.com/questions/19414126/making-text-underline-font-by-using-jtextpane
4. https://stackoverflow.com/questions/12492817/how-to-get-selection-from-jtextpane
5. https://stackoverflow.com/questions/22186160/how-to-clear-all-styling-from-styleddocument
6. https://stackoverflow.com/questions/15206586/getting-attempt-to-mutate-notification-exception
7. https://stackoverflow.com/questions/12072171/how-do-i-set-different-colors-for-text-and-underline-in-jtextpane
8. https://stackoverflow.com/questions/9502654/underline-styleconstant-in-a-different-colour-with-attributeset
9. https://stackoverflow.com/questions/6744028/deselect-selected-text-in-jtextpane
[1]: https://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html
</details>
# 答案2
**得分**: 1
要实现在拼写错误的单词下面画出红色波浪线,您可以突出显示文本并使用自定义Painter来绘制红色波浪线。您可以查看[Squiggle Painter](https://tips4java.wordpress.com/2008/10/28/rectangle-painter/)以获取自定义绘制代码。基本用法如下:
```java
SquigglePainter red = new SquigglePainter(Color.RED);
try {
textField.getHighlighter().addHighlight(?, ?, red);
} catch (BadLocationException ble) {}

其中的“?”应该是您想要下划线的文本的起始/结束偏移量。

英文:

> how to get the red squiggly line under misspelled words.

You can highlight the text and use a custom Painter to draw the red squiggly line.

Check out the Squiggle Painter for the custom painting code.

Basic usage would be:

SquigglePainter red = new SquigglePainter( Color.RED );
try
{
textField.getHighlighter().addHighlight( ?, ?, red );
}
catch(BadLocationException ble) {}

where the "?" would be the start/end offset of the text you want to underline.

huangapple
  • 本文由 发表于 2020年7月29日 02:45:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/63140840.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定