如何使用 PDFBox 2.0 创建单选按钮组

How to Create a Radio Button Group with PDFBox 2.0

我想使用 PDFBox 2.0 创建一个单选按钮组,我可以创建 3 个单选按钮,但我不知道如何对它们进行分组(PDFBox 1.8,使用 PDRadioCollection,但 2.0没有。)。

如何使用 PDFBox 2.0 创建单选按钮组?

这是我当前的代码:

        PDDocument document = new PDDocument();
        PDPage page = new PDPage(PDRectangle.A4);
        document.addPage(page);

        PDAcroForm acroForm = new PDAcroForm(document);
        acroForm.setNeedAppearances(true);
        document.getDocumentCatalog().setAcroForm(acroForm);

        PDResources res = new PDResources();
        COSName fontName = res.add(PDTrueTypeFont.load(document, new FileInputStream("C:/Windows/Fonts/arial.ttf"), StandardEncoding.INSTANCE));
        acroForm.setDefaultResources(res);
        acroForm.setDefaultAppearance('/' + fontName.getName() + " 10 Tf 0 g");

        PDPageContentStream contents = new PDPageContentStream(document, page);

        List<String> options = Arrays.asList("a", "b", "c");
        for (int i = 0; i < options.size(); i++) {
            PDRadioButton button = new PDRadioButton(acroForm);
            button.setPartialName("RadioButton" + options.get(i));

            PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary(new COSDictionary());
            fieldAppearance.setBorderColour(new PDColor(new float[]{0, 0, 0}, PDDeviceRGB.INSTANCE));

            PDAnnotationWidget widget = button.getWidgets().get(0);
            widget.setRectangle(new PDRectangle(30, 800 - i * (21), 16, 16));
            widget.setAppearanceCharacteristics(fieldAppearance);

            acroForm.getFields().add(button);
            page.getAnnotations().add(widget);
        }
        contents.close();
        document.save(new FileOutputStream("RadioButtonTest.pdf"));
        document.close();

通过查看 Tilman 的建议和侥幸,我想出了一个创建单选按钮组的解决方案。

注意:我一直在通过在 Acrobat 11 中检查 pdf 来验证我的结果。

代码如下:

try {
        PDDocument document = new PDDocument();
        PDPage page = new PDPage(PDRectangle.A4);

        document.addPage(page);

        PDAcroForm acroForm = new PDAcroForm(document);
        acroForm.setNeedAppearances(true);
        acroForm.setXFA(null);
        document.getDocumentCatalog().setAcroForm(acroForm);

        PDFont font = PDType1Font.HELVETICA;

        PDResources res = new PDResources();
        COSName fontName = res.add(font);
        acroForm.setDefaultResources(res);
        acroForm.setDefaultAppearance('/' + fontName.getName() + " 10 Tf 0 g");

        PDPageContentStream contents = new PDPageContentStream(document, page);

        List<String> options = Arrays.asList("a", "b", "c");
        PDRadioButton radioButton = new PDRadioButton(acroForm);
        radioButton.setPartialName("RadioButtonParent");
        radioButton.setExportValues(options);
        radioButton.getCOSObject().setName(COSName.DV, options.get(1));

        List<PDAnnotationWidget> widgets = new ArrayList<>();
        for (int i = 0; i < options.size(); i++) {

            PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary(new COSDictionary());
            fieldAppearance.setBorderColour(new PDColor(new float[]{0, 0, 0}, PDDeviceRGB.INSTANCE));

            PDAnnotationWidget widget = new PDAnnotationWidget();
            widget.setRectangle(new PDRectangle(30, 811 - i * (21), 16, 16));
            widget.setAppearanceCharacteristics(fieldAppearance);

            widgets.add(widget);
            page.getAnnotations().add(widget);

            // added by Tilman on 13.1.2017, without it Adobe does not set the values properly
            PDAppearanceDictionary appearance = new PDAppearanceDictionary();
            COSDictionary dict = new COSDictionary();
            dict.setItem(COSName.getPDFName("Off"), new COSDictionary());
            dict.setItem(COSName.getPDFName(options.get(i)), new COSDictionary());
            PDAppearanceEntry appearanceEntry = new PDAppearanceEntry(dict);
            appearance.setNormalAppearance(appearanceEntry);
            widget.setAppearance(appearance);


            contents.beginText();
            contents.setFont(font, 10);
            contents.newLineAtOffset(56, 811 - i * (21) + 4);
            contents.showText(options.get(i));
            contents.endText();
        }
        radioButton.setWidgets(widgets);
        acroForm.getFields().add(radioButton);

        contents.close();
        try(FileOutputStream output = new FileOutputStream("Test.pdf")) {
            document.save(output);
        }
        document.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

关键似乎是将每个单选按钮的部分名称设置为相同的值,但我不能确定。

2019年1月17日更新:我就是开头提到的"Tilman",为单选按钮创建了一个更灵活的代码并上传到source code repository。它的优点是创建类似于Adobe的外观流,因此不再需要调用acroForm.setNeedAppearances(true);。该代码适用于 PDFBox 2.0.13 及更高版本。