据我所知,当您使用TextRenderer.MeasureText
查找字符的宽度(以我为例,固定宽度CourierNew
字符)时,如果字体大小为小数,我会得到奇怪的结果组件,例如11.3,而不是11.0或12.0。
例如
Dim font As Font = New Font("Courier New", emSize:=11.3)
Dim width As Double = TextRenderer.MeasureText(New String("0"c, 1000), font).Width / 1000
(我是将一个长字符串的平均长度用于填充。)
结果
emSize = 11.0 -> width = 9.008
emSize = 12.0 -> width = 10.008
emSize = 11.3 -> width = 10.008
emSize = 11.7 -> width = 10.008
我做错什么了吗?或者这是预期的行为?
答案 0 :(得分:2)
与TextRenderer.MeasureText()
返回的值有关的唯一事情是,知道由TextRenderer.DrawText()
渲染文本时的文本大小。因此,问题实际上是:MeasureText()
返回的大小是否与调用DrawText()
方法时发生的大小匹配?实际上,他们确实这样做:
上面是一个简单程序(下面的代码)的输出,该程序以四种不同的字体,以您要问的四种不同的字体大小呈现一个十位数的示例字符串。前两个集合使用TextRenderer.DrawText()
渲染,而后两个集合使用Graphics.DrawString()
渲染。
请注意,在使用TextRenderer
时,四种尺寸中的三种会精确地呈现 。因此,当然,当您测量文本时,所测量的宽度也将完全相同。
对于所使用的两种渲染方法中的每一种,实际上都会进行两次渲染,一次是使用Graphics
对象的默认设置,然后是将Graphics.TextRenderingHint
设置为AntiAlias
。有趣的是,至少在我的计算机上,设置AntiAlias
会使TextRenderer
的输出看起来更好,而使用Graphics.DrawString()
的方法会使它看起来更糟(实际上,设置为TextRenderer
的默认值时,它看起来很像SystemDefault
的输出。
不过,更重要的是,请注意,尽管TextRenderer
不能按比例缩放字体大小,但是Graphics.DrawString()
可以缩放。这两种渲染方法根本不同。如果要使用小数字体大小,则需要使用支持该大小的渲染方法。 TextRenderer
不是。
代码示例:
在Visual Studio中全新的Windows窗体项目中,可以将这些成员添加到Form1
类中,以产生上面的输出:
private readonly IReadOnlyList<float> _emSizes = new[] { 11.0f, 11.3f, 11.7f, 12.0f };
private const string _text = "0123456789";
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int y = _DrawTextExamples(e.Graphics, _text, 0, _emSizes) + 10;
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
y = _DrawTextExamples(e.Graphics, _text, y, _emSizes) + 10;
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
y = _DrawTextExamplesWithDrawString(e.Graphics, _text, y, _emSizes) + 10;
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
y = _DrawTextExamplesWithDrawString(e.Graphics, _text, y, _emSizes) + 10;
}
private int _DrawTextExamples(Graphics g, string text, int y, IReadOnlyList<float> emSizes)
{
Point pt = new Point(0, y);
foreach (float emSize in emSizes)
{
using (Font font = new Font("Courier New", emSize))
{
Size size = TextRenderer.MeasureText(g, text, font);
TextRenderer.DrawText(g, text, font, pt, Color.Black);
pt.X += size.Width + 20;
TextRenderer.DrawText(g, $"emSize: {emSize}, width: {size.Width}", font, pt, Color.Black);
pt = new Point(0, pt.Y + size.Height);
}
}
return pt.Y;
}
private int _DrawTextExamplesWithDrawString(Graphics g, string text, int y, IReadOnlyList<float> emSizes)
{
PointF pt = new Point(0, y);
foreach (float emSize in emSizes)
{
using (Font font = new Font("Courier New", emSize))
{
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, Brushes.Black, pt);
pt.X += size.Width + 20;
g.DrawString($"emSize: {emSize}, width: {size.Width}", font, Brushes.Black, pt);
pt = new PointF(0, pt.Y + size.Height);
}
}
return (int)pt.Y + 1;
}