写点什么

Java 操作 Office:POI word 之表格格式

发布于: 2 小时前
Java 操作 Office:POI word 之表格格式

系列文章:

Java 操作 Office:POI 之 word 生成

Java 操作 Office:POI 之 word 图片处理

Java 操作 Office:POI word 之网络图片处理


一 概述

小结失败。因为之前生成的 word 文档,表格格式不够美观,所以最近又花时间做了一些研究和调整。在这里分享一点不算经验的经验。

二 原来的效果

旧版效果如下图所示:

其实已经做了一点格式调整,就是单元格合并(横纵方向),一级宽度设置。但在编写代码时,经常发现一些基础宽度不生效,或者被文字挤掉之后,宽度显示异常的情况。所以最近抽时间又思考了一下,怎样合理的调整格式。

三 调整过程

3.1 预期效果

我们预期的效果,主要是试图固定前面几行的列宽,让最下面的"公司章程" 和 明细 这行保持相对合理的宽度。

3.2 基础设置

我们再看看表格的基础设置方法,首先还是定义一个 3 行 4 列的表格。为什么没有直接定义 7 行 4 列?这是因为开始的时候,曾经试图拆分成多个独立表格来实现效果,不过感觉是失败了。。 poi 有自动合并表格的操作。但出于方便调试的考虑,这里还是保留了拆分子表的设置。

XWPFTable table = doc.createTable(3, 4);TableTools.widthTable(table, MiniTableRenderData.WIDTH_A4_FULL, 4);
复制代码

先设置前 3 行,这 3 行的列宽样式是一致的。考虑设定第 1 列的宽度为文档宽度的 1/8,第 2 列的宽度为 3/8,第 3 列的宽度为文档宽度的 1/8,第 4 列的宽度为 3/8。

3.2.1 获取表格宽度

直接使用 table.getWidth()即可。

3.2.2 设置列宽度

XWPFTableCell 的 setWidth()方法,但需要注意的是,参数不是整数 或 浮点数,而是字符串。从下面代码中可以看出,最终是通过 CTTblWidth 对向设置列(表格)的宽度。


public void setWidth(String widthValue) {    XWPFTable.setWidthValue(widthValue, this.getTcWidth());}
复制代码


protected static void setWidthValue(String widthValue, CTTblWidth ctWidth) {    if (!widthValue.matches("auto|[0-9]+|[0-9]+(\\.[0-9]+)?%")) {        throw new RuntimeException("Table width value \"" + widthValue + "\" must match regular expression \"" + "auto|[0-9]+|[0-9]+(\\.[0-9]+)?%" + "\".");    } else {        if (widthValue.matches("auto")) {            ctWidth.setType(STTblWidth.AUTO);            ctWidth.setW(BigInteger.ZERO);        } else if (widthValue.matches("[0-9]+(\\.[0-9]+)?%")) {            setWidthPercentage(ctWidth, widthValue);        } else {            ctWidth.setW(new BigInteger(widthValue));            ctWidth.setType(STTblWidth.DXA);        }
}}
复制代码

3.2.3 设置列宽

下面我们执行设置如下:

int colWidth = table.getWidth() / 8;List<XWPFTableCell> row0 = table.getRow(0).getTableCells();row0.get(0).setText("xxxx");row0.get(0).setWidth(String.valueOf(colWidth));row0.get(1).setText("1111");row0.get(1).setWidth(String.valueOf(colWidth * 3));row0.get(2).setText("22222");row0.get(2).setWidth(String.valueOf(colWidth));row0.get(3).setText(nAppName);row0.get(3).setWidth(String.valueOf(colWidth * 3));
复制代码

3.3 明细子表设置

进入这里最复杂的地方,也就是怎样设置子表中各列(单元格)的宽度。我曾经试过按照上述 setWidth 的方式,但当这个子表也是采用 4 列的结构时,总会直接影响上面的 3 行,导致格式出错。想要把序号这列设置的窄一些,把剩余的空间分配给右侧两列,好让文字展示得更完整,分布更合理一些。在单独设置宽度无效的背景下,就想到能否通过把子表拆成更多列,然后通过部分单元格合并 和 重新设置宽度的方式,来避免对前 3 行产生影响。

基于这种想法,我们再次开始尝试。希望把序号列宽度降为之前的 1/2,"明细"列与前 3 行宽度相同。这样计算的话,列数设置为之前的 2 倍,也就是 8 个单元格:第 1 列 2 个,第 2 列 1 个,然后再结合宽度设置来处理剩余两列的宽度。几次调整后代码如下:

int size = 8;XWPFTable detailTable = doc.createTable(details.size(), size);TableTools.widthTable(detailTable, MiniTableRenderData.WIDTH_A4_FULL, size);TableTools.mergeCellsVertically(detailTable, 0, 0, details.size() - 1);for (int i = 0; i < details.size(); i++){    TableTools.mergeCellsHorizonal(detailTable, i, 0, 1);    Detail item = details.get(i);    List<XWPFTableCell> detailTableRow = detailTable.getRow(i).getTableCells();    detailTableRow.get(0).setText("明细");    detailTableRow.get(0).setWidth(String.valueOf(colWidth));    detailTableRow.get(1).setText("斤斤计较斤斤计较斤斤计较斤斤计较急急急急急急");    detailTableRow.get(1).setWidth(String.valueOf(colWidth / 2));    TableTools.mergeCellsHorizonal(detailTable, i, 2, 5);    detailTableRow.get(2).setText("111111111111111");    detailTableRow.get(2).setWidth(String.valueOf(colWidth * 3));    detailTableRow.get(3).setText("xxxxxhhhhhhhhhhhhh哈哈哈哈哈哈哈");    detailTableRow.get(3).setWidth(String.valueOf(colWidth * 3));}
复制代码

3.4 调整后效果

调整之后,看起来比之前好了很多。但实际上前 3 行还是受到了影响。只是样式稍好了一些。由于项目时间的原因,来不及再做优化了,就暂时保留了这种样式。

四 总结

大家可以看到,手写 word 表格格式还是很麻烦,最理想的方式还是通过模板,代码中执行内容替换的方式来生成,这样在样式的控制上会好很多。但真遇到比较麻烦的项目需求时,就只能硬上了。这时也需要进行多次尝试,来获取较好的效果。

发布于: 2 小时前阅读数: 3
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
Java 操作 Office:POI word 之表格格式