Search code examples
.netsystem.drawing

How to draw a multi-line string with trailing spaces in .NET


I am drawing strings using Graphics.DrawString and want trailing spaces to be included so I use StringFormatFlags.MeasureTrailingSpaces. For single line strings this works fine but I noticed that new line characters also result in white space at the end of a line. This is not what I want (and I wonder who would).

So I want to implement a MyDrawString method that creates the following output. | is the the x coordinate of a right-aligned draw operation. The implementation should also work for centered strings.

MyDrawString("Test")              ->       Test|

MyDrawString("Test   ")           ->    Test   |

MyDrawString("Test\r\nLine 2   ") ->       Test|
                                      Line 2   |

Unfortunately, the output of the last call looks more like

                                         Test  |
                                      Line 2   |

Is there a way to achieve what I want without breaking up the string and drawing it line by line?

If not, what would be the best approach to draw the lines individually at the same vertical positions that a single DrawString call would use? MeasureString().Height did not give me the full distance between two lines.

UPDATE

I found this MSDN page that explains how to determine the line height when DrawString draws a multi-line string. Still I'd prefer to use a single DrawString call that takes care of the vertical alignment of individual lines as well as the entire text block. Any hints?


Solution

  • I figured out that in my case I have the bounding rectangle of the text which makes a custom implementation quite easy.

        Public Shared Sub MyDrawString(ByVal g As Drawing.Graphics, _
                                       ByVal text As String, _
                                       ByVal font As Drawing.Font, _
                                       ByVal brush As Drawing.Brush, _
                                       ByVal layoutRect As Drawing.RectangleF, _
                                       ByVal stringFormat As Drawing.StringFormat)
    
            Dim lineSpacingPixel As Single
            lineSpacingPixel = font.Size * font.FontFamily.GetLineSpacing(font.Style) / _
                font.FontFamily.GetEmHeight(font.Style)
    
            Dim lines() As String
            lines = text.Split(New String() {vbCrLf}, StringSplitOptions.None)
    
            For i = 0 To lines.Count - 1
                Dim rect As Drawing.RectangleF
                rect = New Drawing.RectangleF(layoutRect.X, layoutRect.Y + i * lineSpacingPixel, _
                                              layoutRect.Width, _
                                              layoutRect.Bottom - layoutRect.Y - i * lineSpacingPixel)
    
                g.DrawString(lines(i), font, brush, rect, stringFormat)
            Next i
    
        End Sub
    

    Note that code adjustments would be required to take word wrap and LineAlignment into account if the size of layoutRect did not match the size of the text to be drawn.