阅读背景:

为什么DrawString在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:

我已经在C#WinForms中创建了一个控件,并在我的OnPaint()处理程序中自定义绘制文本。使用我的表单中的以下代码将字体设置为Courier New:

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:

在控件本身,字符串存储在realText中,我使用以下代码将其绘制到屏幕上:

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: https://img219.imageshack.us/img219/1778/courier.png

一些随机示例文本的结果如下所示:https://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.

如果你放大,你可以看到,例如,第一个'as'之间的空间不同于第二个'as'之间的空间(1个像素对2个像素)。有没有人知道可能导致这种情况的原因,或者我如何防止它发生?我用不同的字体画出的间距有很多类似的古怪,但我认为它们都是同一问题的结果。

Thanks in advance for any ideas you may have.

提前感谢您的任何想法。

3 个解决方案

#1


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).

我猜这是因为你使用的是Graphics.DrawString()而不是TextRenderer.DrawText()。前者使用GDI +绘制文本,这有点蹩脚和过时。后者使用更现代的GDI(就文本呈现而言)。我相信这是前一个答案所指出的差异(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.

您也可以尝试使用StringFormat对象并指定StringFormat.GenericTypographic的Graphics.DrawString()重载。然而,这实际上是一个关于这个问题的黑客攻击。如果您使用的是.NET 2.0或更高版本,则应该使用TextRenderer类而不是蹩脚的Graphics类来满足所有文本呈现需求。 Graphics.MeasureString()和Graphics.DrawString()严格存在,以便与.NET 1.0和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.

编辑:哦是的,你的代码在每个绘制周期都会泄漏一个GDI对象。 Brush对象是围绕非托管资源的托管包装器,因此必须明确处理它们。

#2


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

我必须诚实,但这从未发生在我之前。但是,尝试将SmoothingMode设置为抗锯齿:

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 ..

除此之外,请确保您的使用将DoubleBuffer设置为true。另外,尽量不要在每次OnPaint调用中创建新的SolidBrush。

#3


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.

我使用WinForms将文本绘制到子类控件中的经验是它使用的文本呈现引擎(GDI +?)不如Windows自己的字体引擎那么好,并且即使它运行良好也会产生不同的结果。

I'm the author of a Visual Studio addin (https://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:

我是Visual Studio插件(https://entrian.com/source-search)的作者,需要在Visual Studio中绘制控件,并使字体看起来与Visual Studio中的标准控件相同( listviews,treeviews等)我必须绕过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);

...and family.

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

可能不是你想听到的,但它确实存在。


分享到: