如何在 Word 中创建可填充表单(Java 实现)

在 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() 设置"仅允许填写表单域"的保护模式,即可生成一份用户只能填写指定区域的可填充表单。内容控件类型丰富、界面友好,适合合同、申请表、登记表等模板类文档的自动化生成。

相关推荐
用户37215742613540 分钟前
如何使用 Java 从 PDF 中提取图片及获取图片信息
java
devpotato42 分钟前
把 MySQL 索引讲透:从 B+ 树结构到线上索引治理
java·mysql
SL_staff43 分钟前
JVS-Logic 实践:如何将‘需求→上线’从11天压缩至2小时?
java·后端·开源
编程老船长43 分钟前
权限不只是菜单按钮——QuickBlue 的 RBAC 与行级数据权限是怎么落地的
java·前端·后端
SL_staff43 分钟前
区域银行如何用JVS-BI两周打通异构数据库:面向开发者的低代码数据融合实践
java·后端·数据可视化
小羊没烦恼!5 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里5 天前
java中的继承和多态的区别
java
小羊没烦恼!5 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕5 天前
JSONObject与JSONArray封装数据格式区别
java·json