views:

505

answers:

2

I basically want to implement changing the color of the links when I hover over them. The HyperlinkEvent that is triggered when I mouse over the link hands me the HTML element, but it won't let me set any style attributes on it, and I can't figure out how to get the elements that do have settable attributes.

+2  A: 

See Highlighting Words in a JTextComponent.

JTextArea textComp = new JTextArea();

// Highlight the occurrences of the word "public"
highlight(textComp, "public");

// Creates highlights around all occurrences of pattern in textComp
public void highlight(JTextComponent textComp, String pattern) {
    // First remove all old highlights
    removeHighlights(textComp);

    try {
        Highlighter hilite = textComp.getHighlighter();
        Document doc = textComp.getDocument();
        String text = doc.getText(0, doc.getLength());
        int pos = 0;

        // Search for pattern
        while ((pos = text.indexOf(pattern, pos)) >= 0) {
            // Create highlighter using private painter and apply around pattern
            hilite.addHighlight(pos, pos+pattern.length(), myHighlightPainter);
            pos += pattern.length();
        }
    } catch (BadLocationException e) {
    }
}

// Removes only our private highlights
public void removeHighlights(JTextComponent textComp) {
    Highlighter hilite = textComp.getHighlighter();
    Highlighter.Highlight[] hilites = hilite.getHighlights();

    for (int i=0; i<hilites.length; i++) {
        if (hilites[i].getPainter() instanceof MyHighlightPainter) {
            hilite.removeHighlight(hilites[i]);
        }
    }
}

// An instance of the private subclass of the default highlight painter
Highlighter.HighlightPainter myHighlightPainter = new MyHighlightPainter(Color.red);

// A private subclass of the default highlight painter
class MyHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
    public MyHighlightPainter(Color color) {
        super(color);
    }
}
eed3si9n
Thanks. I completely forgot about Highlighters. Unfortunately what I wanted to do was change the foreground, not the background, which is much harder with the highlighters. It did send me on the right path, however. So, thanks.
Mike Katz
+2  A: 

I figured out what I wanted to do using styled documents and bit of help from the HTMLEditorKit:

public class HighlightHyperlinkExample {
    private static Element lastHyperlinkElementEntered;
    private static JEditorPane textPane;


    public static void main(String[] args) {
        textPane = new JEditorPane();
        textPane.setContentType(new HTMLEditorKit().getContentType());
        JScrollPane scrollPane = new JScrollPane(textPane);
        textPane.setText(
                "Sample text with <a href=\"x\">a link</a> and another <a href=\"x\">link</a>.");

        initListeners();

        JFrame frame = new JFrame();
        frame.add(scrollPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }


    private static void initListeners() {
        textPane.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                removeHyperlinkHighlight();
            }
        });
        textPane.addMouseMotionListener(new MouseMotionListener() {
            public void mouseDragged(MouseEvent e) {
            }

            public void mouseMoved(MouseEvent e) {
                Point pt = new Point(e.getX(), e.getY());
                int pos = textPane.viewToModel(pt);
                if (pos >= 0) {
                    HTMLDocument hdoc = (HTMLDocument) textPane.getDocument();
                    Element elem = hdoc.getCharacterElement(pos);
                    if (elem != null) {
                        AttributeSet a = elem.getAttributes();
                        AttributeSet anchor = (AttributeSet) a.getAttribute(HTML.Tag.A);
                        if (anchor != null) {
                            //only highlight anchor tags
                            highlightHyperlink(elem);
                        } else {
                            removeHyperlinkHighlight();
                        }
                    }
                }
            }
        });
    }

    private static void removeHyperlinkHighlight() {
        changeColor(lastHyperlinkElementEntered, Color.BLUE);
        lastHyperlinkElementEntered = null;
    }

    private static void highlightHyperlink(Element hyperlinkElement) {
        if (hyperlinkElement != lastHyperlinkElementEntered) {
            lastHyperlinkElementEntered = hyperlinkElement;
            changeColor(hyperlinkElement, Color.RED);
        }
    }

    private static void changeColor(Element el, Color color) {
        if (lastHyperlinkElementEntered != null) {
            HTMLDocument doc = (HTMLDocument) textPane.getDocument();
            int start = el.getStartOffset();
            int end = el.getEndOffset();
            StyleContext ss = doc.getStyleSheet();
            Style style = ss.addStyle("HighlightedHyperlink", null);
            style.addAttribute(StyleConstants.Foreground, color);
            doc.setCharacterAttributes(start, end - start, style, false);
        }
    }
}
Mike Katz
consider rembering the actual color that was overwriten in #highlightHyperlink and use the remembered color in #removeHyperlinkHighlight.
ordnungswidrig
That would be better for this example.
Mike Katz