2012-08-26 7 views
5

Mit Java, gibt es eine eingebaute Möglichkeit, Text zu rendern, so dass es auf ein Rechteck auf einem graphics2D Objekt beschränkt ist?Wie rende ich verpackten Text auf ein Bild in Java

Ich weiß, ich kann Graphics2D.drawString verwenden, aber es zeichnet nur eine einzige Zeile Text.

Ich weiß auch, dass ich

FontMetrics fm= graphics.getFontMetrics(font); 
Rectangle2D rect=fm.getStringBounds("Some Text",graphics); 

verwenden können, die Informationen über die Grenzen einer Zeichenfolge zu erhalten, wenn einige Font font auf einige Graphics2D graphics-Objekt erstellt.

So könnte ich anfangen zu loopen, brechen meine Saite und so weiter, um es in ein Rechteck zu passen.

Aber ich würde viel lieber nicht haben, um diejenigen zu schreiben ...

Gibt es eine fertige Funktion, die das für mich tun?

+0

ich persönlich wie das Beispiel von Andrew bewiesen, wie es zu erreichen, relativ schnell ist. Ich habe jedoch diesen Ansatz in der Vergangenheit verwendet http://java.sun.com/developer/onlineTraining/Media/2DText/style.html#multiple – MadProgrammer

+0

Alle Vor- und Nachteile auf den beiden Alternativen? – epeleg

+0

Ich würde sagen, Andrews Lösung ist einfacher, IMHO – MadProgrammer

Antwort

4

hier Dies könnte das sein, was Sie suchen:

StringUtils.java:

import java.awt.FontMetrics; 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.Iterator; 
import java.util.List; 

/** 
* Globally available utility classes, mostly for string manipulation. 
* 
* @author Jim Menard, <a href="mailto:[email protected]">[email protected]</a> 
*/ 
public class StringUtils { 
    /** 
    * Returns an array of strings, one for each line in the string after it has 
    * been wrapped to fit lines of <var>maxWidth</var>. Lines end with any of 
    * cr, lf, or cr lf. A line ending at the end of the string will not output a 
    * further, empty string. 
    * <p> 
    * This code assumes <var>str</var> is not <code>null</code>. 
    * 
    * @param str 
    *   the string to split 
    * @param fm 
    *   needed for string width calculations 
    * @param maxWidth 
    *   the max line width, in points 
    * @return a non-empty list of strings 
    */ 
    public static List wrap(String str, FontMetrics fm, int maxWidth) { 
    List lines = splitIntoLines(str); 
    if (lines.size() == 0) 
     return lines; 

    ArrayList strings = new ArrayList(); 
    for (Iterator iter = lines.iterator(); iter.hasNext();) 
     wrapLineInto((String) iter.next(), strings, fm, maxWidth); 
    return strings; 
    } 

    /** 
    * Given a line of text and font metrics information, wrap the line and add 
    * the new line(s) to <var>list</var>. 
    * 
    * @param line 
    *   a line of text 
    * @param list 
    *   an output list of strings 
    * @param fm 
    *   font metrics 
    * @param maxWidth 
    *   maximum width of the line(s) 
    */ 
    public static void wrapLineInto(String line, List list, FontMetrics fm, int maxWidth) { 
    int len = line.length(); 
    int width; 
    while (len > 0 && (width = fm.stringWidth(line)) > maxWidth) { 
     // Guess where to split the line. Look for the next space before 
     // or after the guess. 
     int guess = len * maxWidth/width; 
     String before = line.substring(0, guess).trim(); 

     width = fm.stringWidth(before); 
     int pos; 
     if (width > maxWidth) // Too long 
     pos = findBreakBefore(line, guess); 
     else { // Too short or possibly just right 
     pos = findBreakAfter(line, guess); 
     if (pos != -1) { // Make sure this doesn't make us too long 
      before = line.substring(0, pos).trim(); 
      if (fm.stringWidth(before) > maxWidth) 
      pos = findBreakBefore(line, guess); 
     } 
     } 
     if (pos == -1) 
     pos = guess; // Split in the middle of the word 

     list.add(line.substring(0, pos).trim()); 
     line = line.substring(pos).trim(); 
     len = line.length(); 
    } 
    if (len > 0) 
     list.add(line); 
    } 

    /** 
    * Returns the index of the first whitespace character or '-' in <var>line</var> 
    * that is at or before <var>start</var>. Returns -1 if no such character is 
    * found. 
    * 
    * @param line 
    *   a string 
    * @param start 
    *   where to star looking 
    */ 
    public static int findBreakBefore(String line, int start) { 
    for (int i = start; i >= 0; --i) { 
     char c = line.charAt(i); 
     if (Character.isWhitespace(c) || c == '-') 
     return i; 
    } 
    return -1; 
    } 

    /** 
    * Returns the index of the first whitespace character or '-' in <var>line</var> 
    * that is at or after <var>start</var>. Returns -1 if no such character is 
    * found. 
    * 
    * @param line 
    *   a string 
    * @param start 
    *   where to star looking 
    */ 
    public static int findBreakAfter(String line, int start) { 
    int len = line.length(); 
    for (int i = start; i < len; ++i) { 
     char c = line.charAt(i); 
     if (Character.isWhitespace(c) || c == '-') 
     return i; 
    } 
    return -1; 
    } 
    /** 
    * Returns an array of strings, one for each line in the string. Lines end 
    * with any of cr, lf, or cr lf. A line ending at the end of the string will 
    * not output a further, empty string. 
    * <p> 
    * This code assumes <var>str</var> is not <code>null</code>. 
    * 
    * @param str 
    *   the string to split 
    * @return a non-empty list of strings 
    */ 
    public static List splitIntoLines(String str) { 
    ArrayList strings = new ArrayList(); 

    int len = str.length(); 
    if (len == 0) { 
     strings.add(""); 
     return strings; 
    } 

    int lineStart = 0; 

    for (int i = 0; i < len; ++i) { 
     char c = str.charAt(i); 
     if (c == '\r') { 
     int newlineLength = 1; 
     if ((i + 1) < len && str.charAt(i + 1) == '\n') 
      newlineLength = 2; 
     strings.add(str.substring(lineStart, i)); 
     lineStart = i + newlineLength; 
     if (newlineLength == 2) // skip \n next time through loop 
      ++i; 
     } else if (c == '\n') { 
     strings.add(str.substring(lineStart, i)); 
     lineStart = i + 1; 
     } 
    } 
    if (lineStart < len) 
     strings.add(str.substring(lineStart)); 

    return strings; 
    } 

} 

Sie würden dies in seiner eigenen Klasse setzen, dann einfach mit, was Sie hatte:

FontMetrics fm= graphics.getFontMetrics(font); 
Rectangle2D rect=fm.getStringBounds("Some Text",graphics); 

Anruf wrap(String str, FontMetrics fm, int maxWidth) die eine List von String s zurück, die acco gewickelt wurden rdingly zu Ihrem maxWidth die wird die Breite des Rectangle2D der Text gesetzt werden:

String text="Some Text"; 
FontMetrics fm= graphics.getFontMetrics(font); 
Rectangle2D rect=fm.getStringBounds(text,graphics); 
List<String> textList=StringUtils.wrap(text, fm, int maxWidth); 

Referenz:

3

Siehe LabelRenderTest.java Quelle in this answer. Es verwendet HTML/CSS mit der Körperbreite, die mit CSS eingestellt wird, und macht dadurch Zeilenumbruch automatisch.

+0

+1 nette Technik muss ich sagen –

+0

@David Andere würden mit Ihnen nicht übereinstimmen, zitiert, dass mit HTML-Formatierung verlieren wir einige der Vorteile der Layouts (etwas mit Linie zu tun .. drop AFAIR) und die J2SE-Unterstützung für HTML ist auf 3.2 begrenzt. & CSS-Unterstützung ist relativ lückenhaft und nicht dokumentiert. OTOH, es kann eine schnelle und einfache Art sein, den Text automatisch zu verpacken. –

5

schrieb ich eine kleine Funktion, die helfen können. 447 ist die verfügbare Breite, die Sie von der erforderlichen Breite zum Rendern von Text erhalten können.

private void drawTextUgly(String text, FontMetrics textMetrics, Graphics2D g2) 
{ 
    // Ugly code to wrap text 
    int lineHeight = textMetrics.getHeight(); 
    String textToDraw = text; 
    String[] arr = textToDraw.split(" "); 
    int nIndex = 0; 
    int startX = 319; 
    int startY = 113; 
    while (nIndex < arr.length) 
    { 
     String line = arr[nIndex++]; 
     while ((nIndex < arr.length) && (textMetrics.stringWidth(line + " " + arr[nIndex]) < 447)) 
     { 
      line = line + " " + arr[nIndex]; 
      nIndex++; 
     } 
     GraphicsUtility.drawString(g2, line, startX, startY); 
     startY = startY + lineHeight; 
    } 
} 
1
private List<String> wrap(String txt, FontMetrics fm, int maxWidth){ 
    StringTokenizer st = new StringTokenizer(txt) ; 

    List<String> list = new ArrayList<String>(); 
    String line = ""; 
    String lineBeforeAppend = ""; 
    while (st.hasMoreTokens()){ 
     String seg = st.nextToken(); 
     lineBeforeAppend = line; 
     line += seg + " "; 
     int width = fm.stringWidth(line); 
     if(width < maxWidth){ 
      continue; 
     }else { //new Line. 
      list.add(lineBeforeAppend); 
      line = seg + " "; 
     } 
    } 
    //the remaining part. 
    if(line.length() > 0){ 
     list.add(line); 
    } 
    return list; 
}