Sun Robin
Sun Robin

Reputation: 593

How to add cells vertically

Here we have a requirment. In a table, we need to add cells vertically. For example, a table may be like this.

Name Age   Name Age

Jim  11    Lily 9

Lucy 8     Tom  6

Lile 12

Leo  13

Firstly, it will add cells in the first column, when the first column is full, it will then add cells in the second column. All the data is from a dictionary.

Is there a simply way to add cells vertically? Otherwise, I have to add cells horizontally, but get data from dictionary by calculated order to achieve this goal.

Upvotes: 3

Views: 423

Answers (2)

Chris Haas
Chris Haas

Reputation: 55427

I just wanted to elaborate on @Alexis-Pigeon's answer with some code specific to C#. (Also, the C# port of iText appears to be missing the ColumnText.START_COLUMN constant which should be set to zero.)

The code below will lay text out into multiple columns top to bottom and then left to right (instead of a normal table which it left to right, top to bottom). Instead of hard-coding the table's dimensions it also calculates the table's location based on the document's margins as well as how many columns are desired and the gutter between columns. The latter two can be changed by changing the columnCount and gutterWidth properties towards the top.

Very important, this will not create table cells top to bottom left to right so that everything lines up perfectly. Instead, this will draw arbitrary text and when it can't fit at the bottom it will start over in the next column. This could happen right in the middle of paragraph. The code below just happens to line up perfectly but that's because the text is controlled. If you change the gutter from 50 to 20 you'll see how it breaks up weirdly.

See the code comments for specific details.

using (var fs = new FileStream(testFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
    using (var doc = new Document()) {
        using (var writer = PdfWriter.GetInstance(doc, fs)) {
            doc.Open();

            //Number of columns to create
            var columnCount = 4;

            //Distance be columns
            var gutterWidth = 20;

            //Setup and calculate some helper variables

            //The left-most edge
            var tableLeft = doc.LeftMargin;

            //The bottom-most edge
            var tableBottom = doc.BottomMargin;

            //The available width and height of the table taking into account the document's margins
            var tableWidth = doc.PageSize.Width - (doc.LeftMargin + doc.RightMargin);
            var tableHeight = doc.PageSize.Height - (doc.TopMargin + doc.BottomMargin);

            //The width of a column taking into account the gutters (three columns have two gutters total)
            var columnWidth = (tableWidth - (gutterWidth * (columnCount - 1))) / columnCount;

            //Create an array of columns
            var columns = new List<iTextSharp.text.Rectangle>();

            //Create one rectangle per column
            for (var i = 0; i < columnCount; i++) {
                columns.Add(new iTextSharp.text.Rectangle(
                        tableLeft + (columnWidth * i) + (gutterWidth * i),               //Left
                        tableBottom,                                                     //Bottom
                        tableLeft + (columnWidth * i) + (gutterWidth * i) + columnWidth, //Right
                        tableBottom + tableHeight                                        //Top
                        )
                   );
            }

            //Create our column text object
            var ct = new ColumnText(writer.DirectContent);

            //Create and set some placeholder copy
            for (var i = 0; i < 100; i++) {
                ct.AddText(new Phrase(String.Format("This is cell {0}. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris lorem tortor, condimentum non urna congue, tincidunt viverra elit.", i)));
                //Optional but helps to add spacing
                ct.AddText(Chunk.NEWLINE);
                ct.AddText(Chunk.NEWLINE);
            }

            //As we draw content below we'll loop through each column defined above
            //This holds the current column index that we'll change in the loop
            var currentColumnIndex = 0;

            //Current status as returned from ct.go()
            int status = 0; //START_COLUMN is defined in Java but is currently missing in .Net

            //Loop until we've drawn everything
            while (ColumnText.HasMoreText(status)) {

                //Setup our column
                ct.SetSimpleColumn(columns[currentColumnIndex]);

                //To be honest, not quite sure how this is used but I think it is related to leading
                ct.YLine = columns[currentColumnIndex].Top;

                //This actually "draws" the text and will return either 0, NO_MORE_TEXT (1) or NO_MORE_COLUMN(2)
                status = ct.Go();

                //Increment our current column index
                currentColumnIndex += 1;

                //If we're out of columns
                if (currentColumnIndex > (columns.Count - 1)) {

                    //Create a new page and reset to the first column
                    doc.NewPage();
                    currentColumnIndex = 0;
                }
            }

            doc.Close();
        }
    }
}

Upvotes: 1

Alexis Pigeon
Alexis Pigeon

Reputation: 7512

What you are looking for is the ColumnText class.

There are many examples available on the iText website, for example this one.

These examples are in Java, but the "translation" to C# should be straightforward.

Upvotes: 1

Related Questions