表格行真正高度获取

我发现我获取不到表格中每一行的真正高度。
当单元格有内容或者内容太长,转换出来的文件是会自动换行的,但是我都获取不到表格行的高度,下面这个我获取到的都是0.0。
问题:我需要怎么做才能获取到表格当前行的真正高度呢

@GetMapping("/test3")
    public void test3() throws Exception {
        String rootPath = Objects.requireNonNull(this.getClass().getResource("/")).getPath() + "templates/";
        Document document = new Document(Files.newInputStream(new File(rootPath + "表格.docx").toPath()));
        Table table = (Table) document.getChild(NodeType.TABLE, 0, true);
        for (Row row : table.getRows()) {
            System.out.println("高度: " + row.getRowFormat().getHeight());
        }
    }

输出.png (972 Bytes)
模板.docx (10.6 KB)

@magua, Word 文档中未指定行高。 因此,您无法使用 RowFormat.getHeight() 方法获取行高。

在您的情况下,实际行高是在渲染 Word 文档时计算的。 要获取高度,您可以使用 LayoutCollectorLayoutEnumerator 类,如下例所示:

Document document = new Document("表格.docx");
LayoutCollector collector = new LayoutCollector(document);
LayoutEnumerator enumerator = new LayoutEnumerator(document);

Table table = (Table) document.getChild(NodeType.TABLE, 0, true);

// Move to the first row.
enumerator.setCurrent(collector.getEntity(table.getFirstRow().getFirstCell().getFirstParagraph()));
while (enumerator.getType()!= LayoutEntityType.ROW)
    enumerator.moveParent();

do {
    String left = String.format("%.2f", enumerator.getRectangle().getX());
    String top = String.format("%.2f", enumerator.getRectangle().getY());
    String width = String.format("%.2f", enumerator.getRectangle().getWidth());
    String height = String.format("%.2f", enumerator.getRectangle().getHeight());

    System.out.print("[(x, y) = (" + left + ", " + top + ")]");
    System.out.println(" AND [(width, height) = (" + width + ", " + height + ")]");
} while (enumerator.moveNext() && enumerator.getType() == LayoutEntityType.ROW);

您好,我发现在没有创建 LayoutEnumerator 这个这个对象的时候是可以正常设置页面大小的,但是创建了 LayoutEnumerator 这个对象就不能设置高度跟宽度了,这个要怎么解决呢。使用的版本是18.6

        String rootPath = Objects.requireNonNull(this.getClass().getResource("/")).getPath() + "templates/";
        Document document = new Document(Files.newInputStream(new File(rootPath + "表格.docx").toPath()));
        LayoutCollector collector = new LayoutCollector(document);
        LayoutEnumerator enumerator = new LayoutEnumerator(document);

        Section section = document.getSections().get(0);
        section.getPageSetup().setPageWidth(595.275590551181);
        section.getPageSetup().setPageHeight(396.8503937007874);

        OutputStream out = Files.newOutputStream(new File(rootPath + "test.pdf").toPath());
        document.save(out, SaveFormat.PDF);
        out.close();

存在LayoutEnumerator对象.pdf (28.5 KB)
不存在LayoutEnumerator对象.pdf (28.5 KB)

@magua, 如果在创建 LayoutCollector 实例后对 Document 类实例进行了任何更改,则需要调用 LayoutCollector.clear() 和 doc.UpdateLayout() 方法。 实际上,我们文档中的 LayoutCollector.clear() 示例中提到了这一点:

Document document = new Document("表格.docx");
LayoutCollector collector = new LayoutCollector(document);
LayoutEnumerator enumerator = new LayoutEnumerator(document);

Section section = document.getSections().get(0);
section.getPageSetup().setPageWidth(595.275590551181);
section.getPageSetup().setPageHeight(396.8503937007874);

collector.clear();
document.updatePageLayout();

document.save("out.pdf");

在最简单的情况下,您可以在对文档进行更改后创建 LayoutCollector 和 LayoutEnumerator 的实例:

Document document = new Document("表格.docx");

Section section = document.getSections().get(0);
section.getPageSetup().setPageWidth(595.275590551181);
section.getPageSetup().setPageHeight(396.8503937007874);

LayoutCollector collector = new LayoutCollector(document);
LayoutEnumerator enumerator = new LayoutEnumerator(document);

document.save("out.pdf");

您好,我发现当表格比较高的时候好像定位有点问题,我这边出现了表格最后一行的 Y 轴点位是小于表格高度的,然后我是通过定位到表格的最后一行去设置页面高度的,结果导致页面由一页变成两页了。

@GetMapping("/test4")
    public void test4() throws Exception {
        AsposeWordUtils.getWordLicense();
        String rootPath = Objects.requireNonNull(this.getClass().getResource("/")).getPath() + "templates/";
        Document document = new Document(Files.newInputStream(new File(rootPath + "测试模板.docx").toPath()));

        /* 1.填充数据 */
        List<Map<String, String>> dataSet = new ArrayList<>();
        MailMerge merge = document.getMailMerge();
        for (int i = 0; i < 9; i++) {
            HashMap<String, String> hashMap = new HashMap<>(1);
            hashMap.put("Name", "测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试");
            dataSet.add(hashMap);
        }
        DataTable dataTable = new DataTable("List");
        for (int i = 0; i < dataSet.size(); i++) {
            // 加上填充数据的字段
            if (i == 0) {
                for (String key : dataSet.get(0).keySet()) {
                    dataTable.getColumns().add(key);
                }
            }

            // 写入数据
            DataRow dataRow = dataTable.newRow();
            for (DataColumn dc : dataTable.getColumns()) {
                if (dataSet.get(i).containsKey(dc.getColumnName())) {
                    String columnName = dc.getColumnName();
                    Object o = dataSet.get(i).get(dc.getColumnName());
                    if (o != null) {
                        String value = o.toString();
                        dataRow.set(columnName, value);
                    }
                }
            }
            dataTable.getRows().add(dataRow);
        }
        merge.executeWithRegions(dataTable);

        /* 2.根据表格设置页面高度 */
        LayoutCollector collector = new LayoutCollector(document);
        LayoutEnumerator enumerator = new LayoutEnumerator(document);

        Table table = (Table) document.getChild(NodeType.TABLE, 0, true);

        // 移动到第一行
        enumerator.setCurrent(collector.getEntity(table.getFirstRow().getFirstCell().getFirstParagraph()));
        while (enumerator.getType()!= LayoutEntityType.ROW) {
            enumerator.moveParent();
        }
        // 记录表格最后一行的 Y 轴
        double lastY;
        // 存放表格每一行的高度
        List<Double> rowsHeight = new ArrayList<>();
        do {
            lastY = enumerator.getRectangle().getY();
            rowsHeight.add(enumerator.getRectangle().getHeight());
        } while (enumerator.moveNext() && enumerator.getType() == LayoutEntityType.ROW);
        // 计算表格真正的高度
        double tableHeight = 0.0d;
        for (Double aDouble : rowsHeight) {
            tableHeight = tableHeight + aDouble;
        }
        System.out.println("表格末尾位置: " + lastY + ", 表格高度: " + tableHeight);
        document.getFirstSection().getPageSetup().setPageHeight(lastY + 35.00d);
        collector.clear();
        document.updatePageLayout();

        /* 3.保存文件 */
        OutputStream out = Files.newOutputStream(new File(rootPath + "test.pdf").toPath());
        document.save(out, SaveFormat.PDF);
        out.close();
    }

image.png (3.6 KB)
测试模板.docx (17.9 KB)

@magua, 您能解释一下预期结果是什么吗? 您是否希望在表格填满数据后通过调整页面大小来将表格调整为一页?

对的,我的预期结果就是获取表格的最后一行的位置,然后根据这个点位设置页面的高度,达到让这个表格在第一个页面上,不出现换页的情况

@magua, 我稍微改变了你的代码。 请检查更新后的代码是否产生适当的结果。

Document document = new Document("表格.docx");

LayoutCollector collector = new LayoutCollector(document);
LayoutEnumerator enumerator = new LayoutEnumerator(document);

// Get the first row Y.
Table table = (Table) document.getChild(NodeType.TABLE, 0, true);
enumerator.setCurrent(collector.getEntity(table.getFirstRow().getFirstCell().getFirstParagraph()));
while (enumerator.getType()!= LayoutEntityType.ROW) {
    enumerator.moveParent();
}
double firstY = enumerator.getRectangle().getY();

/* 1.填充数据 */
ArrayList<Map<String, String>> dataSet = new ArrayList<>();
MailMerge merge = document.getMailMerge();
for (int i = 0; i < 9; i++) {
    HashMap<String, String> hashMap = new HashMap<>(1);
    hashMap.put("Name", "测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试");
    dataSet.add(hashMap);
}
DataTable dataTable = new DataTable("List");
for (int i = 0; i < dataSet.size(); i++) {
    // 加上填充数据的字段
    if (i == 0) {
        for (String key : dataSet.get(0).keySet()) {
            dataTable.getColumns().add(key);
        }
    }

    // 写入数据
    DataRow dataRow = dataTable.newRow();
    for (DataColumn dc : dataTable.getColumns()) {
        if (dataSet.get(i).containsKey(dc.getColumnName())) {
            String columnName = dc.getColumnName();
            Object o = dataSet.get(i).get(dc.getColumnName());
            if (o != null) {
                String value = o.toString();
                dataRow.set(columnName, value);
            }
        }
    }
    dataTable.getRows().add(dataRow);
}
merge.executeWithRegions(dataTable);

/* 2.根据表格设置页面高度 */
collector.clear();
document.updatePageLayout();

// 移动到第一行
enumerator.setCurrent(collector.getEntity(table.getFirstRow().getFirstCell().getFirstParagraph()));
while (enumerator.getType()!= LayoutEntityType.ROW) {
    enumerator.moveParent();
}

// 记录表格最后一行的 Y 轴
double lastY;
// 存放表格每一行的高度
ArrayList<Double> rowsHeight = new ArrayList<>();
do {
    lastY = enumerator.getRectangle().getY();
    rowsHeight.add(enumerator.getRectangle().getHeight());
} while (enumerator.moveNext() && enumerator.getType() == LayoutEntityType.ROW);
// 计算表格真正的高度
double tableHeight = 0.0d;
for (Double aDouble : rowsHeight) {
    tableHeight = tableHeight + aDouble;
}

System.out.println("表格末尾位置: " + lastY + ", 表格高度: " + tableHeight);

// Compute and set the new page height.
double newPageHeight = firstY + tableHeight;
document.getFirstSection().getPageSetup().setPageHeight(newPageHeight);

// Rebuild document layout after the page height change.
document.updatePageLayout();

/* 3.保存文件 */
document.save("out.pdf");

好的,非常感谢您的解答。

对于这一段来说,当动态添加表格数据行的时候,我能获取该行的高度吗。
或者说是,我希望创建出来的dataTable这个表格不超过当前页面,让我能够知道 dataSet 是在哪个位置停的

@magua, 您可能可以实现 IFieldMergingCallback.fieldMerging 方法,该方法在每次插入合并字段时调用。 在这个方法中,您可以更新文档布局,获取表格的高度并检查它是否超过页面高度。 但是,从 fieldMerging 方法停止正在进行的邮件合并过程的唯一方法是抛出异常。 这看起来不是一个好的解决方案,但它可以用作解决方法。

在引发异常之前,您可以计算页面适合的行数。 抛出异常后,您可以重新启动邮件合并过程并仅插入所需数量的行。

这是 fieldMering 方法的示例:

MailMerge merge = document.getMailMerge();

merge.setFieldMergingCallback(new IFieldMergingCallback() {
    @Override
    public void fieldMerging(FieldMergingArgs args) throws Exception {
        collector.clear();
        document.updatePageLayout();
        enumerator.setCurrent(collector.getEntity(table.getLastRow().getFirstCell().getFirstParagraph()));
        while (enumerator.getType()!= LayoutEntityType.ROW) {
            enumerator.moveParent();
        }
        double rowY = enumerator.getRectangle().getY();
        int rowIndex = args.getRecordIndex() + 1;
        if (rowY  < pageHeight - 100d) {
            System.out.println(rowIndex + ": Y: " + rowY);
        } else {
            throw new Exception();
        }
    }

    @Override
    public void imageFieldMerging(ImageFieldMergingArgs imageFieldMergingArgs) throws Exception {
    }
});