I spent a while today messing with JTextPane, as a sort of research for Joust Secure IM Lite's conversation window. I figured out how to insert HTML tags and text and stuff using ElementSpec objects and all sorts of fun stuff like that.
Swing's HTML renderer is cool in a lot of ways, but it does something stupid when word-wrapping: it refuses to split long words when word-wrapping. (It looks like the caption on the right.) This means that the textbox must be at least as wide as the longest word. This is not what most people want, I don't think, and it's especially inappropriate for a chat application (I think having to scroll horizontally within an IM window would be annoying).
Luckily, there's an easy, sort of hacky fix, if you're using HTMLEditorKit. (It might work with other document types, like DefaultStyledEditorKit.) You need to subclass HTMLEditorKit:
(The following code is released in the public domain.)
private static class MyEditorKit extends HTMLEditorKit {
public ViewFactory getViewFactory() {
return new MyViewFactory(super.getViewFactory());
}
private static class WordSplittingParagraphView extends ParagraphView {
public WordSplittingParagraphView(Element elem) {
super(elem);
}
protected SizeRequirements calculateMinorAxisRequirements(int axis,
SizeRequirements r) {
SizeRequirements sup = super.calculateMinorAxisRequirements(axis, r);
sup.minimum = 1;
return sup;
}
}
private static class MyViewFactory implements ViewFactory {
private final ViewFactory parent;
public MyViewFactory(ViewFactory parent) {
this.parent = parent;
}
public View create(Element elem) {
AttributeSet attr = elem.getAttributes();
Object name = attr.getAttribute(StyleConstants.NameAttribute);
if (name == HTML.Tag.P || name == HTML.Tag.IMPLIED) {
return new WordSplittingParagraphView(elem);
}
return parent.create(elem);
}
}
}
This code makes the text pane look more like the image on the right. The code provides a custom View object for paragraph elements in the HTML. The custom View object sets a minimum width of 1 pixel, where the default view would've set it to the width of the longest word in the paragraph. This allows a paragraph to be any width on the screen, regardless of how long its words are. (We're lucky that the paragraph renderer wraps correctly even if its minimum size is smaller than the longest word.)
This solution isn't perfect, and you should probably change part of it if you're going to use it in your application. Specifically, the minimum width should not be 1 pixel: unfortunately, the paragraph renderer we subclassed gets upset when its width is smaller than the first character of a line. It fights with its parent JScrollPane and ends up using 100% CPU, unless the scroll pane has a vertical scroll policy of NEVER or ALWAYS (the default is IF_NEEDED).
This problem happens because when the width is smaller than a single character, the paragraph renderer can't fit any characters on the line, and it probably wasn't written with a situation like that in mind, since by default the width is no smaller than the longest word on the line.
The solution to this is probably to go through the paragraph and find the widest character, and set the minimum width to that character's width. I haven't implemented this yet, but it shouldn't be too hard.
Posted by keith at February 22, 2004 03:39 AM | TrackBackrather than iterating the paragraph characters to find the widest one you could just query the font metrics for the font you are using to find the max character width.
First check font.getMaxAdvance() which may return -1 in which case you would have to iterate the result of font.getWidths() which returns an array of widths the first 256 chars in the font to find the max.
You would only have to do this once whenever the font was set/changed and you would be set so, it would provide a great performance boost over checking the paragraph text each time.
P.S. don't forget about formatting such as bold or italic or BoldItalic which could expand the widths - if you are allowing these formats check for the widest possible character (probably bolditalic).
Yeah, that's a good idea, but it wouldn't work so well since there might be different font sizes and styles within the text, so I'd have to end up going through the text anyway. I'll see what's fastest when I implement that part.
Posted by: Keith Lea at February 28, 2004 02:54 AMNice site. You are doing a great service to the web.
gold online casinos (online casino)
Posted by: gold online casinos (online casino) at June 20, 2004 11:42 AMhjbj
Posted by: online casino at July 15, 2004 05:59 AMThis is my first time here and was wondering how often posts are made?
Posted by: Raimi at August 9, 2004 03:37 AMWill my personal information be public if I post here?
Posted by: Evita at August 17, 2004 07:27 AMI'm just browsing around your site for the first time, interesting read
Posted by: Stephanie at August 17, 2004 03:33 PM