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