这(在某种程度上)是经典。
执行的相当精确的测量之间存在差异测量字符范围和实际执行的字符串绘制Graphics.DrawString
.
The RectagleF
由返回Region.GetBounds()
按原样考虑文本的大小。
Graphics.DrawString
另一方面,在计算给定边界内的文本配置时执行某种网格拟合。
我不会在这里解释它,这是一个相当广泛的问题,但我已经写过一些相关内容:
在位图上绘制长字符串会导致绘图问题.
如果你有兴趣,你可以找到一些详细信息Graphics
在此上下文中的对象行为。
总而言之,文本测量正确,但调整Graphics.DrawString
执行,导致文本不完全适合测量的边界:绘制的文本稍微溢出.
你可以纠正这个problem使用几个StringFormat
flags:
Add [StringFormat].Trimming = StringTrimming.None
应用此设置后,您可以立即看到问题所在:最后一个字符(或几个字符)被换行到新行,弄乱了绘图。
要更正它,请添加StringFormatFlags.NoWrap to StringFormatFlags.NoClip
显然,这将解决问题。显然是因为现在整个字符串都绘制在一条线上。
我向你建议另一种方法,使用文本渲染器.DrawText渲染字符串。
注意TextRenderer
实际上是使用的类WinForms
控件(好吧,不是全部)将文本渲染到屏幕上。
这是使用以下方法的结果:
示例代码,使用原始代码并进行一些修改:
private void panel1_Paint(object sender, PaintEventArgs e)
{
Control control = sender as Control;
const string txt = "C# Helper! Draw some text with each word in a random color.";
TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter |
TextFormatFlags.NoPadding | TextFormatFlags.NoClipping;
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
MatchCollection mc = Regex.Matches(txt, @"[^\s]+");
CharacterRange[] ranges = mc.Cast<Match>().Select(m => new CharacterRange(m.Index, m.Length)).ToArray();
format.SetMeasurableCharacterRanges(ranges);
using (Font font = new Font("Times New Roman", 40, FontStyle.Regular, GraphicsUnit.Point))
{
Region[] regions = e.Graphics.MeasureCharacterRanges(txt, font, control.ClientRectangle, format);
for (int i = 0; i < ranges.Length; i++)
{
Rectangle WordBounds = Rectangle.Round(regions[i].GetBounds(e.Graphics));
string word = txt.Substring(ranges[i].First, ranges[i].Length);
TextRenderer.DrawText(e.Graphics, word, font, WordBounds, RandomColor(), flags);
}
}
}
}
private Random rand = new Random();
private Color[] colors =
{
Color.Red,
Color.Green,
Color.Blue,
Color.Lime,
Color.Orange,
Color.Fuchsia,
};
private Color RandomColor()
{
return colors[rand.Next(0, colors.Length)];
}