このページには自動翻訳されたテキストを含めることができます。

テーブル コンテナー

Table コンテナーを使って、最も複雑なデータをレイアウトします。テーブルは PDF ドキュメントで重要な役割を果たし、明瞭性と効果を高めます。

テーブルは、データを構造化して表示するための形式を提供します。複雑な詳細を簡潔で視覚的に魅力的な方法で提示できます。長い段落の代わりに、テーブルを使って事実、数値、傾向を簡潔に表示できます。

適切に設計されたテーブルは可読性を向上します。列と行を揃えることで、読者の視線を導く構造を作れます。背景、罫線、フォント スタイルを使って、特定のセルや見出しを強調できます。

テーブル コンテナー

LayoutContainer.Table メソッドを呼び出してテーブル コンテナーを取得します。次に、コンテナー内で少なくとも 1 つの列を定義する必要があります。最も単純なケースでは、Cell メソッドを複数回呼び出して、すべての列と行を埋められます。

列の定義方法、テーブルへのヘッダーやフッターの追加方法については、引き続きお読みください。この記事では、Table コンテナーの他のすべての機能についても説明します。

この記事は、PDF 生成用の Layout API に関するシリーズの一部です。API を初めて使う場合は、先に Getting Started with Layout API をお読みください。

列と行

すべてのテーブルでは、少なくとも 1 つの列を定義する必要があります。Table.Columns メソッドを使って列を定義します。このメソッドは Action<TableColumnContainer> 型のデリゲートを受け取ります。デリゲート内では、提供されるオブジェクトのメソッドを呼び出してテーブルに列を追加します。

ConstantColumn メソッドは、幅が正確なポイント数に等しい列を追加します。

RelativeColumn メソッドは、相対幅の列を追加します。このメソッドは、列が占める部品数を受け取ります。部品の合計数は、このテーブル内で呼び出されたすべての RelativeColumn の数値の合計です。ほとんどの場合、このメソッドは Row containerRelativeItem と同じように動作します。詳細な説明はリンクを参照してください。

行を明示的に定義する必要はありません。行数は列とセルのプロパティに依存します。セル数も行数に影響します。テーブルの高さが、すべての行の高さの合計より大きくなることもあります。行に含まれるセル数は、列数より少なくてもかまいません。また、列に含まれるセル数が、行数より少なくなることもあります。

PdfDocumentBuilder.Create().Generate("table-basic.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(300, 100);
        page.Content()
            .Padding(10)

            //.MinimalBox()

            .Border(b => b.Thickness(1).Color(new PdfRgbColor(250, 123, 5)))
            .Table(table =>
            {
                table.Columns(columns =>
                {
                    columns.ConstantColumn(100);
                    columns.RelativeColumn(1);
                    columns.RelativeColumn(3);
                });

                for (int i = 0; i < 10; i++)
                {
                    table.Cell()
                        .Border(b => b.Thickness(0.1))
                        .AlignCenter()
                        .Text($"Cell {i + 1}");
                }
            });
    });
});

コードの結果は table-basic.pdf で確認できます。

生成された PDF では、テーブルが親コンテナーの領域全体を占めます。領域を埋めるにはセル数が不足しています。MinimalBox の呼び出しのコメントを解除すると、テーブルの高さを各行の高さの合計に制限できます。

このコードでは 3 列を定義し、10 個のセルをテーブルに追加しています。テーブルはセルを順に配置し、必要に応じて新しい行を追加します。1 つのセルだけを含む行にしても問題ありません。

現在のページに十分な空きがない場合、テーブルはセルを次のページに配置します。追加するセル数を増やすと、これを確認できます。

セル

Layout API がテーブル セルの操作に対して提供する内容を説明します。

位置

テーブル セルを作成する方法は 2 つあります。

  • 明示的な位置情報を指定しない
  • 少なくとも一部の位置を指定する

前のセクションのコードでは、最初の方法を使いました。引数を受け取らない Cell メソッドのオーバーロードを呼び出します。このメソッドは、最後に追加されたセルの後ろの列に新しいセルを追加します。右側に空きがない場合、セルは次の行に移動します。RTL モードでは、最後に追加されたセルの左側に空きがあるかを確認します。

新しいセルの正確な位置が分かっている場合は、Cell メソッドの別のオーバーロードを使います。Action<TableCell> 型のデリゲートを受け取るものです。デリゲート内では、提供されるオブジェクトの RowIndexColumnIndex メソッドを呼び出して、セルの行と列インデックスを指定します。

新しいセルについて、行インデックスまたは列インデックスだけを指定することもできます。行インデックスだけを指定した場合、列インデックスは 0 です。逆も同様です。

セルを作成する際は、両方の Cell オーバーロードの呼び出しを任意の順序で組み合わせられます。

この記事の次のコード例では、以下の extension method を使います。これにより、例がより簡潔で読みやすくなります。

static class LayoutHelpers
{
    public static TextSpan BoxWithText(this LayoutContainer cell, string caption)
        => cell.Border(b => b.Thickness(0.5))
            .Background(new PdfGrayColor(75))
            .ShowOnce()
            .MinWidth(50)
            .MinHeight(50)
            .Padding(10)
            .AlignCenter()
            .AlignMiddle()
            .Text(caption);
}

次の例では、明示的に配置したセルと暗黙的に配置したセルの両方を含むテーブルを作成します。セルへのスタイル適用とテキスト設定には拡張メソッドを使っています。セル内の数字は、セルの作成順を表します。

PdfDocumentBuilder.Create().Generate("table-cells.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(300, 200);
        page.Content()
            .Padding(10)
            .MinimalBox()
            .Border(b => b.Thickness(0.1))
            .Table(table =>
            {
                table.Columns(columns =>
                {
                    for (int i = 0; i < 4; i++)
                        columns.RelativeColumn();
                });

                table.Cell().BoxWithText("1");
                table.Cell(c => c.RowIndex(1).ColumnIndex(1)).BoxWithText("2");
                table.Cell().BoxWithText("3");
                table.Cell(c => c.RowIndex(2).ColumnIndex(2)).BoxWithText("4");
                table.Cell(c => c.RowIndex(0).ColumnIndex(3)).BoxWithText("5");
            });
    });
});

コードの結果は table-cells.pdf で確認できます。

行と列のスパン

セルは複数の行および/または複数の列にまたがることができます。セルがまたがる行数と列数を指定するには、デリゲートを受け取る Cell のオーバーロードを使います。

PdfDocumentBuilder.Create().Generate("table-cellspans.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(300, 150);
        page.Content()
            .Padding(10)
            .MinimalBox()
            .Border(b => b.Thickness(0.1))
            .Table(table =>
            {
                table.Columns(columns =>
                {
                    for (int i = 0; i < 4; i++)
                        columns.RelativeColumn();
                });

                table.Cell(c => c.RowSpan(2).ColumnSpan(2)).BoxWithText("1");
                table.Cell(c => c.ColumnSpan(2)).BoxWithText("2");
                table.Cell().BoxWithText("3");
                table.Cell().BoxWithText("4");
            });
    });
});

コードの結果は table-cellspans.pdf で確認できます。

重なり

セル同士が重なることがあります。その場合、作成順によってどのセルが上に表示されるかが決まります。

セルが 1 列または 1 行を超えてまたがる場合、セルが重なることがあります。あるいは、セルを明示的配置と暗黙的配置の両方で行う場合もあります。

PdfDocumentBuilder.Create().Generate("table-overlapping.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(300, 300);
        page.Content()
            .Padding(10)
            .MinimalBox()
            .Border(b => b.Thickness(0.1))
            .Table(table =>
            {
                table.Columns(columns =>
                {
                    for (int i = 0; i < 4; i++)
                        columns.RelativeColumn();
                });

                for (int i = 0; i < 16; i++)
                    table.Cell().BoxWithText($"{i + 1}");

                table.Cell(c => c.RowIndex(2).ColumnIndex(1).ColumnSpan(3))
                    .Background(new PdfRgbColor(250, 123, 5), 50);
            });
    });
});

コードの結果は table-overlapping.pdf で確認できます。

下端まで拡張

テーブルのレイアウトが複雑な場合、ページ分割の仕組みにより、列の下部に空白が残ることがあります。空白をなくしたい場合は、ExtendCellsToBottom メソッドを使います。このメソッドは各列の最後のセルを下に延長し、セルがテーブルの下端で終わるようにします。

次の例では、1 ページ目に既定の動作を示します。2 ページ目では、ExtendCellsToBottom の呼び出しが列に与える影響を示します。

PdfDocumentBuilder.Create().Generate("table-extendcells.pdf", doc =>
{
    for (int take = 0; take < 2; take++)
    {
        doc.Pages(page =>
        {
            page.Size(300, 200);
            page.Content()
                .Padding(10)
                .MinimalBox()
                .Border(b => b.Thickness(0.1))
                .Table(table =>
                {
                    if (take != 0)
                        table.ExtendCellsToBottom();

                    table.Columns(columns =>
                    {
                        for (int i = 0; i < 4; i++)
                            columns.RelativeColumn();
                    });

                    table.Cell(c => c.RowIndex(0).ColumnIndex(0)).BoxWithText("1");
                    table.Cell(c => c.RowIndex(2).ColumnIndex(0)).BoxWithText("2");
                    table.Cell(c => c.RowIndex(1).ColumnIndex(1)).BoxWithText("3");
                    table.Cell(c => c.RowIndex(2).ColumnIndex(2)).BoxWithText("4");
                    table.Cell(c => c.RowIndex(1).ColumnIndex(3)).BoxWithText("5");
                });
        });
    }
});

コードの結果は table-extendcells.pdf で確認できます。

テーブルにはヘッダーとフッターを設定できます。対応する TableCellContainer にアクセスして設定するには、Header メソッドと Footer メソッドを使います。コンテナーには、セルを作成するための Cell メソッドがあります。これらのメソッドは、メインのテーブル コンテンツ用のメソッドとまったく同じように動作します。

ヘッダー、フッター、メインのテーブル セルは同じ列定義を使います。ただし、3 つのセル コレクションはすべて独立しており、互いに影響しません。

テーブルが 1 ページに収まらない場合、ヘッダーとフッターはテーブルが配置された各ページで繰り返されます。

前の例では BoxWithText 拡張メソッドを使いました。次のコードでは WhiteBoxWithText 拡張メソッドも使います。

static class LayoutHelpers
{
    public static TextSpan WhiteBoxWithText(
        this LayoutContainer cell, string caption, bool center = true)
    {
        return cell.Border(b => b.Thickness(0.5))
            .ShowOnce()
            .MinWidth(50)
            .MinHeight(50)
            .Padding(10)
            .Container(l => center ? l.AlignCenter() : l)
            .AlignMiddle()
            .Text(caption);
    }
}

次の例は、ヘッダー付きテーブルの作成方法を示します。ここでは、主要な化学元素 5 種を含むテーブルを使います。各元素について、名前と融点を摂氏およびケルビンで示します。

var elements = new (string Name, double Celsius, double Kelvin)[] {
    ("Oxygen", -218.79, 54.36),
    ("Carbon", double.NaN, double.NaN),
    ("Hydrogen", -259.16, 13.99),
    ("Nitrogen", -209.86, 63.23),
    ("Sulfur", 115.21, 388.36),
};

static string formatDouble(double val)
{
    return double.IsNaN(val)
        ? string.Empty
        : val.ToString(CultureInfo.InvariantCulture);
}

PdfDocumentBuilder.Create().Generate("table-header.pdf", doc =>
{
    doc.Pages(page =>
    {
        page.Size(400, 500);
        page.Content()
            .Padding(10)
            .MinimalBox()
            .Border(b => b.Thickness(0.1))
            .Table(table =>
            {
                table.Columns(columns =>
                {
                    columns.RelativeColumn();
                    columns.ConstantColumn(100);
                    columns.ConstantColumn(100);
                });

                table.Header(header =>
                {
                    header.Cell(c => c.RowSpan(2)).BoxWithText("Chemical element");
                    header.Cell(c => c.ColumnSpan(2)).BoxWithText("Melting point");

                    header.Cell().BoxWithText("Celsius");
                    header.Cell().BoxWithText("Kelvin");
                });

                foreach (var (Name, Celsius, Kelvin) in elements)
                {
                    table.Cell().WhiteBoxWithText(Name, false);

                    table.Cell().WhiteBoxWithText(formatDouble(Celsius));
                    table.Cell().WhiteBoxWithText(formatDouble(Kelvin));
                }
            });
    });
});

コードの結果は table-header.pdf で確認できます。

サンプル コード

PDF ドキュメントに表を追加する のサンプルもぜひ確認してください。ヘッダー付きテーブルの作成方法も示していますが、拡張メソッドは使用していません。VB.NET 版もあります。