How do I set different colors for text and underline in JTextPane?
Asked Answered
C

3

6

Just been trying to color the text in JTextPane - but the issue is cannot have different colors for text and the underline. How should I do that or is that even possible? The example below prints all the text and underline in RED.

JTextPane pane = new JTextPane();

StyleContext context = new StyleContext();

Style style = pane.addStyle("Black", null);
StyleConstants.setAlignment(style, StyleConstants.ALIGN_RIGHT);
StyleConstants.setFontSize(style, 14);
StyleConstants.setSpaceAbove(style, 4);
StyleConstants.setSpaceBelow(style, 4);
StyleConstants.setForeground(style, Color.BLACK);

StyledDocument document = pane.getStyledDocument();


style = pane.addStyle("Red Underline", style);
StyleConstants.setForeground(style, Color.RED);
StyleConstants.setUnderline(style, true);

pane.getDocument().insertString(0,  "Test String", style);
Campman answered 22/8, 2012 at 11:33 Comment(2)
+1 Despite the fact that the Style API seems to be extensible, I couldn't find any documentation how to do it.Jochbed
Found answer here ... #9503154Campman
C
5

Here's the solution I found...

Underline StyleConstant in a different colour with AttributeSet

Here's the link to sample code

http://java-sl.com/tip_colored_strikethrough.html

just changing the following line solves it ...

int y = a.getBounds().y + a.getBounds().height + 2 ; 

and it works fine

Campman answered 22/8, 2012 at 12:5 Comment(0)
L
4

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.

Lousy answered 22/8, 2012 at 16:56 Comment(0)
F
2
  • for example, and for Html

  • Document returns model to view, there is possible to determine the index where row started / ended

Favrot answered 22/8, 2012 at 12:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.