【问题标题】:How do i render wrapped text on an image in java如何在java中的图像上呈现包装文本
【发布时间】:2012-08-21 05:05:36
【问题描述】:

使用 Java,是否有任何内置方法来呈现文本,使其限制在 graphics2D 对象上的矩形?

我知道我可以使用Graphics2D.drawString,但它只能绘制一行文本。

我也知道我可以用

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

在使用某些Font font 对某些Graphics2D graphics 对象进行渲染时,获取有关字符串边界的信息。

所以我可以开始循环,打破我的字符串等等,以强制它适合某个矩形。

但我宁愿不必写那些......

是否有任何现成的功能可以为我做到这一点?

【问题讨论】:

标签: java text graphics rendering awt


【解决方案1】:

使用临时 JTextArea 用大约 10 行代码进行完美的换行:

static void drawWrappedText(Graphics g, String text, int x, int y, int w, int h) {
    JTextArea ta = new JTextArea(text);
    ta.setLineWrap(true);
    ta.setWrapStyleWord(true);
    ta.setBounds(0, 0, w, h);
    ta.setForeground(g.getColor());
    ta.setFont(g.getFont());
    Graphics g2 = g.create(x, y, w, h); // Use new graphics to leave original graphics state unchanged
    ta.paint(g2);
}

【讨论】:

  • 很高兴看到有人仍然关心回答我 8.5 年前提出的问题。我很欣赏这种努力。我不知道为什么我问这个问题,也不知道为什么我过去不接受任何答案(我尽量不留下开放的 Q)。我也没有环境来测试您的答案(也没有时间这样做)-但是,鉴于它的简短,最近并且至少似乎可以满足我很久以前的要求,我将接受您的答案并让社区投票它...
【解决方案2】:

查看this answer 中的LabelRenderTest 源。它使用 HTML/CSS,使用 CSS 设置正文宽度,从而自动换行。

【讨论】:

【解决方案3】:
 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;
}

【讨论】:

    【解决方案4】:

    我写了一个可以提供帮助的小函数。 447 是可用的宽度,您可以从所需的宽度中获得以在其上呈现文本。

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

    【讨论】:

      【解决方案5】:

      这可能就是你要找的东西:

      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:jimm@io.com">jimm@io.com</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;
        }
      
      }
      

      你可以把它放在它自己的类中,然后简单地使用你所拥有的:

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

      调用wrap(String str, FontMetrics fm, int maxWidth) 将返回Strings 中的List,这些maxWidth 将是Rectangle2D 的宽度,文本将被放入:

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

      参考:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多