如何计算数字的正确宽度(以像素为单位)? [英] How to compute the correct width of a digit in pixels?
问题描述
我有一个自定义控件,将来可能会为用户提供可自定义的Font(已经实现了缩放).我必须在以10为底的数字的两位数字下方填充一个矩形.我为零,一个或两个数字使用不同的颜色.
使用字体{Name = Microsoft Sans Serif
Size = 16
}和以下 Graphics.MeasureString
方法调用:
g.MeasureString("00",Font);g.MeasureString("0",Font);
我得到:
- "00"的大小为{Width =
31.5486088
高度=26.8124962
} - "0"的大小为{Width =
19.3298588
Height =26.8124962
}
"0"的宽度比"00"的宽度大一半.
我知道方法
更新:在UserControl的OnPaint方法中,我有以下代码:
Graphics g = e.Graphics;int []索引= {0,1};CharacterRange [] charRanges =新的CharacterRange [indices.Length];for(int chx = 0; chx
字体为 {Name ="Microsoft Sans Serif" Size = 25}
.运行程序时,这是可见的:
我想使数字以蓝色矩形为中心.矩形在UserControl中必须尽可能大,但还要留出一定空间以保留UserControl高度的百分之一.字体应适应矩形.
为使此功能按预期进行,需要进行一些小的调整:
- 呈现文本时,
-
TextRenderingHint.ClearTypeGridFit
会提供更好的结果.
它更精确,并且与Graphics.DrawString
的网格拟合特性配合使用.
有关此问题的更多信息,请参见下面的答案中的注释. -
StringFormat
在水平和垂直方向上的对齐方式. - 一种经过修改的方法,可以绘制任意长度的字符串.
如果字符串大于容器,则将使用当前设置将其包装. - Irrelevant:
笔刷和 Pen
在Paint事件外部声明,以便在需要时可以重新定义.
这里的 MeasureCharacterRanges
的不同实现:
Font 16em:
字体9em:
钢笔=新钢笔(Color.LightGreen,1);画笔=新的SolidBrush(Color.White);字符串sourceDigits ="010011001";私人无效panel1_Paint(对象发送者,PaintEventArgs e){e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;CharacterRange [] charRanges =新的CharacterRange [sourceDigits.Length];for(int chx = 0; chx< sourceDigits.Length; ++ chx){charRanges [chx] = new CharacterRange(chx,1);}使用(StringFormat sf = new StringFormat()){sf.Alignment = StringAlignment.Center;sf.LineAlignment = StringAlignment.Center;sf.SetMeasurableCharacterRanges(charRanges);Region []地区= e.Graphics.MeasureCharacterRanges(sourceDigits,Font,e.ClipRectangle,sf);for(int i = 0; i< region.Length; i ++){RectangleF rect = region [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);}}}
I have a custom control that may have user customizable Font in future (the zoom is already implemented). I must fill a rectangle under two digits that form a base-10 number. I have different colors for zero, one or both of the digits.
With the font {Name = Microsoft Sans Serif
Size=16
} and the following Graphics.MeasureString
method calls:
g.MeasureString("00", Font);
g.MeasureString("0", Font);
I get:
- The size of "00" is {Width =
31.5486088
Height =26.8124962
} - The size of "0" is {Width =
19.3298588
Height =26.8124962
}
The width of "0" is a lot bigger that half of the width of "00".
I know of the methods Graphics.MeasureString, it has many overloads, and I also know of the StringFormat class. How can I correctly compute the width of the '0' char?
Because the font will be user-customizable, I do not want to solve the problem using a monospace font.
If I use the following calls:
g.MeasureString("00", Font, 999, StringFormat.GenericTypographic);
g.MeasureString("0", Font, 999, StringFormat.GenericTypographic);
The width of "0" seems to be half of the width of "00", but the digits overlap when drawn with a smaller font size:
Update: In the OnPaint method of an UserControl I have this code:
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);
The font is {Name = "Microsoft Sans Serif" Size=25}
. When running the program, this is what is visible:
I want to make the digits centered in the blue rectangles. The rectangles must be as big as possible in the UserControl but also leaving space for a percent of the Height of the UserControl. The Font should adapt to the rectangles.
Small adjustments are required to make this work as intended:
TextRenderingHint.ClearTypeGridFit
gives a better result when rendering the Text.
It's more precise and works well with the grid-fitting nature ofGraphics.DrawString
.
See the notes you can find in the answer linked below for more informations on this matter.StringFormat
alignment in both horizontal and vertical dimensions.- A modified method that allows to draw strings of any length.
If the string is larger than the container, it will be wrapped, with the current settings. - Irrelevant:
Brush
andPen
are declared outside the Paint event, to allow their re-definition when required.
Different implementations of MeasureCharacterRanges
here:
How to highlight wrapped text in a control
About Graphics.DrawString
and TextRenderingHint.ClearTypeGridFit
:
Drawing a Long String on to a Bitmap results in Drawing Issues
Font 48em:
Font 16em:
Font 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);
}
}
}
这篇关于如何计算数字的正确宽度(以像素为单位)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!