从Graphics.DrawString()居中输出文本
我正在使用.NETCF(Windows Mobile)" Graphics"类和" DrawString()"方法在屏幕上呈现单个字符。
问题是我似乎无法使其正确居中。无论我为字符串渲染的位置的Y坐标设置什么,它总是比该值低,并且文本大小越大,Y偏移量越大。
例如,在文本大小12处,偏移量约为4,但在32处,偏移量约为10.
我希望角色垂直占据绘制的矩形的大部分并水平居中。这是我的基本代码。 " this"是指正在被绘制的用户控件。
Graphics g = this.CreateGraphics(); float padx = ((float)this.Size.Width) * (0.05F); float pady = ((float)this.Size.Height) * (0.05F); float width = ((float)this.Size.Width) - 2 * padx; float height = ((float)this.Size.Height) - 2 * pady; float emSize = height; g.DrawString(letter, new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular), new SolidBrush(Color.Black), padx, pady);
是的,我知道可以使用标签控件来代替它并设置居中,但是实际上我确实需要通过" Graphics"类手动进行此操作。
解决方案
回答
我们可以使用传递给DrawString
方法的StringFormat
对象的实例来使文本居中。
请参见Graphics.DrawString方法和StringFormat类。
回答
这是一些代码。假定我们正在表单或者UserControl上执行此操作。
Graphics g = this.CreateGraphics(); SizeF size = g.MeasureString("string to measure"); int nLeft = Convert.ToInt32((this.ClientRectangle.Width / 2) - (size.Width / 2)); int nTop = Convert.ToInt32((this.ClientRectangle.Height / 2) - (size.Height / 2));
在帖子中,听起来好像ClientRectangle部分(例如,我们没有使用它)给我们带来了困难。
回答
绘制居中文字:
TextRenderer.DrawText(g, "my text", Font, Bounds, ForeColor, BackColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.GlyphOverhangPadding);
确定最佳字体大小来填充区域要困难一些。我发现一个可行的尝试是反复试验:从大字体开始,然后反复测量字符串并缩小字体直到适合为止。
Font FindBestFitFont(Graphics g, String text, Font font, Size proposedSize, TextFormatFlags flags) { // Compute actual size, shrink if needed while (true) { Size size = TextRenderer.MeasureText(g, text, font, proposedSize, flags); // It fits, back out if ( size.Height <= proposedSize.Height && size.Width <= proposedSize.Width) { return font; } // Try a smaller font (90% of old size) Font oldFont = font; font = new Font(font.FontFamily, (float)(font.Size * .9)); oldFont.Dispose(); } }
我们可以将其用作:
Font bestFitFont = FindBestFitFont(g, text, someBigFont, sizeToFitIn, flags); // Then do your drawing using the bestFitFont // Don't forget to dispose the font (if/when needed)
回答
通过结合我的建议,我想到了:
private void DrawLetter() { Graphics g = this.CreateGraphics(); float width = ((float)this.ClientRectangle.Width); float height = ((float)this.ClientRectangle.Width); float emSize = height; Font font = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular); font = FindBestFitFont(g, letter.ToString(), font, this.ClientRectangle.Size); SizeF size = g.MeasureString(letter.ToString(), font); g.DrawString(letter, font, new SolidBrush(Color.Black), (width-size.Width)/2, 0); } private Font FindBestFitFont(Graphics g, String text, Font font, Size proposedSize) { // Compute actual size, shrink if needed while (true) { SizeF size = g.MeasureString(text, font); // It fits, back out if (size.Height <= proposedSize.Height && size.Width <= proposedSize.Width) { return font; } // Try a smaller font (90% of old size) Font oldFont = font; font = new Font(font.Name, (float)(font.Size * .9), font.Style); oldFont.Dispose(); } }
到目前为止,这是完美的。
我唯一要更改的是将FindBestFitFont()调用移到OnResize()事件,这样我每次绘制字母时都不会调用它。仅在控件大小更改时才需要调用它。我只是为了完整性而将其包括在函数中。
回答
我想为StringFormat对象添加另一个投票。
我们可以简单地使用它来指定"中心,中心",文本将在矩形或者所提供的点的中心绘制:
StringFormat format = new StringFormat(); format.LineAlignment = StringAlignment.Center; format.Alignment = StringAlignment.Center;
但是,CF中存在一个问题。如果我们对两个值都使用Center,则它将关闭TextWrapping。不知道为什么会这样,它似乎是CF的一个错误。
回答
要对齐文本,请使用以下命令:
StringFormat sf = new StringFormat(); sf.LineAlignment = StringAlignment.Center; sf.Alignment = StringAlignment.Center; e.Graphics.DrawString("My String", this.Font, Brushes.Black, ClientRectangle, sf);
请注意,此处的文本在给定范围内对齐。在此示例中,这是ClientRectangle。