首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何获得TextRenderer使用的准确文本边距

如何获得TextRenderer使用的准确文本边距
EN

Stack Overflow用户
提问于 2010-12-13 11:26:35
回答 5查看 6.3K关注 0票数 30

System.Windows.Forms.TextRenderer.DrawText方法根据flags参数的值呈现带有或不带左和右填充的格式化文本:

  • TextFormatFlags.NoPadding --将文本紧紧地放进边框中,
  • TextFormatFlags.GlyphOverhangPadding --添加一些左右边距,
  • TextFormatFlags.LeftAndRightPadding --创造了更大的利润率。

现在,我的问题是,如何获得DrawText 为给定设备上下文、字符串、字体等添加到文本中的填充量(左和右)?

我使用.NET 4和.NET反射器进行了深入研究,发现TextRenderer计算“悬空填充”,即字体高度的1/6,然后用以下系数乘以这个值来计算左边和右边距:

  • 左1.0,右1.5表示TextFormatFlags.GlyphOverhangPadding
  • 左2.0,右2.5表示TextFormatFlags.LeftAndRightPadding

结果值被舍入并传递给DrawTextExADrawTextExW本机API函数。很难重新创建这个过程,因为字体的高度不是从System.Drawing.Font获取的,而是从System.Windows.Forms.Internal.WindowsFont获取的,并且这些类为相同的字体返回不同的值。并且涉及来自System.Windows.Forms.Internal命名空间的许多其他内部BCL类。反编译它们并在我的应用程序中重用它们的代码不是一个选项,因为这将是一个严重的.NET实现依赖。这就是为什么我需要知道在WinForms中是否有一些公共API,或者至少我可以使用哪些Windows函数来获得左右边距的值。

注意:,我尝试过用TextRenderer.MeasureText填充和不填充,比较结果,但这只给了我左边距和右边距之和,我需要它们分开。

备注2:,如果您想知道我为什么要这样做:我想用多个字体/颜色绘制一个字符串。这包括为每个格式一致的子字符串调用DrawText一次,并带有NoPadding选项(这样文本就不会传播),但我也希望在整个多格式文本的开头和末尾手动添加普通的GlyphOverhangPadding

EN

回答 5

Stack Overflow用户

发布于 2012-12-13 11:48:03

计算左边距和右边距所需的值是TEXTMETRIC.tmHeight,它可以使用Win32 API获得。

但是,我发现tmHeight只是字体的线条高度(以像素为单位),所以这三种方法都会给出相同的值(您可以在代码中使用任何您喜欢的):

代码语言:javascript
运行
复制
int apiHeight = GetTextMetrics(graphics, font).tmHeight;
int gdiHeight = TextRenderer.MeasureString(...).Height;
int gdipHeight = (int)Math.Ceiling(font.GetHeight(graphics));

为了获得左边距和右边距,我们使用与TextRenderer在遮罩下的代码相同的代码:

代码语言:javascript
运行
复制
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);

现在你可以很容易地检查

代码语言:javascript
运行
复制
(leftMargin + rightMargin) == overallPadding

需要注意的是:

为了在使用GDI文本呈现的基于ListView的控件中实现“搜索突出显示”功能,我需要解决这个问题:

工作起来很有魅力:)

票数 5
EN

Stack Overflow用户

发布于 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的调整大小事件连接到此事件处理程序。

代码语言:javascript
运行
复制
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,或仅放在窗体上),则可以直接处理窗体的调整大小,并直接修改控件的属性。

票数 2
EN

Stack Overflow用户

发布于 2011-08-14 16:14:30

这看起来(非常)粗糙,但这是我唯一能想到的本机实现:DrawText绘制到一个由Graphics实现的IDeviceContext。现在,我们可以使用以下代码来利用这一点:

代码语言:javascript
运行
复制
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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4428335

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档