65.9K
CodeProject 正在变化。 阅读更多。
Home

绕过 Graphics.MeasureString 的限制

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (42投票s)

2002年4月15日

LGPL3

1分钟阅读

viewsIcon

439652

这段示例代码计算字符串的宽度,就像使用 Graphics.DrawString 绘制时一样。

Sample Image - measurestring.gif

引言

Graphics.MeasureString 可以用来计算文本字符串的高度和宽度。然而,通常情况下,返回的尺寸与调用 Graphics.DrawString 时实际在屏幕上绘制的大小不匹配。 上方的红色框显示了 Graphics.MeasureString 返回的尺寸,大约宽了一个“em”...

计算结果与屏幕上实际绘制结果之间的差异与 GDI+ 在使用字体平滑和抗锯齿时计算宽度的方式有关。 这里有详细信息。 一个已知的解决方法是让 GDI+ 以抗锯齿模式显示字符串,在这种情况下,测量的宽度将与显示的結果匹配。 如果您想绘制标准字符串(例如,以匹配 GUI 外观),您就无能为力了。

首先,一个简单的解决方案

我在这里提供的代码可以插入到任何需要计算字符串的实际宽度(如上方黄色背景所示)的类中。 我用来计算实际字符串宽度的技巧是让 GDI+ 将字符串绘制到位图中,然后通过读取像素来找到最后一个字符的位置。 一些优化确保这能尽快完成(小位图,少量像素)。

static public int MeasureDisplayStringWidth(Graphics graphics, string text,
                                            Font font)
{
    const int width = 32;

    System.Drawing.Bitmap   bitmap = new System.Drawing.Bitmap (width, 1, 
graphics); System.Drawing.SizeF size = graphics.MeasureString (text, font); System.Drawing.Graphics anagra = System.Drawing.Graphics.FromImage(bitmap); int measured_width = (int) size.Width; if (anagra != null) { anagra.Clear (Color.White); anagra.DrawString (text+"|", font, Brushes.Black, width - measured_width, -font.Height / 2); for (int i = width-1; i >= 0; i--) { measured_width--; if (bitmap.GetPixel (i, 0).R != 255) // found a non-white pixel ? break; } } return measured_width; }

就这样,各位。 此代码可能无法处理从右向左的脚本。

另一种解决方案...

也可以通过使用 MeasureCharacterRanges 来获得准确的字符串几何形状,它返回一个区域,该区域与指定字符串的边界框完全匹配。 这比我之前在 CodeProject 上发布的第一个解决方案更快、更优雅。

static public int MeasureDisplayStringWidth(Graphics graphics, string text,
                                            Font font)
{
    System.Drawing.StringFormat format  = new System.Drawing.StringFormat ();
    System.Drawing.RectangleF   rect    = new System.Drawing.RectangleF(0, 0,
                                                                  1000, 1000);
    System.Drawing.CharacterRange[] ranges  = 
{ new System.Drawing.CharacterRange(0, text.Length) }; System.Drawing.Region[] regions = new System.Drawing.Region[1]; format.SetMeasurableCharacterRanges (ranges); regions = graphics.MeasureCharacterRanges (text, font, rect, format); rect = regions[0].GetBounds (graphics); return (int)(rect.Right + 1.0f); }

后记

这两个函数仅适用于非空字符串。 第二个解决方案会删除尾随空格;第一个解决方案会考虑它们。 选择最适合您需求的那个。

© . All rights reserved.