在不使用Graphics对象的情况下测量String?

Agn*_*ian 40 c# fonts text gdi+

我使用像素作为我的字体的单位.在一个地方,我正在执行命中测试以检查用户是否在屏幕上的某些文本的边界矩形内点击了.我需要使用像MeasureString这样的东西.不幸的是,执行命中测试的代码深入到一个无法访问Graphics对象甚至是一个对象的库中Control.

如何在不使用Graphics类的情况下获取给定字体的字符串的边界框?为什么Graphics我的字体以像素为单位时甚至需要一个对象?

Jar*_*rod 47

如果您有对System.Windows.Forms的引用,请尝试使用TextRenderer类.有一个静态方法(MeasureText),它接受字符串和字体并返回大小. MSDN链接

  • TextRenderer的一个小问题是它使用整数作为返回值,如果你需要子像素精度,这可能会导致问题.否则,它是一个很好的选择. (2认同)
  • @ jp2code不知道你是否还在乎,但MeaureText使用内部类`WindowsGraphicsCacheManager`.管理器有一个静态的`MeasurementGraphics`属性,它在第一次使用时会被输入.它通过使用[this constructor]从设备上下文创建一个带有PInvoke到gdi32.dll的图形来实现这一点(http://msdn.microsoft.com/en-us/library/windows/desktop/ms536160(v = vs 0.85)的.aspx).NerdFury的答案最终使用[这个构造函数](http://msdn.microsoft.com/en-us/library/windows/desktop/ms536159(v = vs.85).aspx)当然图形不是缓存但是否则他们是一样的 (2认同)

Ner*_*ury 23

您不需要使用用于渲染的图形对象来进行测量.您可以创建一个静态实用程序类:

public static class GraphicsHelper
{
    public static SizeF MeasureString(string s, Font font)
    {
        SizeF result;
        using (var image = new Bitmap(1, 1))
        {
            using (var g = Graphics.FromImage(image))
            {
                result = g.MeasureString(s, font);
            }
        }

        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

可能值得,根据您的情况设置位图的dpi.

  • 使用Graphics.FromHwnd(IntPtr.Zero)来避免创建位图. (4认同)

Ant*_*tov 11

MeasureString@NerdFury中的方法将给出比预期更高的字符串宽度.您可以在此处找到其他 信息.如果您只想测量物理长度,请添加以下两行:

g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
result = 
  g.MeasureString(measuredString, font, int.MaxValue, StringFormat.GenericTypographic);
Run Code Online (Sandbox Code Playgroud)