2010-12-13 51 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

就像一個魅力:)