Fayaz
Fayaz

Reputation: 113

C# printing with spaces/indent

Hi I am trying to print a bill/receipt using a receipt printer from C# application.

The intended output is like this:

ITEM NAME                 QTY     PRICE
Banana Large Yellow        1       2.00
Brie Cheese 6 pack round   3      30.00
Indian Mango Box          10     246.00

The names, quantity and price need to be aligned in a straight line, irrespective of the number of characters in the item name, qty or price.

I have been using String.Format function, but the output is often not aligned, and get's spaced depending on the item name length etc.

ITEM NAME                 QTY     PRICE
Banana Large Yellow        1       2.00
Brie Cheese 6 pack round     3      30.00
Indian Mango Box        10    246.00

How can to fix this?

Code that I have used was

test_string = "-------------------------------\r\n";
        test_string += "First Name | Last Name  |   Age\r\n";
        test_string += String.Format("{0,-10} | {1,-10} | {2,5}", "Bill", "Gates", 51) + "\r\n";
        test_string += String.Format("{0,-10} | {1,-10} | {2,5}", "Edna", "Parker", 114) + "\r\n";
        test_string += String.Format("{0,-10} | {1,-10} | {2,5}", "Johnny", "Depp", 44) + "\r\n";

I am using following print code

StringFormat format = new StringFormat();
        format.Alignment = StringAlignment.Center;      // Horizontal Alignment 

        StringFormat right = new StringFormat();
        right.Alignment = StringAlignment.Far; 

        // Measure string.
        SizeF stringSize = new SizeF();
        pd.PrintPage += delegate(object sender, PrintPageEventArgs e)
            {
                string measureString = data;
                Font stringFont = new Font("Arial", 16);


                stringSize = e.Graphics.MeasureString(measureString, stringFont);

                RectangleF rect = new RectangleF(0, height_value, pd.DefaultPageSettings.PrintableArea.Width, pd.DefaultPageSettings.PrintableArea.Height);                   
                if (weight == "bold")
                {
                    if (alignment == "center")
                    {
                        e.Graphics.DrawString(data, new Font(font, 11, System.Drawing.FontStyle.Bold), new SolidBrush(System.Drawing.Color.Black), rect, format);
                    }
                    else
                    {
                        e.Graphics.DrawString(data, new Font(font, 11, System.Drawing.FontStyle.Bold), new SolidBrush(System.Drawing.Color.Black), rect);
                    }
                }
                else
                {
                    if (alignment == "center")
                    {
                        e.Graphics.DrawString(data, new Font(font, 11), new SolidBrush(System.Drawing.Color.Black), rect, format);
                    }
                    else if (alignment == "right")
                    {
                        e.Graphics.DrawString(data, new Font(font, 11), new SolidBrush(System.Drawing.Color.Black), rect, right);                           
                    }
                    else
                    {
                        e.Graphics.DrawString(data, new Font(font, 11), new SolidBrush(System.Drawing.Color.Black), rect);
                    }

                }
                height_value = Convert.ToInt32(stringSize.Height) + height_value;
            };

In the above print code I am passing data as

public string Test()
    {
        string[] names = { "Banana Large Yellow", "Brie Cheese", "Indian Mango Box" };
        int[] quantities = { 1, 3, 10 };
        decimal[] prices = { 2.00m, 30.00m, 246.00m };

        string format = "{0,-25} {1,-10} {2,5}" + Environment.NewLine;
        var stringBuilder = new StringBuilder().AppendFormat(format, "Item Name", "QTY", "Price");
        for (int i = 0; i < names.Length; i++)
        {
            stringBuilder.AppendFormat(format, names[i], quantities[i], prices[i]);
        }

     PrintFormat(stringBuilder.ToString(), "Arial", "normal", "left", 20);
    }

Upvotes: 1

Views: 11814

Answers (3)

LeBaptiste
LeBaptiste

Reputation: 1186

Have a closer look at Alignment component, you need to increased the first position values, as your strings are longer than 10 chars, give a try with -25.

using System;
using System.Text;

public class Example
{
   public static void Main()
   {

      string[] names = { "Banana Large Yellow", "Brie Cheese", "Indian Mango Box"};
      int[] quantities = { 1,3,10}; 
      decimal[] prices = { 2.00m, 30.00m, 246.00m};

      string format = "{0,-25} {1,-10} {2,10}" + Environment.NewLine;
      var stringBuilder = new StringBuilder().AppendFormat(format, "Item Name", "QTY", "Price");
      for (int i = 0; i < names.Length; i++)
      {
          stringBuilder.AppendFormat(format, names[i], quantities[i], prices[i]);
      }

      Console.WriteLine(stringBuilder.ToString());

   }
}

Item Name                 QTY             Price
Banana Large Yellow       1                2.00
Brie Cheese               3               30.00
Indian Mango Box          10             246.00

Also do not use string concatenation if you are looping on collection, use StringBuilder.

I would advise to use directly Environment.NewLine.

Upvotes: 4

Liren Yeo
Liren Yeo

Reputation: 3451

Use String.PadRight(int). Refer to my code below, I used List to store the elements but it should work the same for array.

Pay attention to padValue1,2 and 3, obtain the padding value for each column dynamically by matching the length of longest word. I added 2 extra spaces after that.

Then before you print out the string, add .PadRight(padValue).

static void Main(string[] args)
{
    string itemNameTitle = "ITEM NAME";
    string qtyTitle = "QTY";
    string priceTitle = "PRICE";

    List<string> itemName = new List<string> { "Banana Large Yellow", "Brie Cheese 6 pack round", "Indian Mango Box"};
    List<string> qty = new List<string> { "1", "3", "10" };
    List<string> price = new List<string> { "2.00", "30.00", "246.00" };

    //Insert titles into first positions of Lists
    itemName.Insert(0, itemNameTitle);
    qty.Insert(0, qtyTitle);
    price.Insert(0, priceTitle);

    //Dynamically get number of spaces according to longest word length + 2
    int padValue1 = itemName.OrderByDescending(s => s.Length).First().Length + 2;
    int padValue2 = qty.OrderByDescending(s => s.Length).First().Length + 2;
    int padValue3 = price.OrderByDescending(s => s.Length).First().Length + 2;

    for (int i = 0; i < itemName.Count; i++)
    {
        Console.Write(itemName[i].PadRight(padValue1));
        Console.Write(qty[i].PadRight(padValue2));
        Console.Write(price[i]);
        Console.Write(Environment.NewLine);
    }
}

Upvotes: 1

Ivan Gritsenko
Ivan Gritsenko

Reputation: 4236

In order to print data in table-like structure you can use string.Format using format item with width and alignment.

Let's have a look how it works:

// in comments underscores mean spaces
Console.WriteLine("Res:{0,6}.", 12345); //   Res:_12345.
Console.WriteLine("Res:{0,-6}.", 12345); //  Res:12345_.

But what if the resulting string length is longer than the specified width? Then the result will be printed as if there was no alignment and width at all.

Console.WriteLine("Res:{0,-6}", 123456789); //  Res:123456789.
Console.WriteLine("Res:{0,6}.", 123456789); //  Res:123456789.

So in order to solve your problem first define the maximum length of the resulting strings in each of your column and use this value as a width.

I have used the code that you have suggested but I did not get the Hours values with proper alignment in print out.I am concatenating string instead of Consol.WriteLine and out side the for loop I am passing it to printer

You should better use StringBuilder.AppendFormat. It works with format items just like String.Format or Console.WriteLine.

Upvotes: 3

Related Questions