2012-08-26 29 views
5

Usando Java, ¿hay alguna forma incorporada de representar texto para que esté limitado a un rectángulo en un objeto graphics2D?¿Cómo puedo renderizar texto envuelto en una imagen en java

Sé que puedo usar Graphics2D.drawString pero solo dibuja una línea de texto simple.

también sé que puedo usar

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

para obtener la información acerca de los límites de una cadena cuando se representa el uso de algunos Font font en algunas Graphics2D graphics objeto.

Así podría comenzar a hacer bucles, romper mi cuerda y demás para forzarlo a caber dentro de un rectángulo.

Pero me gustaría mucho prefieren no tener que escribir los ...

¿Hay alguna función ya hecha que va a hacer esto por mí?

+0

personalmente me gusta el ejemplo demostrado por Andrew ya que es relativamente rápida de lograr. Sin embargo, utilicé este enfoque en el pasado http://java.sun.com/developer/onlineTraining/Media/2DText/style.html#multiple – MadProgrammer

+0

¿Alguna ventaja y desventaja en las dos alternativas? – epeleg

+0

Yo diría que la solución de Andrew es más sencilla, IMHO – MadProgrammer

Respuesta

4

Esta aquí podría ser lo que busca:

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; 
    } 

} 

que había puesto esto en su propia clase, a continuación, simplemente usando lo que tenía:

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

llamada wrap(String str, FontMetrics fm, int maxWidth) que devolverá un List de String s que se han envuelto rdingly a su maxWidth que será el ancho de la Rectangle2D el texto será puesto en:

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

Referencia:

3

Ver la fuente LabelRenderTest.java en this answer. Utiliza HTML/CSS, con el ancho del cuerpo establecido mediante CSS, y por lo tanto hace que el ajuste de línea sea automático.

+0

+1 buena técnica Debo decir –

+0

@David Otros estarían en desacuerdo contigo, citando que al usar formato HTML, perdemos algunos de los beneficios de los diseños (algo que ver con la línea ... soltar AFAIR) y el soporte de J2SE para HTML está limitado a 3.2, y el soporte de CSS es relativamente desigual e indocumentado. OTOH, puede ser una forma rápida de envolver el texto automáticamente. –

5

escribí una pequeña función que puede ayudar. 447 es el ancho disponible que puede obtener desde el ancho requerido para procesar el texto.

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; 
} 
Cuestiones relacionadas