我正在尝试使用OpenXML规范中的官方公式计算Excel列的像素宽度,如this post中所述。但是,为了应用此公式,我需要知道 Normal 字体的最大数字宽度,它是最宽数字的像素宽度。 OpenXML规范给出了这个例子作为澄清:
以Calibri字体为例,最大数字宽度为11磅字体 大小为7像素(96 dpi)。
我通过目视检查一个Calibri 11点数字检查这是正确的,它确实是7像素宽。所以,我正在尝试创建一个方法,它将返回任何字体/大小的最大数字宽度。
我已遵循this question中提出的建议,但它没有产生我期待的结果。
这是我的测试代码:
var font = new Font("Calibri", 11.0f, FontStyle.Regular);
for (var i = 0; i < 10; i++)
{
Debug.WriteLine(TextRenderer.MeasureText(i.ToString(), font));
}
报告所有数字的宽度均为15。
有什么建议吗?
谢谢, 添
答案 0 :(得分:5)
TextRenderer并不总是像您期望的那样准确:
来自MSDN:http://msdn.microsoft.com/en-us/library/8wafk2kt.aspx
例如,TextRenderer的默认行为是将填充添加到绘制文本的边界矩形以容纳悬垂字形
您有Graphics
个对象还是Control对象?如果您正在使用这些,您可以按照预期的方式获得准确的恢复。
查看http://msdn.microsoft.com/en-us/library/6xe5hazb(VS.80).aspx
答案 1 :(得分: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);
}
答案 2 :(得分: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提示,它可以调整数字的形状,使其主干落在像素边界上。添加至少一个像素。
答案 3 :(得分: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 );
}
答案 4 :(得分:1)