2012-08-26 14 views
5

Utilizzo di Java, esiste un modo incorporato per eseguire il rendering del testo in modo che sia limitato a un rettangolo su un oggetto graphics2D?Come eseguire il rendering del testo avvolto su un'immagine in java

So che posso usare Graphics2D.drawString ma disegna solo una riga di testo sinlge.

so anche che posso usare

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

per ottenere le informazioni sui limiti di una stringa se fusi utilizzando alcuni Font font su alcuni Graphics2D graphics oggetto.

Così ho potuto iniziare il ciclo, spezzare la mia corda e così via per forzarla ad adattarsi all'interno di un rettangolo.

Ma vorrei tanto preferisco non dover scrivere quelle ...

C'è qualche funzione di ready made che farà questo per me?

+0

Personalmente, come l'esempio dimostrato da Andrew in quanto è relativamente veloce da realizzare. Tuttavia, ho utilizzato questo approccio in passato http://java.sun.com/developer/onlineTraining/Media/2DText/style.html#multiple – MadProgrammer

+0

Eventuali pro e contro sulle due alternative? – epeleg

+0

Direi che la soluzione di Andrew è più semplice, IMHO – MadProgrammer

risposta

4

Questo qui potrebbe essere quello che stai cercando:

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

} 

che ci si mettere questo nella sua propria classe, poi semplicemente utilizzando ciò che si aveva:

chiamare wrap(String str, FontMetrics fm, int maxWidth) che restituirà un List di String s che sono stati impacchettati acco rdingly al tuo maxWidth che sarà la larghezza del Rectangle2D il testo sarà messo in:

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

Riferimento:

3

vedere la fonte LabelRenderTest.java in this answer. Utilizza HTML/CSS, con la larghezza del corpo impostata tramite CSS, e rende quindi automatico il ritorno a capo automatico.

+0

+1 bella tecnica Devo dire –

+0

@David Altri non sarebbero d'accordo con te, citando che usando la formattazione HTML perdiamo alcuni dei vantaggi dei layout (qualcosa da fare con la linea .. rilascia AFAIR) e il supporto J2SE per HTML è limitato a 3.2, e il supporto CSS è relativamente irregolare e non documentato. OTOH, può essere un modo veloce e non desiderabile per ottenere il testo automaticamente. –

5

ho scritto una piccola funzione che può aiutare. 447 è la larghezza disponibile che puoi ottenere dalla larghezza richiesta per rendere il testo attivo.

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