为什么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'之间的空格不同于第二个'as'之间的空格(1个像素对2个像素)。有没有人知道可能导致这种情况的原因,或者我如何防止它发生?当我用不同的字体绘制时,间距有很多类似的怪异,但我认为它们都是同一问题的结果。
提前感谢您提出的任何想法。
解决方案
我猜这是因为你正在使用 Graphics.DrawString()
而不是 TextRenderer.DrawText()
。前者使用GDI +绘制文本,这有点蹩脚和过时。后者使用更现代的GDI(在文本渲染方面)。我相信这是前一个答案所指出的差异(WinForms vs. Windows)。
您也可以尝试使用StringFormat重载.aspx“rel =”nofollow noreferrer“> StringFormat.GenericTypographic
对象并指定TextRenderer
。然而,这实际上是一个关于这个问题的黑客攻击。如果您使用的是.NET 2.0或更高版本,那么您应该使用Graphics
类而不是蹩脚的Graphics.MeasureString()
类来满足所有文本呈现需求。 <=>和<=>严格存在,以便与.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);
......和家人。
可能不是你想听到的,但确实如此。