2012-08-26 24 views
5

Sử dụng Java, có cách nào để hiển thị văn bản sao cho văn bản được giới hạn ở hình chữ nhật trên đối tượng graphics2D không?Làm cách nào để hiển thị văn bản được bao bọc trên hình ảnh trong java

Tôi biết tôi có thể sử dụng Graphics2D.drawString nhưng nó chỉ vẽ một dòng văn bản đầy tội lỗi.

Tôi cũng biết rằng tôi có thể sử dụng

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

để có được thông tin về các giới hạn của một chuỗi khi render sử dụng một số Font font trên một số đối tượng Graphics2D graphics.

Vì vậy, tôi có thể bắt đầu lặp, phá vỡ chuỗi của mình và cứ thế để buộc nó vừa với một số hình chữ nhật.

Nhưng tôi rất muốn không phải viết những ...

Có chức năng nào đã sẵn sàng thực hiện việc này cho tôi không?

+0

Cá nhân tôi giống như ví dụ chứng minh bởi Andrew vì nó là tương đối nhanh chóng để đạt được. Tuy nhiên, tôi đã sử dụng cách tiếp cận này trong http://java.sun.com/developer/onlineTraining/Media/2DText/style.html#multiple – MadProgrammer

+0

Bất kỳ Ưu điểm và Nhược điểm nào về hai lựa chọn thay thế? – epeleg

+0

Tôi muốn nói giải pháp của Andrew dễ hơn, IMHO – MadProgrammer

Trả lời

4

này đây có thể là những gì bạn đang tìm kiếm:

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

} 

bạn muốn đặt này trong lớp học của riêng mình, sau đó chỉ cần sử dụng những gì bạn có:

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

gọi wrap(String str, FontMetrics fm, int maxWidth) sẽ trả lại List của String s đã được gói acco rdingly để maxWidth của bạn mà sẽ là chiều rộng của Rectangle2D văn bản sẽ được đưa vào:

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

tham khảo:

3

Xem nguồn LabelRenderTest.java trong this answer. Nó sử dụng HTML/CSS, với chiều rộng cơ thể được thiết lập bằng cách sử dụng CSS, và do đó làm cho dòng bọc tự động.

+0

+1 kỹ thuật đẹp Tôi phải nói –

+0

@David Những người khác sẽ không đồng ý với bạn, trích dẫn sử dụng định dạng HTML, chúng tôi mất một số lợi ích của bố cục (liên quan đến dòng .. thả AFAIR) và hỗ trợ J2SE cho HTML được giới hạn ở 3.2, và hỗ trợ CSS tương đối chắp vá và không có giấy tờ. OTOH, nó có thể là một cách nhanh chóng để có được văn bản được bao bọc tự động. –

5

Tôi đã viết một chức năng nhỏ có thể trợ giúp. 447 là chiều rộng có sẵn mà bạn có thể nhận được từ chiều rộng yêu cầu của bạn để hiển thị văn bản.

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