Draw a paragraph one line at a time in C#

My next few posts show how to draw text on a Graphics object in various ways. The examples draw on PictureBoxes but it's important to remember that they work with any Graphics object including the one that you are given by a PrintDocument's PrintPage event handler. That means these routines are useful for printing text.

This example shows how to break a paragraph into lines and draw the lines separately. This isn't terribly useful by itself but a later post will use this ability to let you draw text that is fully justified (spaced so it reaches the left and right margins).

The following code shows the DrawParagraph method that draws a paragraph line-by-line.

// Draw a paragraph by lines inside the Rectangle.
// Return a RectangleF representing any unused
// space in the original RectangleF.
private RectangleF DrawParagraph(Graphics gr, RectangleF rect,
    Font font, Brush brush, string text, float line_spacing,
    float indent, float extra_paragraph_spacing)
{
    // Get the coordinates for the first line.
    float x = rect.Left + indent;
    float y = rect.Top;

    // Break the text into words.
    string[] words = text.Split(' ');
    int start_word = 0;

    // Repeat until we run out of text or room.
    for (; ; )
    {
        // See how many words will fit.
        // Start with just the next word.
        string line = words[start_word];

        // Add more words until the line won't fit.
        int end_word = start_word + 1;
        while (end_word < words.Length)
        {
            // See if the next word fits.
            string test_line = line + " " + words[end_word];
            SizeF line_size = gr.MeasureString(test_line, font);
            if (line_size.Width > rect.Width)
            {
                // The line is too wide. Don't use the last word.
                end_word--;
                break;
            }
            else
            {
                // The word fits. Save the test line.
                line = test_line;
            }

            // Try the next word.
            end_word++;
        }

        // Draw this line.
        DrawLine(gr, line, font, brush, x, y, rect.Width);

        // Move down to draw the next line.
        y += font.Height * line_spacing;

        // Make sure there's room for another line.
        if (y + font.Height > rect.Height) break;

        // Start the next line at the next word.
        start_word = end_word + 1;
        if (start_word >= words.Length) break;

        // Don't indent subsequent lines.
        x = rect.Left;
    }

    // Add a gap after the paragraph.
    y += font.Height * extra_paragraph_spacing;

    // Return a RectangleF representing any unused
    // space in the original RectangleF.
    float height = rect.Bottom - y;
    if (height < 0) height = 0;
    return new RectangleF(rect.X, y, rect.Width, height);
}

The method starts by setting variables x and y to the location where the paragraph's first line of text should be drawn. It then splits the paragraph into words.

Next the code enters a loop that it repeats until it has finished drawing the text or until it runs out of room. Within this loop, the code enters another loop where it tries adding more words to a test string. It keeps adding words until the test string doesn't fit within the allowed drawing area or it runs out of words.

After it has figured out how many words will fit, the code calls the DrawLine method (described shortly) to draw them.

After it finishes drawing all of the words, the method returns the part of the drawing area rectangle that has not yet been used. This is useful if the program may need to draw other paragraphs after this one.

The following code shows the DrawLine method.

// Draw a line of text.
private void DrawLine(Graphics gr, string line, Font font,
    Brush brush, float x, float y, float width)
{
    gr.DrawString(line, font, brush, x, y);
}

This method simply draws a line of text at an indicated location. The following posts will modify this method to do something more interesting.

   

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.