System.Windows.Forms.TextRenderer.DrawText
方法根据flags
参数的值呈现带有或不带左和右填充的格式化文本:
TextFormatFlags.NoPadding
--将文本紧紧地放进边框中,TextFormatFlags.GlyphOverhangPadding
--添加一些左右边距,TextFormatFlags.LeftAndRightPadding
--创造了更大的利润率。现在,我的问题是,如何获得DrawText
为给定设备上下文、字符串、字体等添加到文本中的填充量(左和右)?
我使用.NET 4和.NET反射器进行了深入研究,发现TextRenderer计算“悬空填充”,即字体高度的1/6,然后用以下系数乘以这个值来计算左边和右边距:
TextFormatFlags.GlyphOverhangPadding
,TextFormatFlags.LeftAndRightPadding
。结果值被舍入并传递给DrawTextExA
或DrawTextExW
本机API函数。很难重新创建这个过程,因为字体的高度不是从System.Drawing.Font
获取的,而是从System.Windows.Forms.Internal.WindowsFont
获取的,并且这些类为相同的字体返回不同的值。并且涉及来自System.Windows.Forms.Internal
命名空间的许多其他内部BCL类。反编译它们并在我的应用程序中重用它们的代码不是一个选项,因为这将是一个严重的.NET实现依赖。这就是为什么我需要知道在WinForms中是否有一些公共API,或者至少我可以使用哪些Windows函数来获得左右边距的值。
注意:,我尝试过用TextRenderer.MeasureText
填充和不填充,比较结果,但这只给了我左边距和右边距之和,我需要它们分开。
备注2:,如果您想知道我为什么要这样做:我想用多个字体/颜色绘制一个字符串。这包括为每个格式一致的子字符串调用DrawText
一次,并带有NoPadding
选项(这样文本就不会传播),但我也希望在整个多格式文本的开头和末尾手动添加普通的GlyphOverhangPadding
。
发布于 2012-12-13 11:48:03
计算左边距和右边距所需的值是TEXTMETRIC.tmHeight,它可以使用Win32 API获得。
但是,我发现tmHeight只是字体的线条高度(以像素为单位),所以这三种方法都会给出相同的值(您可以在代码中使用任何您喜欢的):
int apiHeight = GetTextMetrics(graphics, font).tmHeight;
int gdiHeight = TextRenderer.MeasureString(...).Height;
int gdipHeight = (int)Math.Ceiling(font.GetHeight(graphics));
为了获得左边距和右边距,我们使用与TextRenderer在遮罩下的代码相同的代码:
private const float ItalicPaddingFactor = 0.5f;
...
float overhangPadding = (gdiHeight / 6.0f);
//NOTE: proper margins for TextFormatFlags.LeftAndRightPadding flag
//int leftMargin = (int)Math.Ceiling(overhangPadding);
//int rightMargin = (int)Math.Ceiling(overhangPadding * (2 + ItalicPaddingFactor));
//NOTE: proper margins for TextFormatFlags.GlyphOverhangPadding flag
int leftMargin = (int)Math.Ceiling(overhangPadding);
int rightMargin = (int)Math.Ceiling(overhangPadding * (1 + ItalicPaddingFactor));
Size sizeOverhangPadding = TextRenderer.MeasureText(e.Graphics, "ABC", font, Size.Empty, TextFormatFlags.GlyphOverhangPadding);
Size sizeNoPadding = TextRenderer.MeasureText(e.Graphics, "ABC", font, Size.Empty, TextFormatFlags.NoPadding);
int overallPadding = (sizeOverhangPadding.Width - sizeNoPadding.Width);
现在你可以很容易地检查
(leftMargin + rightMargin) == overallPadding
需要注意的是:
为了在使用GDI文本呈现的基于ListView的控件中实现“搜索突出显示”功能,我需要解决这个问题:
工作起来很有魅力:)
发布于 2011-10-28 08:58:31
这个答案是摘录自这里的- http://www.techyv.com/questions/how-get-exact-text-margins-used-textrenderer#comment-35164
如果您曾经想过在Windows中使用一个标签或TextBox来执行更像在网络上的操作,那么您可能已经发现,没有直观的方法可以使标签或TextBox自动调整其高度以适应它所包含的文本。虽然这可能不是直观的,但绝对不是不可能的。
在本例中,我将使用停靠在TextBox顶部的form.To (您也可以很容易地使用标签),将aTextBox调用MyTextBox添加到表单中,并将Dock设置为DockStyle.Top。将TextBox的调整大小事件连接到此事件处理程序。
private void MyTextBox_Resize( object sender, EventArgs e )
{
// Grab a reference to the TextBox
TextBox tb = sender as TextBox;
// Figure out how much space is used for borders, etc.
int chromeHeight = tb.Height - tb.ClientSize.Height;
// Create a proposed size that is very tall, but exact in width.
Size proposedSize = new Size( tb.ClientSize.Width, int.MaxValue );
// Measure the text using the TextRenderer
Size textSize = TextRenderer.MeasureText( tb.Text, tb.Font,
proposedSize, TextFormatFlags.TextBoxControl
| TextFormatFlags.WordBreak );
// Adjust the height to include the text height, chrome height,
// and vertical margin
tb.Height = chromeHeight + textSize.Height
+ tb.Margin.Vertical;
}
如果要调整未停靠的标签或TextBox的大小(例如,位于FlowLayoutPanel或其他面板中的标签或and,或仅放在窗体上),则可以直接处理窗体的调整大小,并直接修改控件的属性。
发布于 2011-08-14 16:14:30
这看起来(非常)粗糙,但这是我唯一能想到的本机实现:DrawText
绘制到一个由Graphics
实现的IDeviceContext
。现在,我们可以使用以下代码来利用这一点:
Bitmap bmp = new Bitmap(....);
Graphics graphic = Graphics.FromImage(bmp);
textRenderer.DrawText(graphic,....);
graphic.Dispose();
使用新的Bitmap
,您可以逐个像素并按某种条件对它们进行计数。同样,这种方法非常粗糙和浪费,但至少它是本土的.
这不是经过测试的,而是基于以下来源:
http://msdn.microsoft.com/en-us/library/4ftkekek.aspx
http://msdn.microsoft.com/en-us/library/system.drawing.idevicecontext.aspx
http://msdn.microsoft.com/en-us/library/system.drawing.graphics.aspx
http://www.pcreview.co.uk/forums/graphics-bitmap-t1399954.html
https://stackoverflow.com/questions/4428335
复制相似问题