c# - 如何计算数字的正确宽度(以像素为单位)?

标签 c# winforms graphics gdi+ measurestring

我有一个自定义控件,将来可能会有用户自定义字体(缩放已经实现)。我必须在两位数字下方填充一个矩形,形成以 10 为基数的数字。我对零个、一个或两个数字使用不同的颜色。

使用字体 {Name = Microsoft Sans Serif Size=16} 和以下 Graphics.MeasureString 方法调用:

g.MeasureString("00", Font);
g.MeasureString("0", Font);

我得到:

  • “00”的大小为{宽度 = 31.5486088 高度 = 26.8124962}
  • “0”的大小为{宽度 = 19.3298588 高度 = 26.8124962}

“0”的宽度比“00”宽度的一半大很多。

我知道这些方法Graphics.MeasureString ,它有很多重载,而且我也知道 StringFormat 类。如何正确计算“0”字符的宽度?

因为字体是用户可自定义的,所以我不想使用等宽字体来解决问题。

如果我使用以下调用:

g.MeasureString("00", Font, 999, StringFormat.GenericTypographic);
g.MeasureString("0", Font, 999, StringFormat.GenericTypographic);

“0”的宽度似乎是“00”宽度的一半,但是用较小的字体大小绘制时数字会重叠:

screenshot

更新:在 UserControl 的 OnPaint 方法中,我有以下代码:

Graphics g = e.Graphics;

int[] indices = { 0, 1 };
CharacterRange[] charRanges = new CharacterRange[indices.Length];
for (int chx = 0; chx < indices.Length; ++chx)
{
    charRanges[chx] = new CharacterRange(indices[chx], 1);
}

StringFormat sf = new StringFormat(StringFormat.GenericDefault);
sf.SetMeasurableCharacterRanges(charRanges);

Region[] regions = e.Graphics.MeasureCharacterRanges("01", Font, e.ClipRectangle, sf);

RectangleF[] r = new RectangleF[regions.Length];
int i = 0;
foreach (Region rr in regions)
{
    r[i] = rr.GetBounds(g);
    g.DrawRectangle(Pens.Blue, r[i].X, r[i].Y, r[i].Width, r[i].Height);
    ++i;
}

g.DrawString("0", Font, Brushes.Black, r[0], sf);
g.DrawString("1", Font, Brushes.Black, r[1], sf);

字体为{Name = "Microsoft Sans Serif"Size=25}。运行程序时,可以看到以下内容:

screenshot 2

我想让数字位于蓝色矩形的中心。 UserControl 中的矩形必须尽可能大,但也要​​为 UserControl 高度的百分比留出空间。字体应适应矩形。

最佳答案

需要进行一些小的调整才能按预期工作:

  1. TextRenderingHint.ClearTypeGridFit 在渲染文本时提供更好的结果。
    它更加精确,并且与 Graphics.DrawString 的网格拟合特性配合得很好。
    有关此问题的更多信息,请参阅下面链接的答案中的注释。
  2. StringFormat 在水平和垂直维度上对齐。
  3. 修改后的方法,允许绘制任意长度的字符串。
    如果字符串大于容器,它将使用当前设置进行换行。
  4. 不相关:BrushPen 在 Paint 事件外部声明,以允许在需要时重新定义它们。

此处 MeasureCharacterRanges 的不同实现:
How to highlight wrapped text in a control

关于Graphics.DrawStringTextRenderingHint.ClearTypeGridFit:
Drawing a Long String on to a Bitmap results in Drawing Issues


字体 48em:
MeasureCharacterRanges 1

字体 16em:
MeasureCharacterRanges 2

字体 9em:
MeasureCharacterRanges 3

Pen pen = new Pen(Color.LightGreen, 1);
Brush brush = new SolidBrush(Color.White);
string sourceDigits = "010011001";

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

    CharacterRange[] charRanges = new CharacterRange[sourceDigits.Length];
    for (int chx = 0; chx < sourceDigits.Length; ++chx) {
        charRanges[chx] = new CharacterRange(chx, 1);
    }

    using (StringFormat sf = new StringFormat())
    {
        sf.Alignment = StringAlignment.Center;
        sf.LineAlignment = StringAlignment.Center;
        sf.SetMeasurableCharacterRanges(charRanges);

        Region[] regions = e.Graphics.MeasureCharacterRanges(sourceDigits, Font, e.ClipRectangle, sf);
        for (int i = 0; i < regions.Length; i++) {
            RectangleF rect = regions[i].GetBounds(e.Graphics);
            e.Graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
            e.Graphics.DrawString(char.ToString(sourceDigits[i]), Font, brush, rect, sf);
        }
    }
}

关于c# - 如何计算数字的正确宽度(以像素为单位)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54365948/

相关文章:

c# - 了解类 SmtpDeliveryMethod

c# - 所有 C# 强制转换都会导致装箱/拆箱

c# - 使用相对坐标从 C# 绘制路径

javascript - DukTape 在 GLUT 窗口上显示 JavaScript Canvas

c# - 使用反射执行审计

c# - 如何用NHibernate保存由其他复杂类型组成的实体,但我只有其他复杂类型的ID

c# - 流布局面板问题

c# - 如何在 C#/Visual Studio 中调用包含在文件夹中的类?

.net - GDI + .NET : LinearGradientBrush wider than 202 pixels causes color wrap-around

java - 调整大小时 JFrame 图像干净