如何使用aspose-words动态分页table

Hi Teams,
因为aspose-words是自动分页的,但是现在我需要满足这样的需求。在正文部分的table需要有table header和table footer。也就是每一页的header是一样的,table footer也是一样的,但是这样的话就需要动态计算总页数,然后分页。
请问该怎么实现呢?或者实现这样的Table数据还有其他的方式么? 非常感谢。

@imzdong

原因

要在使用 Aspose.Words 时实现动态分页的表格,并在每一页上添加相同的表头和表尾,您需要动态计算总页数。这是因为 Aspose.Words 默认情况下会自动处理分页,但在这种情况下,您需要手动控制分页以确保表格的表头和表尾在每一页上都能正确显示。

解决方案

您可以通过以下步骤来实现这一目标:

  1. 创建表格:首先,创建一个表格并添加数据。
  2. 添加表头和表尾:在表格中添加表头和表尾。
  3. 动态计算页数:使用 FieldNumPages 字段来动态获取文档的总页数。
  4. 分页处理:在生成文档时,确保在每一页上都插入表头和表尾。

代码示例

以下是一个简单的代码示例,展示了如何在 Aspose.Words 中实现动态分页的表格:

import com.aspose.words.*;

public class DynamicTablePagination {
    public static void main(String[] args) throws Exception {
        Document doc = new Document();
        DocumentBuilder builder = new DocumentBuilder(doc);

        // 创建表格
        Table table = builder.startTable();
        builder.insertCell();
        builder.write("Header 1");
        builder.insertCell();
        builder.write("Header 2");
        builder.endRow();

        // 添加数据行
        for (int i = 0; i < 100; i++) {
            builder.insertCell();
            builder.write("Row " + (i + 1) + " Col 1");
            builder.insertCell();
            builder.write("Row " + (i + 1) + " Col 2");
            builder.endRow();
        }
        builder.endTable();

        // 添加页码字段
        builder.insertField("NUMPAGES", null);

        // 保存文档
        doc.save("DynamicTablePagination.docx");
    }
}

后续步骤

  1. 运行上述代码以生成包含动态分页表格的文档。
  2. 根据需要调整表格的样式和内容。
  3. 如果需要,您可以进一步探索 Aspose.Words 的文档以获取更多关于表格和分页的高级功能。

如果您有任何其他问题或需要进一步的帮助,请随时告诉我!我将乐意为您提供支持。

我想要的是动态计算每页的值,去控制分页,因为每页最后一行需要特定的值,并且所有页是一样的。
不能用word的footer和header去实现,只能用table的行去实现。

like :

当分页,这两个都保持第二页也一样

@imzdong 表头可以通过 "重复作为表头行 "来实现。 您可以查看 https://docs.aspose.com/words/java/applying-formatting/. 但如果我没理解错的话,你需要在每一页上都有一个带页眉和页脚的表格,而且很难确定哪一行是每一页的最后一行。 如果不正确,能否请您提供预期结果的文档?

@vyacheslav.deryushev 感谢。
“表头可以通过 "重复作为表头行 "来实现” 感谢已经实现。
“你需要在每一页上都有一个带页眉和页脚的表格” 是的,我想要这样这么实现。但是不清楚如何实现表格的页脚。word的页脚是针对每一页的。我想实现的是表格的最后一行作为页脚。或者在每一页正文的最下面作为页脚(word 页脚的上面),
“而且很难确定哪一行是每一页的最后一行” 没有这个问题,应该是我描述的有误。

“能否请您提供预期结果的文档” 预期文档
Demo.docx (25.4 KB)

@imzdong 您可以使用 LayoutCollector | Aspose.Words for Java 计算当前行的页码,并在表格中插入页脚行。 以下是示例代码:

Document doc = new Document();
doc.getCompatibilityOptions().optimizeFor(MsWordVersion.WORD_2019);
DocumentBuilder builder = new DocumentBuilder(doc);

builder.startTable();

builder.insertCell();
builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
builder.write("Table 14.1.1.1.1");
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
Row row = builder.endRow();
row.getRowFormat().setHeadingFormat(true);
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);

// Row 2
builder.insertCell();
builder.write("Subject Disposition - Data from Part A");
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.endRow();
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);

// Row 3
builder.insertCell();
builder.write("(All Screened Subjects - Part A)");
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.endRow();
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);

// Row 4 (column headers)
builder.insertCell();
builder.write("");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("Total");
builder.endRow();

// Add more header cells for row 4 (continued)
builder.insertCell();
builder.write("");
builder.insertCell();
builder.write("2 mg BIW");
builder.insertCell();
builder.write("4 mg BIW");
builder.insertCell();
builder.write("2 mg/4 mg BIW");
builder.insertCell();
builder.write("1.2 mg QD");
builder.insertCell();
builder.write("(N=42)");
row = builder.endRow();
row.getRowFormat().setHeadingFormat(false);

builder.insertCell();
builder.write("");
builder.insertCell();
builder.write("(N=14)");
builder.insertCell();
builder.write("(N=14)");
builder.insertCell();
builder.write("(N=28)");
builder.insertCell();
builder.write("(N=14)");
builder.insertCell();
builder.write("");
builder.endRow();

for (int i = 0; i < 200; i++) {
    builder.insertCell();
    builder.write("Screen failed, n");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write(String.valueOf(i));
    builder.endRow();
}

addFooterRows(doc);

doc.save("output.docx");

public static void addFooterRows(Document doc) throws Exception {
    LayoutCollector layoutCollector = new LayoutCollector(doc);

    for (Table table : (Iterable<Table>) doc.getChildNodes(NodeType.TABLE, true)) {
        int currentPage = 1;
        int footerRowHeight = 4;
        for (Row row : table.getRows()) {
            if (layoutCollector.getStartPageIndex(row) > currentPage) {
                Row insertPoint = row.getPreviousRow();
                currentPage = layoutCollector.getStartPageIndex(row);

                Row footerRow = (Row)table.getFirstRow().deepClone(true);
                footerRow.getRowFormat().setHeadingFormat(false);
                Paragraph paragraph = footerRow.getCells().get(0).getFirstParagraph();
                paragraph.removeAllChildren();
                paragraph.getParagraphFormat().setAlignment(ParagraphAlignment.LEFT);
                paragraph.appendChild(new Run(doc, "Note: Percentages are calculated relative to the number of randomized subjects in the corresponding treatment group."));
                paragraph.appendChild(new Run(doc, ControlChar.LINE_BREAK));
                paragraph.appendChild(new Run(doc, "Note: Subjects who rolled over to the OLE are categorized as study completers."));
                paragraph.appendChild(new Run(doc, ControlChar.LINE_BREAK));
                paragraph.appendChild(new Run(doc, "Note: Time to treatment discontinuation due to an AE is calculated as date of treatment discontinuation – date of first dose + 1."));

                int rowIndex = table.indexOf(insertPoint);
                int currPoint = rowIndex - footerRowHeight;
                Row currRow = table.getRows().get(currPoint);
                currRow.getParentNode().insertBefore(footerRow, currRow);

                layoutCollector.clear();
                doc.updatePageLayout();
            }
        }
    }
}

@vyacheslav.deryushev 非常感谢哈,您提供的方案,非常棒。
但是还有两个小问题,1、row动态高度(自适应高度)。footer的计算就有问题。
2、最后一页如果只有几行。需要添加空行填充。把footer放到最后一行。

请问你针对这两个问题怎么解决呀?非常感谢?

@imzdong 遗憾的是,没有一种通用的方法可以保留所有值。 您可以尝试用以下代码计算默认字体和格式值,并使用 builder.getRowFormat().setAllowBreakAcrossPages(false);。 代码如下

Document doc = new Document();
doc.getCompatibilityOptions().optimizeFor(MsWordVersion.WORD_2019);
DocumentBuilder builder = new DocumentBuilder(doc);

Table table = builder.startTable();

builder.insertCell();
builder.getRowFormat().setAllowBreakAcrossPages(false);
builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
builder.write("Table 14.1.1.1.1");
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
Row row = builder.endRow();
row.getRowFormat().setHeadingFormat(true);
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);

// Row 2
builder.insertCell();
builder.write("Subject Disposition - Data from Part A");
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.endRow();
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);

// Row 3
builder.insertCell();
builder.write("(All Screened Subjects - Part A)");
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.endRow();
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);

// Row 4 (column headers)
builder.insertCell();
builder.write("");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("AL102");
builder.insertCell();
builder.write("Total");
builder.endRow();

// Add more header cells for row 4 (continued)
builder.insertCell();
builder.write("");
builder.insertCell();
builder.write("2 mg BIW");
builder.insertCell();
builder.write("4 mg BIW");
builder.insertCell();
builder.write("2 mg/4 mg BIW");
builder.insertCell();
builder.write("1.2 mg QD");
builder.insertCell();
builder.write("(N=42)");
row = builder.endRow();
row.getRowFormat().setHeadingFormat(false);

builder.insertCell();
builder.write("");
builder.insertCell();
builder.write("(N=14)");
builder.insertCell();
builder.write("(N=14)");
builder.insertCell();
builder.write("(N=28)");
builder.insertCell();
builder.write("(N=14)");
builder.insertCell();
builder.write("");
builder.endRow();

// Add content rows (these won't repeat)
for (int i = 0; i < 200; i++) {
    builder.insertCell();
    builder.write("Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, n Screen failed, nScreen failed, nScreen failed, nScreen failed, nScreen failed, nScreen failed, n");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write("");
    builder.insertCell();
    builder.write(String.valueOf(i));
    builder.endRow();
}

addFooterRows(doc);

doc.save(getArtifactsDir() + "output.docx");

public static void addFooterRows(Document doc) throws Exception {
    LayoutCollector layoutCollector = new LayoutCollector(doc);

    for (Table table : (Iterable<Table>) doc.getChildNodes(NodeType.TABLE, true)) {
        int currentPage = 1;
        for (Row row : table.getRows()) {
            if (layoutCollector.getStartPageIndex(row) > currentPage) {
                Row insertPoint = row.getPreviousRow();
                currentPage = layoutCollector.getStartPageIndex(row);

                Row footerRow = (Row)table.getFirstRow().deepClone(true);
                footerRow.getRowFormat().setHeadingFormat(false);
                Paragraph paragraph = footerRow.getCells().get(0).getFirstParagraph();
                paragraph.removeAllChildren();
                paragraph.getParagraphFormat().setAlignment(ParagraphAlignment.LEFT);
                paragraph.appendChild(new Run(doc, "Note: Percentages are calculated relative to the number of randomized subjects in the corresponding treatment group."));
                paragraph.appendChild(new Run(doc, ControlChar.LINE_BREAK));
                paragraph.appendChild(new Run(doc, "Note: Subjects who rolled over to the OLE are categorized as study completers."));
                paragraph.appendChild(new Run(doc, ControlChar.LINE_BREAK));
                paragraph.appendChild(new Run(doc, "Note: Time to treatment discontinuation due to an AE is calculated as date of treatment discontinuation – date of first dose + 1."));

                int insertRowHeight = (int) estimateRowHeightRatio(insertPoint);
                int footerRowHeight = (int) estimateRowHeightRatio(footerRow);

                int rowIndex = table.indexOf(insertPoint);
                int currPoint = rowIndex - (insertRowHeight - footerRowHeight);
                Row currRow = table.getRows().get(currPoint);
                currRow.getParentNode().insertBefore(footerRow, currRow);

                layoutCollector.clear();
                doc.updatePageLayout();
            }
        }
    }
}

public static double estimateRowHeightRatio(Row row) {
    // Define average line height in points (adjust based on your font size).
    final double LINE_HEIGHT = 15.0;
    final double PARAGRAPH_SPACING = 6.0;

    double totalHeight = 0;

    for (Paragraph para : (Iterable<Paragraph>) row.getChildNodes(NodeType.PARAGRAPH, true)) {
        // Estimate lines in this paragraph.
        int lineCount = (int)Math.ceil(para.getText().length() / 60.0); // ~60 chars per line.
        totalHeight += (lineCount * LINE_HEIGHT) + PARAGRAPH_SPACING;
    }

    // Standard row height (adjust based on your document).
    double standardHeight = LINE_HEIGHT * 1.5 + PARAGRAPH_SPACING;

    return Math.ceil(totalHeight / standardHeight);
}

此外,您还可以尝试使用 LayoutEnumerator Class | Aspose.Words for .NET 并根据矩形值进行计算。

至于最后一页,你也可以使用 LayoutCollector 插入新行,直到页面结束。 请注意,如果我们讨论的是大表格,使用这种方法会增加工作时间。