DrawStringがC#Winformsで予期しない動作をするのはなぜですか?
-
10-07-2019 - |
質問
C#WinFormsでコントロールをサブクラス化し、 OnPaint()
ハンドラーのカスタム描画テキストです。
フォントは、フォームに次のコードを使用してCourier Newに設定されます。
FontFamily family = new FontFamily("Courier New");
this.myControl.Font = new Font(family, 10);
コントロール自体では、文字列は realText
に格納され、次のコードを使用して画面に描画します。
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawString(realText, Font, new SolidBrush(ForeColor), ClientRectangle);
}
ランダムなサンプルテキストの結果は次のようになります。 http://img219.imageshack.us/img219/1778/courier.png
ズームインすると、たとえば、最初の 'as'の間隔が2番目の 'as'の間隔と異なることがわかります(1ピクセル対2ピクセル)。誰がこれを引き起こしているのか、またはそれを防ぐ方法を知っていますか?異なるフォントを使用して描画すると、間隔にもっと似た奇妙さがありますが、それらはすべて同じ問題の結果だと思います。
ご意見をお寄せいただきありがとうございます。
解決
TextRenderer.DrawText()
。前者はGDI +を使用してテキストをペイントしますが、これはくだらないものであり、時代遅れです。後者は(テキストレンダリングに関して)より最新のGDIを使用します。これは前の回答(WinFormsとWindows)で指摘された違いだと思います。
StringFormat
オブジェクトを指定し、 StringFormat.GenericTypographic
を指定します。ただし、これは実際には問題のちょっとしたハックです。 .NET 2.0以降を使用している場合、すべてのテキストレンダリングのニーズに対して、くだらない Graphics
クラスではなく、 TextRenderer
クラスを使用する必要があります。 Graphics.MeasureString()
および Graphics.DrawString()
は、.NET 1.0および1.1との後方互換性のためにのみ存在します。
編集:ああ、そうです、そしてあなたのコードはペイントサイクルごとにGDIオブジェクトをリークします。ブラシオブジェクトは、アンマネージリソースのマネージラッパーであるため、明示的に破棄する必要があります。
他のヒント
正直に言う必要がありますが、これは私には前に決して起こりませんでした。ただし、SmoothingModeをアンチエイリアスに設定してみてください:
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
別のことは別として、使用中のDoubleBufferがtrueに設定されていることを確認してください。また、OnPaintの呼び出しごとに新しいSolidBrushを作成しないようにしてください。.
WinFormsを使用してテキストをサブクラス化されたコントロールにペイントする私の経験では、使用するテキストレンダリングエンジン(GDI +?)はWindows独自のフォントエンジンほど優れておらず、うまく機能していても確かに異なる結果が得られます。
私はVisual Studioアドインの作成者です( http://entrian.com/source-search )Visual Studio内でコントロールをペイントする必要があり、フォントをVisual Studioの標準コントロール(リストビュー、ツリービューなど)と同じにするには、WinFormsをバイパスし、Win32を使用してテキストをペイントする必要があります。 API:
[DllImport("gdi32.dll")]
public static extern bool ExtTextOut(IntPtr hdc, int X, int Y,
uint fuOptions, [In] ref RECT lprc, string lpString, uint cbCount,
[In] int[] lpDx);
...およびファミリ。
おそらくあなたが聞きたかったことではありませんが、そこにあります。