.NET 有两种绘制文本的方式:
graphics.MeasureString
和 graphics.DrawString
TextRenderer.MeasureText
和 TextRenderer.DrawText
在 .NET 1.1 中,所有文本渲染都使用了 GDI+。但是存在一些问题:
- GDI+ 的无状态特性会导致性能问题,每次调用后设备上下文都会被设置并恢复原始状态。
- 国际化文本的字形引擎已经多次更新,包括 Windows/Uniscribe 和 Avalon(Windows Presentation Foundation),但尚未更新 GDI+,这导致新语言的国际化呈现支持的质量不同。
因此,他们知道他们想要改变 .NET 框架,停止使用 GDI+ 的文本渲染系统,而使用 GDI。起初,他们希望可以简单地更改:
graphics.DrawString
在编写与Windows相关的应用程序时,我们需要使用旧的DrawText
API而不是GDI+。但他们无法使文本换行和间距与GDI+完全匹配。
因此,他们被迫保留在Windows Forms 2.0中,我们添加了对绘制GDI文本的支持。起初,我们计划通过调整DrawText API来使其完全匹配GDI+的DrawString API。我认为我们已经非常接近了,但是在单词换行和字符间距方面存在根本性差异,作为两个API的普通使用者,Windows Forms无法解决这些问题。
因此,现在我们面临一个问题:我们希望将所有人都切换到新的TextRenderer API,以便文本看起来更好、本地化更好、与操作系统中其他对话框更一致... ...但我们不想破坏那些依赖GDI+测量字符串进行文本对齐计算的人。
graphics.DrawString
以调用GDI+(兼容性原因;那些调用graphics.DrawString
的人会突然发现他们的文本换行方式与以前不同)。来自MSDN:UseCompatibleTextRendering
属性设置为true以针对特定控件进行设置。要为应用程序中的所有受支持控件设置UseCompatibleTextRendering
为true,请调用Application.SetCompatibleTextRenderingDefault方法并将参数设置为true。TextRenderer
类来包装GDI文本渲染。它有两个方法:TextRenderer.MeasureText
TextRenderer.DrawText
然后有一个问题是如何处理所有现有的.NET控件,例如:
Label
Button
TextBox
他们想要将它们切换到使用TextRenderer
(即GDI),但他们必须小心。可能会有人依赖于他们的控件在.NET 1.1中的绘制方式。因此,“兼容文本渲染”应运而生。
默认情况下,应用程序中的控件的行为与.NET 1.1中的相同(它们是“兼容的”)。
您可以通过调用以下方法来关闭兼容模式:
Application.SetCompatibleTextRenderingDefault(false);
SetCompatibleTextRenderingDefault(true) SetCompatibleTextRenderingDefault(false)
======================================= ========================================
default opt-in
bad good
the one we don't want to use the one we want to use
uses GDI+ for text rendering uses GDI for text rendering
graphics.MeasureString TextRenderer.MeasureText
graphics.DrawString TextRenderer.DrawText
Behaves same as 1.1 Behaves *similar* to 1.1
Looks better
Localizes better
Faster
值得注意的是,GDI+的TextRenderingHint
与用于GDI字体绘制的相应LOGFONT
Quality之间的映射也很有用:
TextRenderingHint mapped by TextRenderer to LOGFONT quality
======================== =========================================================
ClearTypeGridFit CLEARTYPE_QUALITY (5) (Windows XP: CLEARTYPE_NATURAL (6))
AntiAliasGridFit ANTIALIASED_QUALITY (4)
AntiAlias ANTIALIASED_QUALITY (4)
SingleBitPerPixelGridFit PROOF_QUALITY (2)
SingleBitPerPixel DRAFT_QUALITY (1)
else (e.g.SystemDefault) DEFAULT_QUALITY (0)
这里是GDI+(graphics.DrawString)和GDI(TextRenderer.DrawText)文本渲染的一些比较:
GDI+:TextRenderingHintClearTypeGridFit
,GDI:CLEARTYPE_QUALITY
:
GDI+:文本呈现提示抗锯齿,GDI:抗锯齿质量。
GDI+: TextRenderingHintAntiAliasGridFit
, GDI: 不支持,使用ANTIALIASED_QUALITY:
GDI+:TextRenderingHintSingleBitPerPixelGridFit
,GDI:PROOF_QUALITY
:
DRAFT_QUALITY
和 PROOF_QUALITY
以及 CLEARTYPE_QUALITY
是完全相同的。另见
DRAFT_QUALITY
和PROOF_QUALITY
相同的原因是您选择的字体。 DRAFT_QUALITY
只是意味着字体映射器在选择字体时应优先考虑指定的逻辑属性匹配而不是字符质量; PROOF_QUALITY
则反转了这种关系。如果字体映射器不必做出选择,则两个值将生成相同的输出。至于为什么这两者都与CLEARTYPE_QUALITY
相同,那是因为您的系统启用了ClearType(并且字体支持),因此DRAFT_QUALITY
和PROOF_QUALITY
都使用它。 - Cody Gray我的个人经验(我只知道这两个区别):
DrawString支持Alpha通道,抗锯齿
TextRenderer支持Uniscribe
我只是随便加入一些测试代码:
class Form1: Form
{
private string str = "hello world hello world hello world";
private int x = 32, yLabel = 0, yDraw = 64, yRenderer = 32;
public Form1()
{
Font = new Font("Times", 16);
Label label = new Label();
label.BorderStyle = BorderStyle.FixedSingle;
label.AutoSize = true;
label.Text = str;
label.Location = new Point(x, yLabel);
Controls.Add(label);
}
protected override void OnPaint(PaintEventArgs e)
{
SizeF a;
// TextRenderer
a = TextRenderer.MeasureText(str, Font);
TextRenderer.DrawText(e.Graphics, str, Font, new Point(x, yRenderer), Color.Pink);
e.Graphics.DrawRectangle(new Pen(Color.Blue), x, yRenderer, a.Width, a.Height);
// DrawString
e.Graphics.DrawString(str, Font, new SolidBrush(Color.Red), x, yDraw);
a = e.Graphics.MeasureString(str, Font);
e.Graphics.DrawRectangle(new Pen(Color.Lime), x, yDraw, a.Width, a.Height);
base.OnPaint(e);
}
}