Wrap long words in JTextPane (Java 7)

懵懂的女人 提交于 2019-11-29 01:24:56

For me the fix works (tested under 1.7.0_09)

import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;

public class WrapTestApp extends JFrame {

    public static void main ( String[] args ) {
        new WrapTestApp();
    }

    public WrapTestApp () {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(200,200);
        getContentPane().setLayout(new BorderLayout());
        JTextPane jtp = new JTextPane();
        jtp.setEditorKit(new WrapEditorKit());
        JScrollPane jsp = new JScrollPane(jtp);
        jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        getContentPane().add(jsp, BorderLayout.CENTER);
        jtp.setText("ExampleOfTheWrapLongWordWithoutSpaces");
        setVisible(true);
    }

    class WrapEditorKit extends StyledEditorKit {
        ViewFactory defaultFactory=new WrapColumnFactory();
        public ViewFactory getViewFactory() {
            return defaultFactory;
        }

    }

    class WrapColumnFactory implements ViewFactory {
        public View create(Element elem) {
            String kind = elem.getName();
            if (kind != null) {
                if (kind.equals(AbstractDocument.ContentElementName)) {
                    return new WrapLabelView(elem);
                } 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);
        }
    }

    class WrapLabelView extends LabelView {
        public WrapLabelView(Element elem) {
            super(elem);
        }

        public float getMinimumSpan(int axis) {
            switch (axis) {
                case View.X_AXIS:
                    return 0;
                case View.Y_AXIS:
                    return super.getMinimumSpan(axis);
                default:
                    throw new IllegalArgumentException("Invalid axis: " + axis);
            }
        }

    }
}
PhiLho

Good catch from @dk89, but alas the given workarounds don't work: JDK 7 apparently still doesn't offer a wait to set a custom BreakIterator on a JTextComponent; not even on a GlyphView, where the generation of the BreakIterator is private. And if we insert the string char by char, it still doesn't work: I suppose the consecutive runs of text with identical style (AttributeSet) are collapsed together.

I have spent two days trying to do a custom EditorKit, as advised elsewhere, but it doesn't work well (with JDK 1.7.0_4 at least) as the text.

I tried the solution given at How to word wrap text stored in JTextPanes which are cells in a JList and a variant found at http://www.experts-exchange.com/Programming/Languages/Java/Q_20393892.html

But I found out that the breakView is no longer called when the JTextPane is smaller than the longest word in the sentence. So it doesn't work at all when there is only one (long) word. That's our case, as we display user-provided, identifier-like strings, often without spaces, in rather small spaces.

I finally found a simple solution, derived from the suggestion in the bug report: indeed, insert the string char by char, but alternate styles! Thus, we have as many segments as we have chars, and the string is wrapped at char bounds. Until the next "bug fix"?

Code snippets:

private JTextPane tp;
private SimpleAttributeSet sas = new SimpleAttributeSet();

tp= new JTextPane();
sas.addAttribute( "A", "C" ); // Arbitrary attribute names and value, not used actually

    // Set the global attributes (italics, etc.)
    tp.setParagraphAttributes(styleParagraphAttributes, true);

    Document doc = tp.getDocument();
    try
    {
        doc.remove(0, doc.getLength()); // Clear
        for (int i = 0; i < textToDisplay.length(); i++)
        {
            doc.insertString(doc.getLength(), textToDisplay.substring(i, i+1),
                    // Change attribute every other char
                    i % 2 == 0 ? null : sas);
        }
    }
    catch (BadLocationException ble)
    {
        log.warn("Cannot happen...", ble);
    }

As stated in the bug, they should have provided an easy way (some property perhaps, or some injectable stuff) to revert to the old behavior.

Hi I've had the same problem but found a work-around:

just create an extended class of JTextPane e.g.

        MyWrapJTextPane extends JTextPane

and overwrite the following method - it works ;-)

        public boolean getScrollableTracksViewportWidth() {
            return true;
        }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!