Articles Projects Tips Downloads Contacts About

Letter wrap in html in JEditorPane.

HTML in browsers provide space based wrap support. Alternatively in custom layout we may need a letter based wrap behaviour. In other words content should be wrapped in the mid of word not by space.

The screenshot shows the letter wrap in html content and in normal text.

In the example the HTMLEditorKit was extended and behaviour of paragraph and text views was changed. Labels provide good break weight for all cases which means we can break label in every necessary offset. Also label provides the break according to the closest position. As for paragraphs size requirements was changed to prevent min size=longest word's size behaviour.

The example code is below:

import java.awt.Dimension; 
import javax.swing.*; 
import javax.swing.text.Element; 
import javax.swing.text.View; 
import javax.swing.text.ViewFactory; 
import javax.swing.text.html.HTMLEditorKit; 
import javax.swing.text.html.InlineView; 
import javax.swing.text.html.ParagraphView; 
public class HtmlLetterWrap { 
    public HtmlLetterWrap(){ 
        final JFrame frame = new JFrame("Letter wrap test"); 
        final JEditorPane htmlTextPane = newJEditorPane(); 
           public ViewFactory getViewFactory(){ 
               return new HTMLFactory(){ 
                   public View create(Element e){ 
                      View v = super.create(e); 
                      if(v instanceof InlineView){ 
                          return new InlineView(e){ 
                              public int getBreakWeight(int axis, float pos, float len) { 
                                  return GoodBreakWeight; 
                              public View breakView(int axis, int p0, float pos, float len) { 
                                  if(axis == View.X_AXIS) { 
                                      int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len); 
                                      if(p0 == getStartOffset() && p1 == getEndOffset()) { 
                                          return this; 
                                      return createFragment(p0, p1); 
                                  return this; 
                      else if (v instanceof ParagraphView) { 
                          return new ParagraphView(e) { 
                              protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { 
                                  if (r == null) { 
                                        r = new SizeRequirements(); 
                                  float pref = layoutPool.getPreferredSpan(axis); 
                                  float min = layoutPool.getMinimumSpan(axis); 
                                  // Don't include insets, Box.getXXXSpan will include them. 
                                    r.minimum = (int)min; 
                                    r.preferred = Math.max(r.minimum, (int) pref); 
                                    r.maximum = Integer.MAX_VALUE; 
                                    r.alignment = 0.5f; 
                                  return r; 
                      return v; 
        htmlTextPane.setText("This text pane contains html. The custom HTMLEditorKit supports single letter wrapping."); 
        JEditorPane noHtmlTextPane = new JEditorPane(); 
        noHtmlTextPane.setText("This text pane contains no html. It supports single letter wrapping!"); 
        htmlTextPane.setMinimumSize(new Dimension(0, 0)); 
        noHtmlTextPane.setMinimumSize(new Dimension(0, 0)); 
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, noHtmlTextPane, htmlTextPane); 
        frame.setSize(200, 200); 
  public static void main(String[] args) {