Search code examples
javaswingsvgword-wrapjtextarea

How to extract the word and line wrapping information from JTextArea for text with given font


I have to convert styled text to wrapped simple text (for SVG word wrapping). I cannot beleive that the word wrapping information (how many lines are there, where are the line breaks) cannot be extracted from the JTextArea. So I created a small frame program:

package bla;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JTextArea;

public class Example1 extends WindowAdapter {
    private static String content = "01234567890123456789\n" + "0123456 0123456 01234567 01234567";
    JTextArea text;

    public Example1() {
        Frame f = new Frame("TextArea Example");
        f.setLayout(new BorderLayout());
        Font font = new Font("Serif", Font.ITALIC, 20);
        text = new JTextArea();
        text.setFont(font);
        text.setForeground(Color.blue);
        text.setLineWrap(true);
        text.setWrapStyleWord(true);
        f.add(text, BorderLayout.CENTER);
        text.setText(content);
        // Listen for the user to click the frame's close box
        f.addWindowListener(this);
        f.setSize(100, 511);
        f.show();
    }

    public static List<String> getLines( JTextArea text ) {
        //WHAT SHOULD I WRITE HERE
        return new ArrayList<String>();
    }

    public void windowClosing(WindowEvent evt) {
        List<String> lines = getLines(text);
        System.out.println( "Number of lines:" + lines.size());
        for (String line : lines) {
            System.out.println( line );
        }
        System.exit(0);
    }

    public static void main(String[] args) {
        Example1 instance = new Example1();
    }

}

If you run it you will see this:

The displayed picture is this

And what I expect as output:

Number of lines:6
0123456789
0123456789
0123456
0123456
01234567
01234567

What should I write in place of the comment?

Complete answer:

So, then the complete solution based on the accepted answer without displaying the frame actually (note, that you should remove the actual newline characters from the result):

package bla;

import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
import javax.swing.text.Utilities;

public class Example1 {
    private static String content = "01234567890123456789\n" + "0123456 0123456 01234567 01234567";

    public static List<String> getLines( String textContent, int width, Font font ) throws BadLocationException {
        JTextArea text;
        text = new JTextArea();
        text.setFont(font);
        text.setForeground(Color.blue);
        text.setLineWrap(true);
        text.setWrapStyleWord(true);
        text.setText(content);
        text.setSize(width, 1);
        int lastIndex = 0;
        int index = Utilities.getRowEnd(text, 0);
        List<String> result = new ArrayList<String>();
        do {
            result.add( textContent.substring( lastIndex, Math.min( index+1, textContent.length() ) ) );
            lastIndex = index + 1;
        }
        while ( lastIndex < textContent.length() && ( index = Utilities.getRowEnd(text, lastIndex) ) > 0 );
        return result;
    }

    public static void main(String[] args) throws BadLocationException {
        Font font = new Font("Serif", Font.ITALIC, 20);
        Example1 instance = new Example1();
        for (String line : getLines(content,110,font)) {
            System.out.println( line.replaceAll( "\n", "") );
        }
    }

} 

Open question in me (not that important), why is that a frame with 100px width containing a jtextarea wraps the text later than a jtextarea without frame with the same width. Ideas for this?


Solution

  • Use Utilities.getRowEnd() Pass 0 as start offset and then previousline's end offset +1