在我们的学生时代,我们经常需要完成各种考试题目。对于卷子这种形式,我们并不陌生,因为它伴随着我们从小学到大学的学习生涯。通常情况下,卷子采用 A3 格式的横向布局,以 Word 文档的形式呈现。一页卷子被分成两栏,每栏下方通常都有一个包含页码的页脚。
本篇帮助文档将介绍如何使用 Spire.Doc for Java 将 A4 格式的纵向的 Word 文档变成横向的分栏 A3 文档,并为每栏设置页码页脚。实现效果图如下:
由于本篇是一篇综合性的帮助文档,本文主要还是介绍如何给每栏插入包含页码的页脚,对于插入页码和分栏可以点击下面链接访问相关文档做一个简单了解。
安装 Spire.Doc for Java
首先,您需要在 Java 程序中添加 Spire.Doc.jar 文件作为依赖项。您可以从此链接下载 JAR 文件;如果您使用 Maven,则可以通过在 pom.xml 文件中添加以下代码导入 JAR 文件。
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc</artifactId>
<version>12.9.4</version>
</dependency>
</dependencies>
逻辑分析
由于页脚设置页码和总页数用到了两个域,Page 和 Num_Pages。但分栏的两部分内容始终在同一页上,获取到的页码也都是相同的,必须要进行一些计算处理才能达到预期的效果。
如果把所有分栏从开始到结束排列起来,那么可以很轻易得出,奇数栏实际的页码应该是 “2*当前 Word 页码-1“,偶数栏实际的页码应该是 “2*当前 Word 页码”,总页码应该是 “2*Word 总页数”。因此,现在存在两个主要问题:
- 1、如何利用页码域(Page)和总页数域(Num_Pages)来完成上述的计算?
- 2、如何让同一页里,两个页码部分左右排列以达到下面截图效果?要知道如果 Paragraph 是没有这种对齐方式的。
好,我们带着这两个问题,继续往下吧!
解决问题1:利用嵌套域的方式完成
在一个表达式域中嵌套页码域,并让页码域获取的值参与表达式的计算。即达到 “{=2*{page}-1 }” 或者 “{=2*{page} }” 的效果。
那么如何实现表达式域嵌套页码域呢?首先需要了解的是一个完整的 Field 的构成应该是 Field+FieldMark(分隔符)+FieldMark(结束符)。并且,分隔符和结束符应该相邻;Field 和分隔符之间,可以嵌套其他的域。因此在表达式域中嵌套页码域完整表达如下:
Field(表达式域)
+Field(页码域)+FieldMark(页码域的分隔符)+FieldMark(页码域的结束符)
+FieldMark(表达式域的分隔符)+FieldMark(表达式域的结束符)
解决问题2:利用 Table 来达到需要的效果
在页脚中添加一个一行两列的不带边框的 Table,把两个分栏的页码部分分别放置于两个单元格中,再分别居中对齐。这样便可达到需要的效果。
关于表格的帮助文档,可以从下面链接中查看更多:表格帮助文档
关键方法
Spire.Doc for Java 提供了 Field 类用于处理域。
方法 | 方法解释 |
new Field(Document) | 实例化一个 Field,构造方法中要传入 Document 对象 |
Field.setType(FieldType) | 设置 Field 类型,这里我们需要用到3种域的类型,分别是:FieldType.Field_Expression(表达式域)、FieldType.Field_Page(页码域)、FieldType.Field_Num_Pages(总页数域) |
Field.setEnd(FieldMark) | 设置 Field 的结束符,将结束符实例作为参数 |
Spire.Doc for Java 提供了 FieldMark 类用于处理域的分隔符和结束符。
方法 | 方法解释 |
new FieldMark(Document,FieldMarkType) | 实例化一个 FieldMark,构造方法中要传入 Document 和 FieldMarkType 对象,这里需要用到2个种类型,分别是:FieldMarkType.Field_Separator(分隔符)、FieldMarkType.Field_End(结束符) |
最后将,将添加的页码域或者总页数域 Field 和 FieldMark 按照上面提到的嵌套顺序插入到段落中即可。
方法 | 方法解释 |
Paragraph.getItem().add() | 方法参数传入 Field 和 FieldMark 实例 |
详细步骤
下面介绍如何将 A4 格式的 Word 文档变成横向的分栏 A3 文档,并为每栏设置页码页脚。本 Demo 代码除主方法(Main)外,另写了 addPage() 方法来处理页码这一块的逻辑,因为需要多次插入分隔符和结束符,所以写 insertFieldMark() 方法来简化代码。另本次操作的 Word 文档只有一个 Section。
Main() 方法
- 创建 Document 类的实例。
- 使用 Document->loadFromFile() 方法加载 Word 文档。
- 使用 Document.getSections().get(0) 方法获取第一个 Section。
- 使用 section.getPageSetup().setPageSize(PageSize.A3) 将页面设置为 A3 大小。
- 使用 section.getPageSetup().setOrientation(PageOrientation.Landscape) 方法将页面方向设置为横向。
- 使用 section.addColumn(0,0) 方法将文档设置为1页2栏。
- 使用 section.getHeadersFooters().getFooter() 获取页脚对象。
- 使用 HeaderFooter.getChildObjects().clear() 方法清空页脚原有内容。
- 使用 HeaderFooter.addTable(false) 方法添加一个没有边框的表格来排版页码,参数为 true 时就是添加有边框的表格。
- 使用 HeaderFooter.resetCells(1,2) 方法将表格设置为一行两列。
- 调用 自定义的 addPage() 方法在表格中添加页码。
- 最后使用 Document .saveToFile() 方法保存结果文档。
addPage (Paragraph footerParagraph, Document document,String direction) 方法
- 参数1:是添加表格单元格中的段落,用于添加域。
- 参数2:文档对象,创建域实例时作为构造方法的参数。
- 参数3:左右两栏的页码的表达式域的写法不一样,需要区分开。
下面代码实现 “第y页 共x页” 的效果
- 使用 footerParagraph.appendText("第 ") 方法插入文本到段落。
- 创建域实例并设置域类型为表达式域:
- 设置域代码:Field.setCode("=2*")
- 使用 footerParagraph.getItems().add(Field) 方法将表达式域添加到段落。
- 创建域并设置域类型为页码域:
- 使用 footerParagraph.getItems().add(Field) 方法将页码域添加到段落。
- 调用 insertFieldMark() 方法插入页码域的分隔符和结束符。
- 判断 direction 值是否为 “Left”,为 true 时,需要使用代码:
- 调用 insertFieldMark() 方法插入表达式域的分隔符和结束符。
Field field = new Field(document);
field. setType(FieldType.Field_Expression);
Field field = new Field(document);
field. setType(FieldType.Field_Page);
footerParagraph.appendText("-1");
到此已经完成了对 “第y页” 效果的实现,后面 “共x页” 实现步骤类似,就不重复了。
insertFieldMark(Document document,Paragraph paragraph, Field field) 方法
- 参数1:文档对象,创建 FieldMark 实例时需要。
- 参数2:段落对象,新建的 FieldMark 插入到段落中。
- 参数3:域对象,结束符 FieldMark 对应的域。
- 创建 FieldMark 分隔符 实例
- 使用 paragraph.getItems().add(FieldMark) 方法将分隔符插入到段落。
- 创建 FieldMark 结束符实例
- 使用 paragraph.getItems().add(FieldMark) 方法将结束符插入到段落。
- 使用 Field.setEnd(FieldMark) 方法将结束符设置给对应域。
FieldMark fieldMark = new FieldMark(document,FieldMarkType.Field_Separator);
FieldMark FieldMark = new FieldMark(document,FieldMarkType.Field_End);
- Java
import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
//加载源文档
Document doc = new Document();
doc.loadFromFile("data/考试题.docx");
//获取第一个Section
Section section = doc.getSections().get(0);
//设置页面大小A3并将页面设置为横向
section.getPageSetup().setPageSize(PageSize.A3);
section.getPageSetup().setOrientation(PageOrientation.Landscape);
//分栏
section.addColumn(0,0);
//获取页脚并清空页脚内容
HeaderFooter footer = section.getHeadersFooters().getFooter();
footer.getChildObjects().clear();
//页脚中插入一行二列的表格
Table table=footer.addTable(false);
table.resetCells(1,2);
//左分栏页码
addPage(table.get(0,0).addParagraph(),doc,"Left");
//右分栏页码
addPage(table.get(0,1).addParagraph(),doc,"Right");
//保存结果文档
doc.saveToFile("output/分栏word加页码.docx",FileFormat.Docx);
}
public static void addPage(Paragraph footerParagraph, Document document,String direction) {
//添加文本、节域、页码域到段落 第1页,共7页
footerParagraph.appendText("第 ");
//自定义域代码。表达式域嵌套页码域 完成页码计算
//创建表达式域
Field currentPage_Field =new Field(document);
currentPage_Field.setType(FieldType.Field_Expression);
//设置前半部分域代码
currentPage_Field.setCode("=2*");
//添加到段落中
footerParagraph.getItems().add(currentPage_Field);
//创建嵌入表达式域中的页码域(获取当前页码)
Field fieldPage=new Field(document);
fieldPage.setType(FieldType.Field_Page);
//添加到段落中
footerParagraph.getItems().add(fieldPage);
//给页码域设置“域分隔符标志”和“域结束标志”
insertFieldMark(document,footerParagraph,fieldPage);
//判断是左侧分栏页码还是右侧,如果是左侧,则追加域代码"减一"即"-1"
//左侧分栏页码对应计算表达式应该是 2*page-1
//右侧分栏页码对应计算表达式应该是 2*page
//page表示当前页码
if(direction.equals("Left")){
footerParagraph.appendText("-1");
}
//给页码域设置“域分隔符标志”和“域结束标志”
insertFieldMark(document,footerParagraph,currentPage_Field);
footerParagraph.appendText(" 页,共 ");
//添加嵌套“总页数”的表达式域
Field totalPage_Field = new Field(document);
totalPage_Field.setType(FieldType.Field_Expression);
totalPage_Field.setCode("=2*");
footerParagraph.getItems().add(totalPage_Field);
// 添加总页数域
Field pageNums=new Field(document);
pageNums.setType(FieldType.Field_Num_Pages);
footerParagraph.getItems().add(pageNums);
// 给总页数域设置“域分隔符标志”和“域结束标志”
insertFieldMark(document,footerParagraph,pageNums);
//给表达式域设置“域分隔符标志”和“域结束标志”
insertFieldMark(document,footerParagraph,totalPage_Field);
footerParagraph.appendText(" 页");
//设置段落样式
footerParagraph.getStyle().getCharacterFormat().setFontSize(9f);
footerParagraph.getStyle().getCharacterFormat().setFontName("宋体");
footerParagraph.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);
}
// 给field插入分隔符(Field_Separator)和结束(Field_End)
public static void insertFieldMark(Document document,Paragraph paragraph, Field field) {
// 插入Field的分隔符
FieldMark separatorFieldMark = new FieldMark(document,FieldMarkType.Field_Separator);
paragraph.getItems().add(separatorFieldMark);
// 插入Field的结束符
FieldMark endFieldMark = new FieldMark(document,FieldMarkType.Field_End);
paragraph.getItems().add(endFieldMark);
field.setEnd(endFieldMark);
}
}
申请临时 License
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。