problems with custom underline in JTextPane
Hi!
I found in this forum some sample code for custom underline (jagged underline) that was written by Stas. Thanks for sharing it!
I had to make some changes to satisfy my requirements: I want to use jagged underlines in red and green and I want to underline e.g. black text red or green.
I extended DefaultStyledEditorKit like Stas does in his solution. Please see the sample code below.
The problem is that the underlines are not painted correctly when you select multiple lines and change the style of the underline by clicking one of the buttons in the sample-app. Only the first and the last line of the selection is rendered with the selected underline, the lines between are not changed. If you force to repaint the lines between that are not rendered correctly by selecting a few characters of it and select a custom underline again, the underline you selected before is painted, too. So I guess that the LabelViews are not painted correctly. TextPane.repaint does not help. So how can I force that all LabelView of a selection are painted? Or maybe I have done some other mistake.
Any suggestions are highly appreciated.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.text.*;
class Testimplements ActionListener{
JTextPane pane;
public Test(){
JPanel p =new JPanel();
JButton green =new JButton("green");
green.addActionListener(this);
p.add(green);
JButton greenJagged =new JButton("greenJagged");
greenJagged.addActionListener(this);
p.add(greenJagged);
JButton red =new JButton("red");
red.addActionListener(this);
p.add(red);
JButton redJagged =new JButton("redJagged");
redJagged.addActionListener(this);
p.add(redJagged);
JButton reset =new JButton("reset");
reset.addActionListener(this);
p.add(reset);
JFrame fr =new JFrame("TEST");
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pane =new JTextPane();
pane.setEditorKit(new ExtendedEditorKit());
String text ="test test test test\n";
for (int i = 0; i < 20; i++){
text +="test test test test\n";
}
pane.setText(text);
pane.setEditable(false);
JScrollPane sp =new JScrollPane(pane);
fr.getContentPane().add(sp);
fr.getContentPane().add(p, BorderLayout.NORTH);
fr.setSize(500, 500);
fr.setVisible(true);
}
publicstaticvoid main(String[] args){
new Test();
}
publicvoid actionPerformed(ActionEvent e){
MutableAttributeSet as =new SimpleAttributeSet();
if (e.getActionCommand().equals("green")){
setCustomUnderline(as, GREEN_UNDERLINE);
}elseif (e.getActionCommand().equals("red")){
setCustomUnderline(as, RED_UNDERLINE);
}elseif (e.getActionCommand().equals("redJagged")){
setCustomUnderline(as, RED_JAGGED_UNDERLINE);
}elseif (e.getActionCommand().equals("greenJagged")){
setCustomUnderline(as, GREEN_JAGGED_UNDERLINE);
}elseif (e.getActionCommand().equals("reset")){
setCustomUnderline(as, NO_CUSTOM_UNDERLINE);
}
pane.setCharacterAttributes(as,false);
// pane.revalidate(); // does not help...
// pane.repaint(); // does not help...
}
publicclass ExtendedEditorKitextends StyledEditorKit{
public ViewFactory getViewFactory(){
returnnew ExtendedViewFactory();
}
}
class ExtendedViewFactoryimplements ViewFactory{
public View create(Element elem){
String kind = elem.getName();
if (kind !=null){
if (kind.equals(AbstractDocument.ContentElementName)){
int customUnderlineType = getCustomUnderline(elem
.getAttributes());
if (customUnderlineType == GREEN_JAGGED_UNDERLINE){
returnnew JaggedLabelView(elem, Color.green);
}elseif (customUnderlineType == RED_JAGGED_UNDERLINE){
returnnew JaggedLabelView(elem, Color.red);
}elseif (customUnderlineType == GREEN_UNDERLINE){
returnnew ColorLabelView(elem, Color.green);
}elseif (customUnderlineType == RED_UNDERLINE){
returnnew ColorLabelView(elem, Color.red);
}else
returnnew LabelView(elem);
}elseif (kind.equals(AbstractDocument.ParagraphElementName)){
returnnew ParagraphView(elem);
}elseif (kind.equals(AbstractDocument.SectionElementName)){
returnnew BoxView(elem, View.Y_AXIS);
}elseif (kind.equals(StyleConstants.ComponentElementName)){
returnnew ComponentView(elem);
}elseif (kind.equals(StyleConstants.IconElementName)){
returnnew IconView(elem);
}
}
returnnew LabelView(elem);
}
}
class JaggedLabelViewextends LabelView{
private Color color;
public JaggedLabelView(Element elem, Color color){
super(elem);
this.color = color;
}
publicvoid paint(Graphics g, Shape allocation){
super.paint(g, allocation);
paintJaggedLine(g, allocation);
}
publicvoid paintJaggedLine(Graphics g, Shape a){
int y = (int) (a.getBounds().getY() + a.getBounds().getHeight());
int x1 = (int) a.getBounds().getX();
int x2 = (int) (a.getBounds().getX() + a.getBounds().getWidth());
Color old = g.getColor();
g.setColor(color);
int w = 3;
int h = 2;
for (int i = x1; i <= x2; i += w * 2){
g.drawArc(i + 0, y - h, w, h, 0, 180);
g.drawArc(i + w, y - h, w, h, 180, 181);
}
g.setColor(old);
}
}
class ColorLabelViewextends LabelView{
private Color color;
public ColorLabelView(Element elem, Color color){
super(elem);
this.color = color;
}
publicvoid paint(Graphics g, Shape allocation){
super.paint(g, allocation);
paintLine(g, allocation);
}
publicvoid paintLine(Graphics g, Shape a){
int y = (int) (a.getBounds().getY() + a.getBounds().getHeight());
int x1 = (int) a.getBounds().getX();
int x2 = (int) (a.getBounds().getX() + a.getBounds().getWidth());
Color old = g.getColor();
g.setColor(color);
g.drawLine(x1, y - 2, x2, y - 2);
g.setColor(old);
}
}
publicstaticfinal String CustomUnderline ="customUnderline";
publicstaticfinalint RED_UNDERLINE = 1;
publicstaticfinalint GREEN_UNDERLINE = 2;
publicstaticfinalint RED_JAGGED_UNDERLINE = 3;
publicstaticfinalint GREEN_JAGGED_UNDERLINE = 4;
publicstaticfinalint NO_CUSTOM_UNDERLINE = -1;
publicstaticvoid setCustomUnderline(MutableAttributeSet a,int type){
a.addAttribute(CustomUnderline,new Integer(type));
}
publicstaticint getCustomUnderline(AttributeSet a){
Object o = a.getAttribute(CustomUnderline);
if (o !=null){
try{
return Integer.parseInt(o.toString());
}catch (Exception x){
return NO_CUSTOM_UNDERLINE;
}
}
return NO_CUSTOM_UNDERLINE;
}
}

