10

我正在尝试使用 OpenXML 规范中的官方公式计算 Excel 列的像素宽度,如本文所述。但是,为了应用这个公式,我需要知道Normal字体的最大数字宽度,即最宽数字的像素宽度。OpenXML 规范给出了这个例子作为说明:

以 Calibri 字体为例,11 点字体大小的最大数字宽度为 7 像素(在 96 dpi 时)。

我已经通过目视检查 Calibri 11 点数字来检查这是否正确,它确实是 7 像素宽。因此,我正在尝试创建一种方法,该方法将返回任何字体/大小的最大数字宽度。

我遵循了在这个问题中提出的建议,但它没有产生我期望的结果。

这是我的测试代码:

var font = new Font("Calibri", 11.0f, FontStyle.Regular);

for (var i = 0; i < 10; i++)
{
    Debug.WriteLine(TextRenderer.MeasureText(i.ToString(), font));
}

这报告所有数字的宽度都是 15。

请问有什么建议吗?

谢谢,蒂姆

4

5 回答 5

5

TextRenderer 并不总是像您期望的那样准确:

来自 MSDN:http: //msdn.microsoft.com/en-us/library/8wafk2kt.aspx

例如,TextRenderer 的默认行为是向绘制文本的边界矩形添加填充以适应悬垂的字形

你有Graphics对象还是控制对象?如果您使用这些,您可以按照您期望的方式获得准确的结果。

看看http://msdn.microsoft.com/en-us/library/6xe5hazb(VS.80).aspx

于 2009-12-02T14:11:20.540 回答
5

首先让我说我要展示的代码看起来像一个可怕的黑客,我没有把它作为一个解决方案来展示。相反,我希望它能更多地揭示 MeasureText 的行为,这可能会引导您找到最终解决方案。

我对你的代码做了一点改动。我正在测量两个下划线字符的长度。然后,在 for 循环的主体中,我正在测量所需的字符,两边都有下划线,并单独减去两个下划线字符的长度。对于测试场景,我得到的结果为 7。这样做的主要目的是确定 MeasureText 是在逐个字符的基础上进行填充,还是在字符串的开头/结尾进行填充。似乎是后者。也许这与您收到的其他一些输入相结合,将引导您找到更优雅的解决方案。

var font = new Font("Calibri", 11.0f, FontStyle.Regular);
int underscoreWidth = TextRenderer.MeasureText("__", font).Width; 
for (var i = 0; i < 10; i++)
   {
      int charWidth = TextRenderer.MeasureText(String.Concat("_", i.ToString(), "_"), font).Width - underscoreWidth;
      Debug.WriteLine(charWidth);
   }
于 2009-12-02T16:26:24.827 回答
5

MeasureText 添加了填充,虽然它与字体大小大致呈线性关系,但数量相当不可预测。诀窍是减去两个测量值以消除填充。这段代码生成了非常开心的数字:

        float size = 5;
        for (int ix = 0; ix < 10; ++ix) {
            var font = new Font("Calibri", size, FontStyle.Regular);
            string txt = new string('0', 100);
            SizeF sz1 = TextRenderer.MeasureText("00", font) - TextRenderer.MeasureText("0", font);
            Console.WriteLine("{0} {1:N3}", size, sz1.Width);
            size += 2;
        }

输出:

5 4.000
7 5.000
9 6.000
11 7.000
13 9.000
15 10.000
17 12.000
19 13.000
21 14.000
23 16.000

这将为您提供您正在寻找的 7 个像素。请注意,您必须适应 TrueType 提示,它可以调整数字的形状,使其主干落在像素边界上。添加至少一个像素。

于 2009-12-02T18:14:42.810 回答
3

测量文本宽度可能是一个噩梦。我不知道他们为什么让它如此混乱..

这是我测量文本长度的最准确方法:

    protected int _MeasureDisplayStringWidth ( Graphics graphics, string text, Font font )
    {
        if ( text == "" )
            return 0;

        StringFormat format = new StringFormat ( StringFormat.GenericDefault );
        RectangleF rect = new RectangleF ( 0, 0, 1000, 1000 );
        CharacterRange[] ranges = { new CharacterRange ( 0, text.Length ) };
        Region[] regions = new Region[1];

        format.SetMeasurableCharacterRanges ( ranges );
        format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

        regions = graphics.MeasureCharacterRanges ( text, font, rect, format );
        rect = regions[0].GetBounds ( graphics );

        return (int)( rect.Right );
    }
于 2009-12-02T14:17:25.067 回答
1

我不是 100% 确定它是你真正需要的。

但您可能想看看这个 Microsoft 页面:

于 2009-12-02T14:07:37.210 回答