Title: Use tabs and StringFormat to align text in C#
This example shows how you can use a StringFormat object to align tab-delimited text when drawing it on a window. The Graphics class's DrawString method draws a string on a window, PictureBox, Bitmap, or other drawing surface. The DrawString method has several overloaded versions, some of which take a StringFormat object as a parameter. That object lets you define things such as the text's horizontal and vertical alignment. It also lets you define tab stops so you can align tab-delimited text when you draw it.
This example uses the following code to use tabs to align text.
// Draw some text aligned in columns.
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
string headings = "Title\tPrice\t# Pages\tYear";
string[] lines =
{
"WPF 3d\t$34.95\t430\t2018",
"The C# Helper Top 100\t$24.95\t380\t2017",
"Interview Puzzles Dissected\t$15.95\t300\t2016",
"C# 24-Hour Trainer, Second Edition\t$45.00\t600\t2015",
"Beginning Software Engineering\t$45.00\t480\t2015",
"Essential Algorithms\t$60.00\t624\t2013",
"Beginning Database Design Solutions\t$44.99\t552\t2008",
"Powers of Two\t$2.04\t8\t16",
};
// Prepare a StringFormat to use the tabs.
using (StringFormat string_format = new StringFormat())
{
// These just make things weird:
//string_format.Alignment = StringAlignment.Center;
//string_format.LineAlignment = StringAlignment.Center;
// Define the tab stops.
float[] tabs = { 250, 75, 75 };
string_format.SetTabStops(0, tabs);
// Draw the headings.
float margin = 10;
float y = 10;
using (Font font = new Font("Times New Roman",
13, FontStyle.Bold))
{
e.Graphics.DrawString(headings, font,
Brushes.Blue, margin, y, string_format);
}
// Draw a horizontal line.
y += 1.4f * Font.Height;
e.Graphics.DrawLine(Pens.Blue, margin, y,
margin + tabs.Sum() + 50, y);
y += 5;
// Draw the book entries.
using (Font font = new Font("Times New Roman", 11))
{
foreach (string line in lines)
{
e.Graphics.DrawString(line, font,
Brushes.Black, margin, y, string_format);
y += 1.2f * this.Font.Height;
}
}
}
}
The code sets the Graphics object's TextRenderingHint to AntiAlias so it produces smooth text. It then defines a tab-delimited header and some tab-delimited text data.
Next, the program creates a StringFormat object. It calls the object's SetTabStops method to define tab stops for drawn text. The first parameter to SetTabStops is an offset that is added to the first tab stop. The second parameter is an array of relative tab stop distances.
In other words, the X position of the first tab stop is the offset value plus the first value in the tab stop array. (The distances are specified in the units given by the Graphics object's PageUnit property.) The X position of the second tab stop is the X position of the first tab stop plus the second value in the array. And so on. (I'm not sure why an offset is included. You can set the offset to 0 and simply add any offset to the first tab stop value. That seems simpler.)
The code then creates a header font and draws the tab-delimited heading text. It increases the Y coordinate where it will draw next and draws a horizontal line under the headings. It then moves the Y coordinate down again to prepare to draw the text data.
Next, the code loops through the lines of text data drawing each and increasing the Y coordinate. The StringFormat object aligns the tab-delimited values so they line up below the column headings.
If you look at the picture above, you'll see that the data lines up nicely below the headings. Unfortunately, all of the values are aligned on the left and that may not be what you want. For example, you might like numeric values to line up on the right. (Trying to align the columns by setting the StringFormat object's Alignment and LineAlignment properties just makes things weird.)
In my next post, I'll show you how you can align different columns in different ways. It's more work but it's also more flexible.
Download the example to experiment with it and to see additional details.
|