2009-05-18 84 views
10

我只是寫一些代碼來縮放字體,以適應內的長方形(長度)。它從18寬度開始並向下迭代,直至適合。需要一種方式來縮放字體,以適應矩形

這似乎太沒效率了,但我不能找到一個非循環的方式來做到這一點。 此行用於縮放遊戲網格中的標籤,所以我看不到解決方案(包裝,切割和延伸過矩形都是不可接受的)。

它實際上是相當快的,我這樣做是爲數以百計的矩形,它的速度不夠快,只是慢下來的觸摸。

如果沒有人有更好的事情來了,我就從表中加載開始猜測(因此它比18更接近),並使用此 - 除了它的偉大工程的滯後。

public Font scaleFont(String text, Rectangle rect, Graphics g, Font pFont) { 
    float nextTry=18.0f; 
    Font font=pFont; 

    while(x > 4) {        
      font=g.getFont().deriveFont(nextTry); 
      FontMetrics fm=g.getFontMetrics(font); 
      int width=fm.stringWidth(text); 
      if(width <= rect.width) 
       return font; 
      nextTry*=.9;    
    } 
    return font; 
} 
+0

呵呵。原來Netbeans不太喜歡用`try`作爲標識符... – Tharwen 2012-05-26 18:58:37

回答

16

半僞代碼:

public Font scaleFont(String text, Rectangle rect, Graphics g, Font pFont) { 
    float fontSize = 20.0f; 
    Font font = pFont; 

    font = g.getFont().deriveFont(fontSize); 
    int width = g.getFontMetrics(font).stringWidth(text); 
    fontSize = (rect.width/width) * fontSize; 
    return g.getFont().deriveFont(fontSize); 
} 

我不知道爲什麼你在pFont傳遞,因爲它是不使用...

+0

很好的答案。如果我理解你的代碼,它會讓我想起牛頓 - 拉夫遜近似。也許做兩次而不是一次,更準確,因爲可能會有一些舍入誤差。 – ChrisW 2009-05-18 04:53:57

0

一種不同的,明顯的方法是對位圖的文本預拉伸,然後縮小位圖以適應矩形;但是,由於手工製作的字體設計和提示等,找到合適的字體大小會產生最好看的(儘管可能不是最快的)結果。

1

可以提高使用二進制搜索圖案的效率 - 高/低一些粒度 - 無論是1,0.5或0.25分。

例如,猜測18,是否過高?移至9,太低? 13.5,太低? 15.75,太高了? 14!

3

你可以使用插值搜索:

public static Font scaleFont(String text, Rectangle rect, Graphics g, Font pFont) { 
    float min=0.1f; 
    float max=72f; 
    float size=18.0f; 
    Font font=pFont; 

    while(max - min <= 0.1) { 
     font = g.getFont().deriveFont(size); 
     FontMetrics fm = g.getFontMetrics(font); 
     int width = fm.stringWidth(text); 
     if (width == rect.width) { 
      return font; 
     } else { 
      if (width < rect.width) { 
       min = size; 
      } else { 
       max = size; 
      } 
      size = Math.min(max, Math.max(min, size * (float)rect.width/(float)width)); 
     } 
    } 
    return font; 
} 
2

將所有寬度變量更改爲float,而不是int,以獲得更好的結果。

public static Font scaleFontToFit(String text, int width, Graphics g, Font pFont) 
{ 
    float fontSize = pFont.getSize(); 
    float fWidth = g.getFontMetrics(pFont).stringWidth(text); 
    if(fWidth <= width) 
     return pFont; 
    fontSize = ((float)width/fWidth) * fontSize; 
    return pFont.deriveFont(fontSize); 
} 
2
private Font scaleFont (String text, Rectangle rect, Graphics gc) 
{ 
    final float fMinimumFont = 0.1f; 
    float fMaximumFont = 1000f; 

    /* Use Point2d.Float to hold (font, width of font in pixels) pairs. */ 
    Point2D.Float lowerPoint = new Point2D.Float (fMinimumFont, getWidthInPixelsOfString (text, fMinimumFont, gc)); 
    Point2D.Float upperPoint = new Point2D.Float (fMaximumFont, getWidthInPixelsOfString (text, fMaximumFont, gc)); 
    Point2D.Float midPoint = new Point2D.Float(); 

    for (int i = 0; i < 50; i++) 
    { 
     float middleFont = (lowerPoint.x + upperPoint.x)/2; 

     midPoint.setLocation (middleFont, getWidthInPixelsOfString (text, middleFont, gc)); 

     if (midPoint.y >= rect.getWidth() * .95 && midPoint.y <= rect.getWidth()) 
      break; 
     else if (midPoint.y < rect.getWidth()) 
      lowerPoint.setLocation (midPoint); 
     else if (midPoint.y > rect.getWidth()) 
      upperPoint.setLocation (midPoint); 
    } 

    fMaximumFont = midPoint.x; 

    Font font = gc.getFont().deriveFont (fMaximumFont); 

    /* Now use Point2d.Float to hold (font, height of font in pixels) pairs. */ 
    lowerPoint.setLocation (fMinimumFont, getHeightInPixelsOfString (text, fMinimumFont, gc)); 
    upperPoint.setLocation (fMaximumFont, getHeightInPixelsOfString (text, fMaximumFont, gc)); 

    if (upperPoint.y < rect.getHeight()) 
     return font; 

    for (int i = 0; i < 50; i++) 
    { 
     float middleFont = (lowerPoint.x + upperPoint.x)/2; 

     midPoint.setLocation (middleFont, getHeightInPixelsOfString (text, middleFont, gc)); 

     if (midPoint.y >= rect.getHeight() * .95 && midPoint.y <= rect.getHeight()) 
      break; 
     else if (midPoint.y < rect.getHeight()) 
      lowerPoint.setLocation (midPoint); 
     else if (midPoint.y > rect.getHeight()) 
      upperPoint.setLocation (midPoint); 
    } 

    fMaximumFont = midPoint.x; 

    font = gc.getFont().deriveFont (fMaximumFont); 

    return font; 
} 


private float getWidthInPixelsOfString (String str, float fontSize, Graphics gc) 
{ 
    Font font = gc.getFont().deriveFont (fontSize); 

    return getWidthInPixelsOfString (str, font, gc); 
} 

private float getWidthInPixelsOfString (String str, Font font, Graphics gc) 
{ 
    FontMetrics fm = gc.getFontMetrics (font); 
    int nWidthInPixelsOfCurrentFont = fm.stringWidth (str); 

    return (float) nWidthInPixelsOfCurrentFont; 
} 


private float getHeightInPixelsOfString (String string, float fontSize, Graphics gc) 
{ 
    Font font = gc.getFont().deriveFont (fontSize); 

    return getHeightInPixelsOfString (string, font, gc); 
} 

private float getHeightInPixelsOfString (String string, Font font, Graphics gc) 
{ 
    FontMetrics metrics = gc.getFontMetrics (font); 
    int nHeightInPixelsOfCurrentFont = (int) metrics.getStringBounds (string, gc).getHeight() - metrics.getDescent() - metrics.getLeading(); 

    return (float) nHeightInPixelsOfCurrentFont * .75f; 
}