TextBoxの一行の文字数を設定するには?(等幅フォント使用)

解決


さやか  2009-11-29 20:14:52  No: 146583

こんにちは。
複数行入力できるテキストボックス(あるいはリッチテキストボックス)の一行の全角文字数が固定になるように、
テキストボックスの幅を設定したいと思っています。
自分なりに色々調べたところ、System.Drawing.GraphicsのMeasureStringメソッドを使用すると、
文字数に応じたテキスト領域の幅が得られると思い試しているのですが、うまくいきません。
以下に試したコードを記載します。

'---------------------------------------------------------
Const DISP_TEXT As String = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん"
Dim fnt As New Font("MS ゴシック", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(128, Byte))
Dim g As Graphics = TextBox1.CreateGraphics()
Dim intWidth As Integer = System.Math.Ceiling(g.MeasureString(clsUtil.RepeatString("亜", 20), fnt).Width)

TextBox1.Font = fnt
TextBox1.Text = DISP_TEXT
TextBox1.ClientSize = New Size(intWidth, TextBox1.ClientSize.Height)
'---------------------------------------------------------

実行結果では、21文字目である「な」から次の行に折り返しされることを期待したのですが、
実際は19文字目の「て」から次の行に表示されてしまいます。
(これはTextBox1.ScrollBarがVerticalの場合の結果です。また、TextBox1.ScrollBarがNoneの場合は、
上記の結果とは異なりますが、やはり21文字目からの折り返しは発生しません。)

テキストボックスの代わりにリッチテキストボックスを使用しても結果は同じでしたが、
ラベル(AutoSize=Falseにしたもの)で試してみると、こちらはちゃんと21文字目からの折り返しが発生しています。
そこで、同じフォントのラベルとテキストボックスを上下に並べて配置し、同じテキストをセットしてみると、
どうやら文字送りの幅がラベルとテキストボックスとでは違うようなのです(テキストボックスの方が文字送りの幅が大きい)。
従って、ラベルのテキスト幅はGraphics.MeasureStringでOKだと思うのですが、
テキストボックスの場合のテキスト幅を得るにはどうすればよいでしょうか?
使用しているのはVB 2008です。宜しくお願いします。


Hongliang  2009-11-29 22:34:47  No: 146584

まず、System.Graphics は描画コンポーネントとして GDI+ を使用しています。しかし WinForm の TextBox は Windows のコモンコントロールを使って実装されており、これは GDI を使って画面を操作します。
この違いはテキストの描画にも及んでおり、テキストボックスに表示される文字列の幅と Graphics.MeasureString で計測される文字列の幅には差が存在しています。
GDI を使って文字列を描画などするために、WinForm は TextRenderer クラスを用意してあります。このクラスには MeasureText メソッドも用意されており、これで GDI で描画されるときの文字列の幅を計測できます。
なお、Label は、Application.SetCompatibleTextRenderingDefault メソッド及び Label.UseCompatibleTextRendering プロパティによって文字列を GDI+ で描画するか GDI で描画するか切り替えられるようになっています。
// で、アプリケーションフレームワークを使ったデフォルトでは GDI 使うはずだったと思うんですが……。

それから、ClientSize はどうも ScrollBars がらみが適当なようです。
たとえば ClientSize の Width に 200 を設定したとします。縦スクロールバーの幅が 15 とすると、ClientSize.Width は 200 を報告しますが、実際に設定されている(スクロールバーを除いた)クライアント領域の幅は 185 になります。その後、一旦 ScrollBars.None にしてもう一度 ScrollBars.Vertical にすると ClientSize.Width は 185 を報告するようになります。
// 確認した環境は 日本語版 Windows Vista SP1, .NET Framework 2.0 SP1。
この動作が環境を問わない普遍的なものとすると、ClientSize を設定する際、Width には ScrollBars を確認して Vertical が含まれている場合は SystemInformation.VerticalScrollBarWidth をプログラム側で足しておかなければならないと言うことになります。


さやか  2009-11-30 19:35:47  No: 146585

Hongliang様、ありがとうございました☆
以下のようにして解決しました。

・TextRenderer.MeasureTextで、全角文字の指定文字数のサイズを取得する。
・テキストボックスの幅を、上記で得た値 + SystemInformation.VerticalScrollBarWidthとする。

ありがとうございました♪


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加