.NETで文字列のサイズを計測するのにはGraphics.MeasureString()
を使いますよね?文字列のサイズが知りたいのに、1度適当なサイズのBitmap
をGraphics.FromImage()
してあげないとMeasureString()
が使えないという話は置いておいて、ただ単純にMeasureString()
をしただけじゃ、文字列のサイズを正確に計測することはできません。どうしても、左揃えなら右側に、右揃えなら左側に謎の空白ができてしまいます。
(正確には、はみ出しを抑制するための空白です。ちゃんと意味があります。)
これを回避するために、MeasureString()
の第4引数にStringFormat.GenericTypographic
を指定してやる必要があります。ですが、第4引数を指定するには、その前にある第3引数、文字列の最大の長さ、を指定する必要があります。
ここで思います、「今から文字列の長さを知りたいのに、なぜ最大の長さを指定する必要があるのだろう」、と。
確かに、文字を詰めて表示するために上限を決めたり、すでにウィンドウサイズが決まっていたりするのであれば、上限の横幅というのを指定しても良いですが、ほとんどの場合、純粋に文字列を描画したときの長さが知りたいはずですし、ウィンドウサイズが一定のアプリであるとも限りません。
ですから、何らかの値を入れてやる必要があります。適当な定数でも、int.MaxValue
でも問題はなさそうですが、あまりスマートではありませんよね。
そこで、一番初めに紹介した、「謎の空白を生み出してしまう計測法」を用います。これは、純粋な文字列のサイズではないですが、「正しい文字列のサイズ」よりもちょっと大きいサイズを取得できることは100%、間違いないので、近似値と言えるこの値を使います。
// Fontという名のフィールドがすでにあるとする
// 適当なBitmapを生成
var bitmap = new Bitmap(16, 16);
// 適当なGraphicsを生成
var graphics = Graphics.FromImage(bitmap);
// 謎の空白付きの文字列のサイズを計測。
var graphicsSize = graphics.MeasureString("成就した恋ほど語るに値しないものはない。", Font);
// ちゃんとした文字列のサイズを計測。
var trueGraphicsSize = graphics.MeasureString("成就した恋ほど語るに値しないものはない。", Font, (int)graphicsSize.Width, StringFormat.GenericTypographic);
bitmap.Dispose();
graphics.Dispose();
適当な定数を使うよりも、こっちの方がスマート……な気がします(計算量は増えるけど)。
謎の空白を生み出してしまうあのメソッドが、なんとここに来て役に立ってしまいました。Microsoftのおじさんもこう使われることを想定していたのでしょうか。
ともあれ、.NETで正確に文字列のサイズを計測するのには2度手間が掛かります。たぶん。