如何精确测量弦的宽度?

时间:2012-07-29 10:48:39

标签: c# winforms gdi+

首先,回答问题How to measure width of character precisely?对这种情况并没有什么帮助,所以这不是的重复。

我有一个字符串。我使用graphics.DrawString进行绘制,但是当我需要在其后面添加另一个时,我需要知道前一个字符串的精确宽度。

为此我使用graphics.MeasureString:

StringFormat format = new StringFormat(StringFormat.GenericTypographic);
format.Alignment = StringAlignment.Center;
format.Trimming = StringTrimming.None;
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

我尝试了许多其他功能,就像TextRendered.MeasureText一样,但是所有这些功能都失败了,所有可能的参数组合。

上面提到的MeasureString组合最接近我的需要(它在大多数情况下都适用,特殊字符除外),但是使用像#破坏它这样的字符。宽度要么更短,要么更长。

有没有办法获得DrawString函数生成的文本的精确大小? DrawString如何计算绘图区域的大小?它必须是一些其他功能,因为它的大小总是不同的。

整个应用程序的源代码在这里https://gitorious.org/pidgeon/pidgeon-main/(我使用它的文件是https://gitorious.org/pidgeon/pidgeon-main/blobs/master/scrollback/SBABox.cs

4 个答案:

答案 0 :(得分:8)

你只需要消除额外的宽度。您可以使用string format

执行此操作
GdipStringFormatGetGenericTypographic()

你也可以使用:

float doubleWidth = g.MeasureString(text+text,...).Width;
float singleWidth = g.MeasureString(text).Width;
float textWidth = doubleWidth-singleWidth;

这将允许您使用其他语言,如日语

On codeproject,Pierre Anaud的解决方案是使用MeasureCharacterRanges,它返回一个与指定字符串的边界框完全匹配的区域:

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);
    var 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);
}

答案 1 :(得分:4)

我在这里参加派对有点晚了,但是我试图做类似的事情,偶然发现了这个问题。你可能已经从the documentation for the Graphics.MeasureString method on MSDN看到了以下评论:

  

MeasureString方法设计用于单个字符串,并在字符串之前和之后包含少量额外空格以允许悬垂字形。此外,DrawString方法调整字形点以优化显示质量,并且可能显示比MeasureString报告的字符串更窄的字符串。要获取适合布局中相邻字符串的度量标准(例如,在实现格式化文本时),请使用MeasureCharacterRanges方法或采用MeasureStringStringFormat方法之一,并传递{{ 3}}。另外,请确保GenericTypographicTextRenderingHintGraphics

您似乎正在尝试遵循此建议,因为您使用StringFormat.GenericTypographic作为自定义StringFormat对象的起点。但是,行

format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

有效地否定了您从StringFormat.GenericTypographic开始的事实,因为它清除了之前设置的任何标志。您可能要做的是设置StringFormatFlags.MeasureTrailingSpaces标志,同时保留其他标志,如下所示:

format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;

答案 2 :(得分:1)

尝试使用此方法:

GDI+ (graphics.MeasureString and graphics.DrawString) >> System.Drawing.Graphics
GDI (TextRenderer.MeasureText and TextRenderer.DrawText)

它也可以帮助您:

  

编写自定义度量方法:

     
      
  • 在特殊字符上拆分条目字符串
  •   
  • 使用上述.net方法
  •   
  • 计算特殊字符的宽度和总和......
  •   

Read Ian Boyd answer

答案 3 :(得分:0)

使用Graphics.MeasureCharacterRanges返回包含所有单个字母的所有矩形的方法,其位置在此处给出:Measure character positions when drawing long strings in C#

我从那篇文章中使用了MeasureCharactersInWord和MeasureCharacters方法,然后为了找到确切的宽度而没有在字符串的每一侧添加空格,我使用了以下代码:

var w = 0F;
var rects = MeasureCharacters(Graphics.FromHwnd(IntPtr.Zero), font, text);
if (rects.Count>0)
{
    if (rects.Count == 1)
    {
        w = rects.First().Width;
    }
    else
    {
        var r0 = rects.First();
        var rN = rects.Last();
        w = rN.X - r0.X + rN.Width;
    }
}

请注意,矩形的高度是字体的高度,而不是字符本身的高度。如果您需要身高,请检查以下信息:Determining exact glyph height in specified font

最后一点:我使用MeasureCharacterRanges的原因是因为我尝试的所有其他方法都未能给我一个边界框,文本的左右两边都没有空格。这篇The wonders of text rendering and GDI帖子提供了一种方法来获取字符串宽度并使用TextRenderer删除此空间,因此整个过程可以用大约两行代码完成。我还没有检查结果。