2009-06-28 2 views
20

私はそれが単純な概念だと知っていますが、私はフォントメトリクスに苦労しています。水平にセンタリングするのは難しくありませんが、垂直には少し難しいようです。Javaで文字列を縦に中央にどのように描画しますか?

私はFontMetrics getAscent、getLeading、getXXXXメソッドをさまざまな組み合わせで使用しようとしましたが、テキストを試しても何画素かは常にオフになっています。正確にセンタリングされるようにテキストの正確な高さを測定する方法はありますか?

答えて

48

注意、あなたは検討する必要性を行う垂直センタリングの意味を正確に表します。

フォントは、テキストの下端に沿って実行されるベースライン上にレンダリングされます。垂直方向のスペースは、次のように割り当てられます。

--- 
^ 
| leading 
| 
-- 
^    Y  Y 
|    Y Y 
|    Y Y 
| ascent   Y  y  y 
|     Y  y y 
|     Y  y y 
-- baseline ______Y________y_________ 
|       y     
v descent    yy 
-- 

先頭へ移動すると、行間のフォントの推奨スペースになります。 2つの点の間を垂直にセンタリングするために、リーディングを無視する必要があります(一般的なタイポグラフィでは、印刷板のライン間に挿入されたリード間隔です)。

だからテキストアセンダとディセンダをセンタリングするため、あなたは最終的に「+アセント」がなければ

baseline=(top+((bottom+1-top)/2) - ((ascent + descent)/2) + ascent; 

をしたい、あなたはフォントのトップのための位置を持っています。したがって、上昇を追加するのは上からベースラインに向かいます。

また、フォントの高さには先頭が含まれている必要がありますが、一部のフォントには含まれていません。また、丸めの違いにより、フォントの高さが正確に等しくないことがあります。

+0

ああ、それは完璧な説明です。どうもありがとうございました! (先導の説明のためにも、それを知らなかった) – brimborium

+1

あなたは1を追加している理由は何ですか? – Max

+1

@Alex:(下+ 1-top)は高さなので、ボトムとトップが同じであれば、高さはゼロではなく1です。正味の効果は、中間点がn.5ピクセルである場合に下に丸めることである。 –

11

レシピが見つかりましたhere

決定的な方法はgetStringBounds()getAscent()

// Find the size of string s in font f in the current Graphics context g. 
FontMetrics fm = g.getFontMetrics(f); 
java.awt.geom.Rectangle2D rect = fm.getStringBounds(s, g); 

int textHeight = (int)(rect.getHeight()); 
int textWidth = (int)(rect.getWidth()); 
int panelHeight= this.getHeight(); 
int panelWidth = this.getWidth(); 

// Center text horizontally and vertically 
int x = (panelWidth - textWidth)/2; 
int y = (panelHeight - textHeight)/2 + fm.getAscent(); 

g.drawString(s, x, y); // Draw the string. 

(注:ページ上で述べたように、コードの上にMIT Licenseで覆われている)ように見える

+2

ええと...私はこのコンセプトに精通しています...でも間違っています。 fm.getAscent()メソッドが問題です。フォントの実際のピクセルの上昇を報告せず、上部よりも底部に近いテキストを出力します。 –

2

これは役に立ちますが、drawString(s, x, y)のベースラインをyに設定します。

私はいくつかの垂直センタリングを行っていて、ドキュメントに記載されている動作に気づくまで、テキストを正しく表示することができませんでした。私はフォントの底がyにあると仮定していました。

私にとっては、修正はfm.getDescent()をy座標から差し引くことでした。

1

もう1つのオプションは、TextLayout classgetBoundsメソッドです。

Font f; 
// code to create f 
String TITLE = "Text to center in a panel."; 
FontRenderContext context = g2.getFontRenderContext(); 

TextLayout txt = new TextLayout(TITLE, f, context); 
Rectangle2D bounds = txt.getBounds(); 
int xString = (int) ((getWidth() - bounds.getWidth())/2.0); 
int yString = (int) ((getHeight() + bounds.getHeight())/2.0); 
// g2 is the graphics object 
g2.setFont(f); 
g2.drawString(TITLE, xString, yString); 
関連する問題