英文:
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("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);
});
}
}
<hr/>
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("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);
});
}
}
<hr/>
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论