Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

I have to be honest, but this never happened to me before. However, try setting the SmoothingMode to Antialiasing:

e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

Another thing aside, make sure the from your using has DoubleBuffer set to true. Also, try not to create a new SolidBrush in every OnPaint call ..

My experience with painting text into subclassed controls using WinForms is that the text rendering engine it uses (GDI+?) is not as good as Windows's own font engine, and certainly gives different results even when it works well.

I'm the author of a Visual Studio addin (http://entrian.com/source-search) that needs to paint controls within Visual Studio, and in order to make the fonts look the same as the standard controls in Visual Studio (listviews, treeviews, etc.) I have to bypass WinForms and paint the text using the 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);

...and family.

Probably not what you wanted to hear, but there it is.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top