Justify paragraphs in C#

[justify paragraphs]

This example adds the ability to justify paragraphs to the example The example Align text by lines in C#. This is a bit more complicated than aligning text on the left, right, or center.

(I don’t know why Microsoft didn’t include the ability to justify text to the StringFormat class. My guess is that they didn’t think it always looked good so they decided not to allow it. It is true that this looks best if you use relatively long lines of text so the spacing between words isn’t too large.)

Unfortunately, because Microsoft didn’t include justification in the StringFormat class, the previous example’s DrawLine method can’t do this. The following DrawJustifiedLine method draws a justified line of text.

// 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 splits the line into words and then loops through the words measuring them. It calculates the extra space not needed to draw the words and divides that space by the number of gaps between the words.

The code then loops through the words again, this time drawing them and adding the extra space between them.

The program needs a few other changes. First, it adds the value Justified to the TextJustification enumeration. Next, the DrawLine method now checks for the new value and calls DrawJustifiedLine if appropriate. The following code shows that part of the method.

// See if we should justify the text.
if (justification == TextJustification.Justified)
    DrawJustifiedLine(gr, rect, font, brush, line);
else
{
    // Make a StringFormat to align the text.
    using (StringFormat sf = new StringFormat())
    {
        // 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);
    }
}

The last change is to the DrawParagraph method. When you draw justified text, you draw the last line of each paragraph left-aligned. If you try to justify a paragraph’s final line, the result if usually quite strange. For example, suppose a paragraph’s last line only includes the two words “do it.” If you justify that line, you get “do” on the left, a huge gap, and then “it” on the right.

The DrawParagraph method uses the following code to avoid this problem.

// If this is the end of the paragraph and
// we're justifying, align on the left.
if ((end_word == words.Length) &&
    (justification == TextJustification.Justified))
{
    DrawLine(gr, line, font, brush,
        rect.Left + indent,
        y,
        rect.Width - indent,
        TextJustification.Left);
}
else
{
    DrawLine(gr, line, font, brush,
        rect.Left + indent,
        y,
        rect.Width - indent,
        justification);
}

This code checks whether we are justifying text and the last word in the current line is also the paragraph’s last word and, if so, the code makes DrawLine left-align the text. If this is not the paragraph’s final word or we are not justifying text, the program calls DrawLine to align the text as before.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in fonts, graphics, printing, strings and tagged , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *