如何计算以像素为单位的数字的正确宽度?
How to compute the correct width of a digit in pixels?
我有一个自定义控件,将来可能会有用户自定义字体(缩放已经实现)。我必须在构成以 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 class。如何正确计算“0”字符的宽度?
因为字体是用户自定义的,我不想使用单space字体来解决问题。
如果我使用以下调用:
g.MeasureString("00", Font, 999, StringFormat.GenericTypographic);
g.MeasureString("0", Font, 999, StringFormat.GenericTypographic);
“0”的宽度似乎是“00”宽度的一半,但用较小的字体绘制时数字重叠:
更新: 在 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}
。当运行程序时,这是可见的:
我想让数字在蓝色矩形中居中。矩形在 UserControl 中必须尽可能大,但也为 UserControl 的高度百分比保留 space。字体应适应矩形。
需要进行一些小的调整才能使这项工作按预期进行:
TextRenderingHint.ClearTypeGridFit
在渲染文本时给出更好的结果。
它更精确并且与 Graphics.DrawString
.
的网格拟合特性配合得很好
有关此问题的更多信息,请参阅您可以在下面链接的答案中找到的注释。
StringFormat
水平和垂直方向对齐。
- 修改后的方法,允许绘制任意长度的字符串。
如果字符串比容器大,它将使用当前设置进行包装。
- 不相关:
Brush
和 Pen
在 Paint 事件之外声明,以允许在需要时重新定义它们。
此处 MeasureCharacterRanges
的不同实现:
关于 Graphics.DrawString
和 TextRenderingHint.ClearTypeGridFit
:
字体 48em:
字体 16em:
字体 9em:
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);
}
}
}
我有一个自定义控件,将来可能会有用户自定义字体(缩放已经实现)。我必须在构成以 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 class。如何正确计算“0”字符的宽度?
因为字体是用户自定义的,我不想使用单space字体来解决问题。
如果我使用以下调用:
g.MeasureString("00", Font, 999, StringFormat.GenericTypographic);
g.MeasureString("0", Font, 999, StringFormat.GenericTypographic);
“0”的宽度似乎是“00”宽度的一半,但用较小的字体绘制时数字重叠:
更新: 在 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}
。当运行程序时,这是可见的:
我想让数字在蓝色矩形中居中。矩形在 UserControl 中必须尽可能大,但也为 UserControl 的高度百分比保留 space。字体应适应矩形。
需要进行一些小的调整才能使这项工作按预期进行:
TextRenderingHint.ClearTypeGridFit
在渲染文本时给出更好的结果。
它更精确并且与Graphics.DrawString
.
的网格拟合特性配合得很好 有关此问题的更多信息,请参阅您可以在下面链接的答案中找到的注释。StringFormat
水平和垂直方向对齐。- 修改后的方法,允许绘制任意长度的字符串。
如果字符串比容器大,它将使用当前设置进行包装。 - 不相关:
Brush
和Pen
在 Paint 事件之外声明,以允许在需要时重新定义它们。
此处 MeasureCharacterRanges
的不同实现:
关于 Graphics.DrawString
和 TextRenderingHint.ClearTypeGridFit
:
字体 48em:
字体 16em:
字体 9em:
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);
}
}
}