2010-12-13 48 views
27

System.Windows.Forms.TextRenderer.DrawText方法渲染格式的文本有或无左右边距取决于flags参数的值:如何获得使用的确切文字利润率由TextRenderer

  • TextFormatFlags.NoPadding - 紧密适合文本边框,
  • TextFormatFlags.GlyphOverhangPadding - 增加了一些左右边距,
  • TextFormatFlags.LeftAndRightPadding - 增加了更大的利润。

现在,我的问题是我怎样才能得到填充的确切数额(左,右)DrawText添加到文本对于给定的设备上下文,字符串,字体等?

我用.NET Reflector挖掘了.NET 4,发现TextRenderer计算字体高度的1/6的“悬垂填充”,然后乘以该值以计算使用这些系数的左右边距:

  • 左1.0,对于TextFormatFlags.GlyphOverhangPadding右1.5,
  • 左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在整个多格式文本的开头和结尾。

+0

+1为综合分析:-)。我也有这个问题,你嗅过的左边填充值为我解决了 - 谢谢。 – Fedearne 2011-07-07 08:29:39

回答

1

这似乎是(非常)原油,但是这是唯一的本地实现,我能想到的: DrawText将至IDeviceContext,这是由Graphics实现。现在,我们可以利用这一点与下面的代码:

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

我在几年前做过类似的事情,突出显示搜索结果(搜索模式显示在bol中d等)。我的实现是在DevExpress中,所以代码可能不相关。如果您认为它是有用的,我可以复制它,只需要找到该实现。

System.Windows.Forms中,要使用的类将是Graphics。它有一个MeasureCharacterRanges()方法,它接受StringFormat(从GenericTypographic开始并从那里开始)。它比TextRenderer更适合通过链接具有不同样式,字体或画笔的部分来显示完整的字符串。

你已经走了比我更多的实际填充测量。 DevExpress的控件为您提供了文本边界矩形,以便为我完成。

Here's皮埃尔·阿诺的一篇文章在我的谷歌上发表,涉及这方面。不幸的是,GDI +“血腥细节”链接已经破裂。

干杯,
Jonno

2

这个答案是从这里摘录 - http://www.techyv.com/questions/how-get-exact-text-margins-used-textrenderer#comment-35164

如果你曾经想要一个标签或文本框在执行更喜欢在网络上一点点,那么Windows窗体你我们可能已经发现,没有直观的方法可以让Label或TextBox自动调整其高度以适应其包含的文本。虽然它可能不直观,但绝对不是不可能的。

在这个例子中,我将使用停靠在窗体顶部的TextBox(您可以轻松使用Label)。要使用此窗体,请将名为MyTextBox的aTextBox添加到窗体,并将Dock设置为DockStyle.Top。将TextBox的Resize事件连接到此事件处理程序。

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; 
} 

如果要调整未停靠一个标签或文本框(例如,一个是在FlowLayoutPanel的或其它的面板,或者只是放置在窗体上),那么你可以处理窗体的Resize甚至相反,只是直接修改控件的属性。

+0

TextBox上没有属性字体http://msdn.microsoft.com/en-us/library/system.windows.controls.textbox%28v=vs.110%29.aspx – user969153 2014-08-11 14:07:06

0

修复的方法是计算一下MeasureText将会增加:

var formatFlags FormatFlags = 
    TextFormatFlags.NoPadding | 
    TextFormatFlags.SingleLine; 

int largeWidth = TextRenderer.MeasureText(
    " ", 
    font, 
    new Size(int.MaxValue, int.MaxValue), 
    formatFlags 
).Width; 
int smallWidth = TextRenderer.MeasureText(
    " ", 
    font, 
    new Size(int.MaxValue, int.MaxValue), 
    formatFlags 
).Width; 

int extra = smallWidth - (largeWidth - smallWidth); 

我们计算的一个空间的宽度和两个空间的宽度。两者都添加了额外的宽度,所以我们可以推断出正在添加的额外宽度。增加的宽度显然总是相同的,所以从MeasureText返回的每个宽度中减去extra即可得出预期结果。

5

计算左右边距所需的值为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-based control“搜索突出”的特点:

enter image description here

就像一个魅力:)