Fully justify paragraphs of text in C#

The following examples provide some of the background used by this one:

The new example uses the techniques used by the first example above to deal with the text one line at a time. It then uses the following code to draw each line.

// Draw a line of text.
private void DrawLine(Graphics gr, string line, Font font,
    Brush brush, float x, float y, float width,
    TextJustification justification)
{
    // Make a rectangle to hold the text.
    RectangleF rect = new RectangleF(x, y, width, font.Height);

    // Make a StringFormat to align the text.
    using (StringFormat sf = new StringFormat())
    {
        // See if we should use full justification.
        if (justification == TextJustification.Full)
        {
            // Justify the text.
            DrawJustifiedLine(gr, rect, font, brush, line);
        }
        else
        {
            // Use the appropriate alignment.
            switch (justification)
            {
                case TextJustification.Left:
                    sf.Alignment = StringAlignment.Near;
                    break;
                case TextJustification.Right:
                    sf.Alignment = StringAlignment.Far;
                    break;
                case TextJustification.Center:
                    sf.Alignment = StringAlignment.Center;
                    break;
            }

            gr.DrawString(line, font, brush, rect, sf);
        }
    }
}

This code looks at the justification parameter to see how it should justify the line of text. If justification is Full, the code calls the DrawJustifiedLine method to draw the text. If justification is Left, Right, or Center, the code uses a appropriate StringFormat alignment and draws the text.

The following code shows the DrawJustifiedLine method.

// Draw justified text on the Graphics object
// in the indicated Rectangle.
private void DrawJustifiedLine(Graphics gr, RectangleF rect,
    Font font, Brush brush, string text)
{
    // Break the text into words.
    string[] words = text.Split(' ');

    // Add a space to each word and get their lengths.
    float[] word_width = new float[words.Length];
    float total_width = 0;
    for (int i = 0; i < words.Length; i++)
    {
        // See how wide this word is.
        SizeF size = gr.MeasureString(words[i], font);
        word_width[i] = size.Width;
        total_width += word_width[i];
    }

    // Get the additional spacing between words.
    float extra_space = rect.Width - total_width;
    int num_spaces = words.Length - 1;
    if (words.Length > 1) extra_space /= num_spaces;

    // Draw the words.
    float x = rect.Left;
    float y = rect.Top;
    for (int i = 0; i < words.Length; i++)
    {
        // Draw the word.
        gr.DrawString(words[i], font, brush, x, y);

        // Move right to draw the next word.
        x += word_width[i] + extra_space;
    }
}

This method works as in the earlier example. It measures each word in the line. To calculate the amount of space it should leave between words, the code subtracts the total width available from the sum of the words' widths and divides by the number of spaces between words. The method then draws the words with the appropriate space between them.

Note that this code works best when the text you want to fully justify contains words that are relatively small compared to the width of the rectangle. For example, if you run the program and shrink the form so it's about half its original size, you'll see that the code must add lots of extra space to each line and the result is fairly unattractive.

   

 

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.