I put a JTextPane
into a JScrollPane
. As I tried, the JTextPane
will auto-wrap a long line if it exceed the width of the display area. And the auto wrapping is based on word boundary
, such as a space
character.
My content contains a lot of space
. And I want to display it literally
. So I need auto-wrapping, but I want it happen ONLY
at the maximum width of display area, NOT
on word boundary
.
How?
What I have tried:
- Replace all the space with '\0', so literally, my content is a
single big word
.
ADD 1
Below is my failed attempt after reading StanislavL's solution. I am not blaming his solution since my scenario is not exactly the same as his.
StanislavL
's solution requires that a row contains at least 2 LabelView
s. According to him, this is imposed by Swing
's implementation of layout()
method where forced break works only if row view has more than one child
(see: http://java-sl.com/wrap.html). So StanislavL
deliberately assigned a special attribute to the \r
character which ensure a separate LabelView
. And use the \r
as a landmark of wrapping. But in my scenario I cannot insert any characters to my content.
My idea is simple, just provide a customized implementation of ViewFactory
for the StyledEditorKit
since the ViewFactory
interface determines the break weight and how a break should happen:
this.jTextPane.setEditorKit(new StyledEditorKit(){
@Override
public ViewFactory getViewFactory(){
return new LetterWrappingStyledViewFactory(maxCharWidth);
}
});
Below is my implementation of the interface ViewFactory
:
public class LetterWrappingStyledViewFactory implements ViewFactory {
public int maxCharWidth = -1; // this is the max width where I want wrap to happen.
public LetterWrappingStyledViewFactory(int maxCharWidth) {
this.maxCharWidth = maxCharWidth;
}
public View create(Element elem) {
String kind = elem.getName();
if (kind != null) {
if (kind.equals(AbstractDocument.ContentElementName)) {
return new LabelView(elem) {
public int getBreakWeight(int axis, float pos, float len) {
if (axis == View.X_AXIS) {
checkPainter();
int p0 = getStartOffset();
int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
if (p1 > maxCharWidth)
return View.ForcedBreakWeight;
else
return View.BadBreakWeight;
}
return super.getBreakWeight(axis, pos, len);
}
public View breakView(int axis, int p0, float pos, float len) {
if (axis == View.X_AXIS) {
checkPainter();
int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
if (p0 == getStartOffset() && p1 <= maxCharWidth) {
return this;
}
return createFragment(p0, maxCharWidth);
}
return this;
}
};
} else if (kind.equals(AbstractDocument.ParagraphElementName)) {
return new ParagraphView(elem);
} else if (kind.equals(AbstractDocument.SectionElementName)) {
return new BoxView(elem, View.Y_AXIS);
} else if (kind.equals(StyleConstants.ComponentElementName)) {
return new ComponentView(elem);
} else if (kind.equals(StyleConstants.IconElementName)) {
return new IconView(elem);
}
}
// default to text display
return new LabelView(elem);
}
}