-1

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

Patrick
  • 21
  • 5
  • You would have to draw the red wiggly lines. There are word lists you can use to check word spelling, A JDialog could show the possible words. http://www.gwicks.net/dictionaries.htm – Gilbert Le Blanc Jul 28 '20 at 19:09

2 Answers2

3

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);
        });
    }
}

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);
        });
    }
}

Resources and references:

  1. How to Use Editor Panes and Text Panes
  2. clickable text from jTextPane
  3. making text underline font by using JTextPane?
  4. How to get selection from JTextPane
  5. How to clear all styling from StyledDocument?
  6. Getting 'Attempt to mutate notification' exception
  7. How do I set different colors for text and underline in JTextPane?
  8. Underline StyleConstant in a different colour with AttributeSet
  9. Deselect selected text in JTextPane
gthanop
  • 3,035
  • 2
  • 10
  • 27
1

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.

camickr
  • 321,443
  • 19
  • 166
  • 288