Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is DrawString exhibiting unexpected behavior in C# Winforms?

I have subclassed a control in C# WinForms, and am custom drawing text in my OnPaint() handler. The font is set to Courier New using the following code in my form:

FontFamily family = new FontFamily("Courier New");
this.myControl.Font = new Font(family, 10);

In the control itself, the string is stored in realText, and I use the following code to draw it to the screen:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    e.Graphics.DrawString(realText, Font, new SolidBrush(ForeColor), ClientRectangle);
}

The result for some random example text looks as follows: http://img219.imageshack.us/img219/1778/courier.png

If you zoom in, you can see for example, that the space between the first 'as' is different than the space between the second 'as' (1 pixels versus 2 pixels). Does anybody have any idea what might be causing this, or how I can prevent it from happening? There is a lot more similar weirdness in spacing as I draw with different fonts, but I assume they're all results of the same problem.

Thanks in advance for any ideas you may have.

like image 910
Ko9 Avatar asked May 07 '09 23:05

Ko9


1 Answers

I'm going to guess that it's because you're using Graphics.DrawString() instead of TextRenderer.DrawText(). The former paints text using GDI+ which is sort of crappy and outdated. The latter uses GDI which is more modern (in terms of text rendering). I believe this is the difference noted by the previous answer (WinForms vs. Windows).

You might also try the overload of Graphics.DrawString() that takes a StringFormat object and specify StringFormat.GenericTypographic. However, this is really a bit of a hack around the problem. If you're using .NET 2.0 or later, you should be using the TextRenderer class instead of the crappy Graphics class for all of your text rendering needs. Graphics.MeasureString() and Graphics.DrawString() exist strictly for backwards compatibility with .NET 1.0 and 1.1.

edit: Oh yeah, and your code leaks a GDI object on every paint cycle. Brush objects are managed wrappers around unmanaged resources thus they must be explicitly disposed.

like image 60
Mike Post Avatar answered Sep 18 '22 17:09

Mike Post