puurfect line wrap

This is my linewrap code, it hasn’t failed me yet:


    public ArrayList<String> splitLines(String s, FontMetrics fm) {
        ArrayList<String> ret = new ArrayList<String>();
        String ln = "";
        StringTokenizer st = new StringTokenizer(s);
        String nt;
        while (st.hasMoreTokens()) {
            nt = st.nextToken();
            if (fm.stringWidth(ln + nt) >= maxWidth) {
                ret.add(new String(ln));
                ln = "";
                ln += nt + " ";
            } else {
                ln += nt + " ";
            }
        }
        ret.add(ln);
        //fix the lengths
        int lo = ret.size();
        for (int i = 0; i < lo; i++) {
            if (fm.stringWidth(ret.get(i)) > maxWidth) {
                //umm
                String the = ret.get(i);
                String other = "";
                int fk = 0;
                for (int j = 0; j < the.length(); j++) {
                    char ch = the.charAt(the.length() - 1);
                    the = the.substring(0, the.length() - 1);
                    other += ch;
                    fk = j;
                }
                ret.set(i, the);
                ret.add(i + 1, new StringBuffer(other).reverse().toString());
                i--;
            }
        }
        return ret;
    }

Have fun and report bugs.

Bug #1: You forgot to add maxWidth as a method parameter :slight_smile:

Immediately, I can see a huge problem - the StringTokenizer is removing tab, newline, carriage-return & form-feed characters - and your code is replacing them with just spaces.

Beyond this fundamental problem, there also doesn’t appear to be any support for even the bare minimum of formatting controls?
i.e. Soft-hyphen’s ( \u00AD ) & zero width spaces ( \u200B ).

The way you are manipulating Strings also looks to be extremely inefficient.

As i’ve mentioned before, Text wrapping is in no way a trivial problem.
Having had to write & rewrite many different implementations in J2ME (a platform that does not have the luxurious api provided by J2SE), I can assure you an adequate solution will take many development iterations, will require dozens of test cases, and will end up being a complex bit of code.

If you are developing for J2SE USE THE LIBRARIES PROVIDED, to do otherwise is simply wasting your own time.

Do you know the standard libs that do text wrapping? I’ve never come across them, but it is handy to have a method like Renoria’s for making custom text panes that have nothing to do with Swing and its threading model.

This thread is a continuation of this.

To CommanderKeith, the class is java.awt.font.LineBreakMeasurer.

make that a final int.

Cool, thanks

Carriage return? Replaced and this code recalculates line breaks :smiley:

how is this inefficient? I hate the Java API Libs sometimes =X

[quote=“Renoria,post:8,topic:32691”]
Using += with strings tends to be inefficient because of the way things are implemented internally; basically, a new string is allocated each time, and the whole thing is copied, and so on (almost as if you added each new element to an ArrayList by copying the entire list to a newly allocated backing array with one more element). If you’re building strings piece by piece, you should usually use StringBuilder (http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html) instead of directly adding Strings.

And yup, this is an implementation detail that should not be your concern - string concatenation is such a common task that the String class should probably be backed by some form of dynamic array to begin with, or should at least switch over automatically if it’s clear that a lot of adds are happening (or at the very least, StringBuilder should at least have some of the same syntax sugar that String has, which would make it a bit easier to change code after the fact to use that instead of String concatenation); however, this behavior has been with us since the inception of Java, so it’s worth knowing about since it’s never likely to change.

Also, I’ll agree with you on one thing - java.awt.font.LineBreakMeasurer isn’t exactly a very user friendly or obvious API, at least to do what you want to do. Sometimes you’re right, implementing your own special purpose methods to do things that the Java API already does may turn out to be worth it, esp. if you can get better performance or a cleaner API (raise your hand if you’ve never implemented your own dynamic primitive arrays because ArrayList sucks for primitives…anyone? That’s what I thought…). If your code works for what you need it for, that’s fine; on the other hand, setting up code that will do what everyone might ever need to do is a bit harder, and I think that’s what Abuse’s comments were directed at.

I’d use StringBuffer instead of StringBuilder because of synchronization issues. StringBuilder isn’t thread safe, but it IS faster.

Insertion of additional line breaks does not preclude the need for existing line breaks to be maintained.
For example, take the input String:-

"Title

A paragraph.

Another Paragraph."

Given a sufficiently large wrap width, your method will output a wrapped string containing “Title A paragraph. Another Paragraph.”
This loss of information is clearly not desirable.

This code is fine for my chatbubbles in my MMO, you can edit it all you like, theres no license…