2009-05-18 8 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

答えて

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

+0

pFontとよく遭遇しました - このコードを別の方法で掬い取った後の最後の2分でそれを投げました。 これは魅力的です!私は完全に私は正しいサイズ(フォントサイズが直線的に成長するかどうかはわからない)を得るだろうと確信していないが、それ以外の場合は、最初の驚くべき推測を行います。 –

+0

ええ、私はそれがそうでないかもしれないという事実について考えました。私は、それが境界ボックス内にない矩形のサイズであることを望むなら、これはうまくいくと思いました。さもなければ、あなたのテストはそれが十分であることを示すでしょう、そして、あなたはそれを修正するために短い反復ループを追加することができます。 –

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

より良い結果を得るには、すべての幅変数をintではなくfloatに変更してください。

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; 
} 
関連する問題