在 Word 中,可填充表单通常有两种实现方式:经典表单字段和内容控件。内容控件(Content Control)是 Word 2007 之后引入的特性,相比经典字段,它支持更丰富的类型(如日期选择器、图片控件),在界面上的表现也更现代。在 Free Spire.Doc for Java 中,内容控件通过 StructureDocumentTagInline 类来创建。
本文基于一个完整的示例代码,讲解如何使用免费库中的 StructureDocumentTagInline 在 Word 文档中创建七种常见的内容控件,并设置文档保护,使用户只能填写表单区域。
环境准备
在 Maven 项目中引入 Free Spire.Doc for Java:
xml
<repositories>
<repository>
<id>com.e-iceblue</id>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc.free</artifactId>
<version>5.2.0</version>
</dependency>
</dependencies>
非 Maven 项目可以手动下载 JAR 包并加入 classpath。
完整示例代码
以下代码创建一个包含七种内容控件的表格表单,并最终保存为 .docx 文件。
java
import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.DocPicture;
import com.spire.doc.fields.TextRange;
import java.util.Date;
public class CreateFillableForm {
public static void main(String[] args) {
// 创建文档对象
Document doc = new Document();
// 添加一节
Section section = doc.addSection();
// 添加一个 7 行 2 列的表格
Table table = section.addTable(true);
table.resetCells(7, 2);
// 在第一列添加说明文字
Paragraph paragraph = table.getRows().get(0).getCells().get(0).addParagraph();
paragraph.appendText("Plain Text Content Control");
paragraph = table.getRows().get(1).getCells().get(0).addParagraph();
paragraph.appendText("Rich Text Content Control");
paragraph = table.getRows().get(2).getCells().get(0).addParagraph();
paragraph.appendText("Picture Content Control");
paragraph = table.getRows().get(3).getCells().get(0).addParagraph();
paragraph.appendText("Drop-Down List Content Control");
paragraph = table.getRows().get(4).getCells().get(0).addParagraph();
paragraph.appendText("Check Box Content Control");
paragraph = table.getRows().get(5).getCells().get(0).addParagraph();
paragraph.appendText("Combo box Content Control");
paragraph = table.getRows().get(6).getCells().get(0).addParagraph();
paragraph.appendText("Date Picker Content Control");
// 1. 纯文本内容控件(单元格 0,1)
paragraph = table.getRows().get(0).getCells().get(1).addParagraph();
StructureDocumentTagInline sdt = new StructureDocumentTagInline(doc);
paragraph.getChildObjects().add(sdt);
sdt.getSDTProperties().setSDTType(SdtType.Text);
sdt.getSDTProperties().setAlias("Plain Text");
sdt.getSDTProperties().setTag("Plain Text");
sdt.getSDTProperties().isShowingPlaceHolder(true);
SdtText text = new SdtText(true);
text.isMultiline(false);
sdt.getSDTProperties().setControlProperties(text);
TextRange tr = new TextRange(doc);
tr.setText("Click or tap here to enter text.");
sdt.getSDTContent().getChildObjects().add(tr);
// 2. 富文本内容控件(单元格 1,1)
paragraph = table.getRows().get(1).getCells().get(1).addParagraph();
sdt = new StructureDocumentTagInline(doc);
paragraph.getChildObjects().add(sdt);
sdt.getSDTProperties().setSDTType(SdtType.Rich_Text);
sdt.getSDTProperties().setAlias("Rich Text");
sdt.getSDTProperties().setTag("Rich Text");
sdt.getSDTProperties().isShowingPlaceHolder(true);
text = new SdtText(true);
text.isMultiline(false);
sdt.getSDTProperties().setControlProperties(text);
tr = new TextRange(doc);
tr.setText("Click or tap here to enter text.");
sdt.getSDTContent().getChildObjects().add(tr);
// 3. 图片内容控件(单元格 2,1)
paragraph = table.getRows().get(2).getCells().get(1).addParagraph();
sdt = new StructureDocumentTagInline(doc);
paragraph.getChildObjects().add(sdt);
sdt.getSDTProperties().setSDTType(SdtType.Picture);
sdt.getSDTProperties().setAlias("Picture");
sdt.getSDTProperties().setTag("Picture");
SdtPicture sdtPicture = new SdtPicture();
sdt.getSDTProperties().setControlProperties(sdtPicture);
DocPicture pic = new DocPicture(doc);
pic.loadImage("C:\\Users\\Administrator\\Desktop\\ChooseImage.png"); // 替换为实际图片路径
sdt.getSDTContent().getChildObjects().add(pic);
// 4. 下拉列表内容控件(单元格 3,1)
paragraph = table.getRows().get(3).getCells().get(1).addParagraph();
sdt = new StructureDocumentTagInline(doc);
sdt.getSDTProperties().setSDTType(SdtType.Drop_Down_List);
sdt.getSDTProperties().setAlias("Dropdown List");
sdt.getSDTProperties().setTag("Dropdown List");
paragraph.getChildObjects().add(sdt);
SdtDropDownList sddl = new SdtDropDownList();
sddl.getListItems().add(new SdtListItem("Choose an item.", "1"));
sddl.getListItems().add(new SdtListItem("Item 2", "2"));
sddl.getListItems().add(new SdtListItem("Item 3", "3"));
sddl.getListItems().add(new SdtListItem("Item 4", "4"));
sdt.getSDTProperties().setControlProperties(sddl);
tr = new TextRange(doc);
tr.setText(sddl.getListItems().get(0).getDisplayText());
sdt.getSDTContent().getChildObjects().add(tr);
// 5. 复选框内容控件(单元格 4,1)------两个复选框
paragraph = table.getRows().get(4).getCells().get(1).addParagraph();
sdt = new StructureDocumentTagInline(doc);
paragraph.getChildObjects().add(sdt);
sdt.getSDTProperties().setSDTType(SdtType.Check_Box);
SdtCheckBox scb = new SdtCheckBox();
sdt.getSDTProperties().setControlProperties(scb);
tr = new TextRange(doc);
sdt.getSDTContent().getChildObjects().add(tr); // 注意:此处使用 SDTContent
scb.setChecked(false);
paragraph.appendText(" Option 1");
paragraph = table.getRows().get(4).getCells().get(1).addParagraph();
sdt = new StructureDocumentTagInline(doc);
paragraph.getChildObjects().add(sdt);
sdt.getSDTProperties().setSDTType(SdtType.Check_Box);
scb = new SdtCheckBox();
sdt.getSDTProperties().setControlProperties(scb);
tr = new TextRange(doc);
sdt.getSDTContent().getChildObjects().add(tr);
scb.setChecked(false);
paragraph.appendText(" Option 2");
// 6. 组合框内容控件(单元格 5,1)
paragraph = table.getRows().get(5).getCells().get(1).addParagraph();
sdt = new StructureDocumentTagInline(doc);
paragraph.getChildObjects().add(sdt);
sdt.getSDTProperties().setSDTType(SdtType.Combo_Box);
sdt.getSDTProperties().setAlias("Combo Box");
sdt.getSDTProperties().setTag("Combo Box");
SdtComboBox cb = new SdtComboBox();
cb.getListItems().add(new SdtListItem("Choose an item."));
cb.getListItems().add(new SdtListItem("Item 2"));
cb.getListItems().add(new SdtListItem("Item 3"));
sdt.getSDTProperties().setControlProperties(cb);
tr = new TextRange(doc);
tr.setText(cb.getListItems().get(0).getDisplayText());
sdt.getSDTContent().getChildObjects().add(tr);
// 7. 日期选择器内容控件(单元格 6,1)
paragraph = table.getRows().get(6).getCells().get(1).addParagraph();
sdt = new StructureDocumentTagInline(doc);
paragraph.getChildObjects().add(sdt);
sdt.getSDTProperties().setSDTType(SdtType.Date_Picker);
sdt.getSDTProperties().setAlias("Date Picker");
sdt.getSDTProperties().setTag("Date Picker");
SdtDate date = new SdtDate();
date.setCalendarType(CalendarType.Default);
date.setDateFormat("yyyy.MM.dd");
date.setFullDate(new Date());
sdt.getSDTProperties().setControlProperties(date);
tr = new TextRange(doc);
tr.setText("Click or tap to enter a date.");
sdt.getSDTContent().getChildObjects().add(tr);
// 保护文档:仅允许填写表单域
doc.protect(ProtectionType.Allow_Only_Form_Fields, "permission-psd");
// 保存文件
doc.saveToFile("output/WordForm.docx", FileFormat.Docx_2013);
}
}
代码解析
1. 文档与表格布局
代码首先创建一个 Document 对象,添加一节,然后插入一个 7 行 2 列的表格。第一列用于显示控件类型说明,第二列用于放置实际的内容控件。这种表格布局在制作表单时非常常见,可以清晰地组织字段。
2. 纯文本内容控件
java
sdt.getSDTProperties().setSDTType(SdtType.Text);
sdt.getSDTProperties().setAlias("Plain Text");
sdt.getSDTProperties().setTag("Plain Text");
sdt.getSDTProperties().isShowingPlaceHolder(true);
SdtText text = new SdtText(true);
text.isMultiline(false);
sdt.getSDTProperties().setControlProperties(text);
SdtType.Text 指定为纯文本控件。SdtText 的构造函数参数 true 表示启用占位符显示,isMultiline(false) 限制为单行输入。setAlias 和 setTag 分别设置控件的显示名称和程序标识。占位文本通过 TextRange 设置为 "Click or tap here to enter text.",并添加到 SDTContent 中。
3. 富文本内容控件
与纯文本控件几乎相同,只是类型改为 SdtType.Rich_Text。富文本控件允许用户输入带有格式的文本(如加粗、斜体、颜色等),而纯文本控件只能输入无格式文本。
4. 图片内容控件
java
sdt.getSDTProperties().setSDTType(SdtType.Picture);
SdtPicture sdtPicture = new SdtPicture();
sdt.getSDTProperties().setControlProperties(sdtPicture);
DocPicture pic = new DocPicture(doc);
pic.loadImage("C:\\Users\\Administrator\\Desktop\\ChooseImage.png");
sdt.getSDTContent().getChildObjects().add(pic);
图片控件使用 SdtType.Picture,并通过 SdtPicture 设置属性。实际显示的图片通过 DocPicture.loadImage() 加载,然后加入 SDTContent。用户在实际使用时需要将路径替换为自己的图片路径。在 Word 中,用户点击该控件即可替换图片。
5. 下拉列表内容控件
java
SdtDropDownList sddl = new SdtDropDownList();
sddl.getListItems().add(new SdtListItem("Choose an item.", "1"));
sddl.getListItems().add(new SdtListItem("Item 2", "2"));
// ...
sdt.getSDTProperties().setControlProperties(sddl);
SdtDropDownList 用于创建下拉列表。每个选项是一个 SdtListItem,可以只指定显示文本,也可以同时指定显示文本和值(如 "Choose an item.", "1")。用户只能从列表中选择,不能输入自定义内容。默认显示第一个选项。
6. 复选框内容控件
代码在同一个单元格中添加了两个复选框。每个复选框都是一个独立的 StructureDocumentTagInline,类型为 SdtType.Check_Box,并通过 SdtCheckBox 控制勾选状态。scb.setChecked(false) 设置初始为未勾选。复选框后面通过 paragraph.appendText(" Option 1") 添加说明文字。
注意:在复选框部分,代码将 TextRange 添加到了 sdt.getSDTContent().getChildObjects() 中(与其它控件一致)。这确保了复选框内容控件内部有一个空的文本范围,符合 Word 内容控件的结构要求。
7. 组合框内容控件
组合框与下拉列表类似,但用户既可以从列表中选择,也可以输入自定义文本。代码中使用 SdtType.Combo_Box 和 SdtComboBox,选项通过 SdtListItem 添加。默认显示第一个选项。
8. 日期选择器内容控件
java
SdtDate date = new SdtDate();
date.setCalendarType(CalendarType.Default);
date.setDateFormat("yyyy.MM.dd");
date.setFullDate(new Date());
sdt.getSDTProperties().setControlProperties(date);
日期选择器使用 SdtType.Date_Picker 和 SdtDate。可以设置日历类型(CalendarType.Default 或 Gregorian 等)、日期格式(如 "yyyy.MM.dd")以及默认日期。在 Word 中,用户点击该控件会弹出日历选择面板。
文档保护
创建完所有内容控件后,通过以下代码保护文档:
java
doc.protect(ProtectionType.Allow_Only_Form_Fields, "permission-psd");
ProtectionType.Allow_Only_Form_Fields 表示只允许用户填写表单域(包括内容控件和经典表单字段),文档的其他部分不可编辑。第二个参数是解除保护所需的密码。这样,用户打开文档后只能点击并填写表单控件,无法修改表格文字或其他内容。
总结
本文介绍了如何使用 StructureDocumentTagInline 类创建七种 Word 内容控件:纯文本、富文本、图片、下拉列表、复选框、组合框和日期选择器。通过 Document.protect() 设置"仅允许填写表单域"的保护模式,即可生成一份用户只能填写指定区域的可填充表单。内容控件类型丰富、界面友好,适合合同、申请表、登记表等模板类文档的自动化生成。