Draw rows of data in left and right justified columns in C#

This example draws a series of rows with columns left or right justified. The program uses the following code to define the data it will draw and the row and column alignments.

// The values.
private string[][] Values =
    {
        new string[] { "C# 24-Hour Trainer", ... , "10/10/2010" },
        new string[] { "Beginning Database Design Solutions", ... , "8/8/2008" },
        ...
    };

// The column alignments.
private StringAlignment[] VertAlignments =
{
    StringAlignment.Center,
    StringAlignment.Center,
    ...
};
private StringAlignment[] HorzAlignments =
{
    StringAlignment.Near,
    StringAlignment.Near,
    StringAlignment.Far,
    StringAlignment.Far,
    StringAlignment.Far,
};

The data that will be drawn is an array of arrays of strings. In other words, each row is represented by an array of string values.

The VertAlignments array holds the vertical alignments that should be used to draw each row. The HorzAlignments array holds the horizontal alignments for the data's columns.

The most interesting part of the program involves two methods: GetRowColumnSizes and DrawTextRowsColumns. The following code shows the GetRowColumnSizes method, which returns the data's maximum row height and the widths of the data's columns.

// Return the items' sizes.
private void GetRowColumnSizes(Graphics gr, Font font,
    string[][] values, out float max_height, out float[] col_widths)
{
    // Make room for the column sizes.
    int num_cols = values[0].Length;
    col_widths = new float[num_cols];

    // Examine each row.
    max_height = 0;
    foreach (string[] row in values)
    {
        // Measure the row's columns.
        for (int col_num = 0; col_num < num_cols; col_num++)
        {
            SizeF col_size = gr.MeasureString(row[col_num], font);
            if (col_widths[col_num] < col_size.Width)
                col_widths[col_num] = col_size.Width;
            if (max_height < col_size.Height)
                max_height = col_size.Height;
        }
    }
}

This method takes as parameters a Graphics object similar to the one that the program will later use to draw the data and the font that it will use. The code loops through the rows of data. For each row, it loops through the row's columns. For each column entry, the code uses the Graphics object's MeasureString method to see how big that entry will be when displayed and it updates the maximum row height and that column's width.

The max_height and col_width parameters are output parameters so the calling code learns the maximum row height and the column widths.

The following code shows the DrawTextRowsColumns method.

// Draw the items in columns.
private void DrawTextRowsColumns(Graphics gr, Font font, Brush brush, Pen box_pen,
    float x0, float y0, float row_height, float[] col_widths,
    StringAlignment[] vert_alignments, StringAlignment[] horz_alignments,
    string[][] values, bool draw_box)
{
    // Create a rectangle in which to draw.
    RectangleF rect = new RectangleF();
    rect.Height = row_height;

    using (StringFormat sf = new StringFormat())
    {
        foreach (string[] row in values)
        {
            float x = x0;
            for (int col_num = 0; col_num < row.Length; col_num++)
            {
                // Prepare the StringFormat and drawing rectangle.
                sf.Alignment = horz_alignments[col_num];
                sf.LineAlignment = vert_alignments[col_num];
                rect.X = x;
                rect.Y = y0;
                rect.Width = col_widths[col_num];

                // Draw.
                gr.DrawString(row[col_num], font, brush, rect, sf);

                // Draw the box if desired.
                if (draw_box) gr.DrawRectangle(box_pen,
                    rect.X, rect.Y, rect.Width, rect.Height);

                // Move to the next column.
                x += col_widths[col_num];
            }

            // Move to the next line.
            y0 += row_height;
        }
    }
}

This method loops through the rows in the data and the columns in each row. For each data value, the code creates a RectangleF that is the maximum row height tall and that column's width wide. It sets a StringFormat object's Alignment and LineAlignment values to properly position the data and then draws it. If the draw_box parameter is true, the code also draws a box around the entry.

After drawing each entry in a row, the code advances the variable x to the position where it should draw the next entry. After it finishes a row, the code advances variable y0 so it is ready to draw the next row.

The final piece to the example is the PictureBox's Paint event handler shown in the following code.

// Display the data aligned in columns.
private void picColumns_Paint(object sender, PaintEventArgs e)
{
    using (Font font = new Font("Times New Roman", 12))
    {
        // Get the row and column sizes.
        float row_height;
        float[] col_widths;
        GetRowColumnSizes(e.Graphics, font, Values, out row_height, out col_widths);

        // Add column margins.
        const float margin = 10;
        for (int i = 0; i < col_widths.Length; i++) col_widths[i] += margin;

        // Draw.
        e.Graphics.Clear(Color.White);
        e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
        DrawTextRowsColumns(e.Graphics, font, Brushes.Black, Pens.Blue,
            margin / 2, margin / 2, row_height, col_widths,
            VertAlignments, HorzAlignments, Values, true);
    }
}

This code calls the GetRowColumnSizes method to get the maximum row height and the column widths. It adds a margin to each column width so the results aren't too crowded.

Finally the code clears the PictureBox's background and calls the DrawTextRowsColumns method to draw the data.

   

 

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.