Basically there's 3 classes you need to create:
You need to extend javax.swing.text.LabelView to perform modify the view however you wish (whether that's adding an colored underline or not). You will be overriding the paint(Graphics, Shape)
method. You can access attributes with this line in the overridden class - the attributes should be the trigger for doing something additional to the text (like adding an underline).
getElement().getAttributes().getAttribute("attribute name");
You need to create a new ViewFactory and overwrite the create
method. It's important that when doing this you handle all element types (otherwise things won't quite display right.
You need to create an StyledEditorKit to make tell the pane which ViewFactory
to use.
Here's a simplified and runnable example of this:
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.basic.BasicTextPaneUI;
import javax.swing.text.*;
public class TempProject extends JPanel{
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
//Adding pane
JTextPane pane = new JTextPane();
pane.setEditorKit(new CustomEditorKit());
pane.setText("Underline With Different Color");
//Set Style
StyledDocument doc = (StyledDocument)pane.getDocument();
MutableAttributeSet attrs = new SimpleAttributeSet();
attrs.addAttribute("Underline-Color", Color.red);
doc.setCharacterAttributes(0, doc.getLength()-1, attrs, true);
JScrollPane sp = new JScrollPane(pane);
frame.setContentPane(sp);
frame.setPreferredSize(new Dimension(400, 300));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class CustomEditorKit extends StyledEditorKit{
public ViewFactory getViewFactory(){
return new CustomUI();
}
}
public static class CustomUI extends BasicTextPaneUI{
@Override
public View create(Element elem){
View result = null;
String kind = elem.getName();
if(kind != null){
if(kind.equals(AbstractDocument.ContentElementName)){
result = new MyLabelView(elem);
} else if(kind.equals(AbstractDocument.ParagraphElementName)){
result = new ParagraphView(elem);
}else if(kind.equals(AbstractDocument.SectionElementName)){
result = new BoxView(elem, View.Y_AXIS);
}else if(kind.equals(StyleConstants.ComponentElementName)){
result = new ComponentView(elem);
}else if(kind.equals(StyleConstants.IconElementName)){
result = new IconView(elem);
} else{
result = new LabelView(elem);
}
}else{
result = super.create(elem);
}
return result;
}
}
public static class MyLabelView extends LabelView{
public MyLabelView(Element arg0) {
super(arg0);
}
public void paint(Graphics g, Shape a){
super.paint(g, a);
//Do whatever other painting here;
Color c = (Color)getElement().getAttributes().getAttribute("Underline-Color");
if(c != null){
int y = a.getBounds().y + (int)getGlyphPainter().getAscent(this);
int x1 = a.getBounds().x;
int x2 = a.getBounds().width + x1;
g.setColor(c);
g.drawLine(x1, y, x2, y);
}
}
}
}
Here's the link to another sample code:
http://java-sl.com/tip_colored_strikethrough.html
This answer is mostly for posterity, I thought adding a simplified version of the linked code and explanation would help make things more understandable.