如何使用pdfbox 2设置复选框的外观上的边框

时间:2019-05-16 14:49:29

标签: java pdfbox

我正在使用PDFBox v2从头开始创建pdf,我对复选框的外观有疑问,当单击复选框(并且没有单击鼠标时)时,复选框的边框不会出现。

我使用了tilman官方文档中提供的代码示例来创建单选按钮,并使其适应于创建复选框:

public void drawCheckBox() throws IOException {
    for (Entry<String, List<InputCheckBox>> entry : myHash.entrySet()) {
        String checkBoxKey = entry.getKey(); // radio buton key
        List<InputCheckBox> checkBoxValue = entry.getValue(); // checkbox list(s)
        PDCheckBox checkBox = new PDCheckBox(checkBoxValue.get(0).getAcroForm());
        checkBox.setPartialName(checkBoxKey);
        checkBox.setExportValues(Arrays.asList(checkBoxKey));

        // couleur de la checkbox
        PDAppearanceCharacteristicsDictionary appearanceCharacteristics = new PDAppearanceCharacteristicsDictionary(
                new COSDictionary());
        appearanceCharacteristics.setBorderColour(new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE));
        appearanceCharacteristics.setBackground(new PDColor(new float[] { 1, 1, 1 }, PDDeviceRGB.INSTANCE));

        checkBoxValue.get(0).getAcroForm().getFields().add(checkBox);
        List<PDAnnotationWidget> widgets = new ArrayList<>();
        for (int i = 0; i < checkBoxValue.size(); i++) {
            PDAnnotationWidget widget = new PDAnnotationWidget();
            widget.setRectangle(new PDRectangle(checkBoxValue.get(i).getLeft(),
                    checkBoxValue.get(i).getPage().getMediaBox().getHeight()
                            - (checkBoxValue.get(i).getTop() + checkBoxValue.get(i).getHeight()),
                    checkBoxValue.get(i).getWidth(), checkBoxValue.get(i).getHeight()));

            // border du checkbox
            widget.setAppearanceCharacteristics(appearanceCharacteristics);
            PDBorderStyleDictionary borderStyleDictionary = new PDBorderStyleDictionary();
            borderStyleDictionary.setWidth(1);
            borderStyleDictionary.setStyle(PDBorderStyleDictionary.STYLE_SOLID);
            // creer les apparence de radio button pour l'état off et l'état activé
            COSDictionary apNDict = new COSDictionary();
            apNDict.setItem(COSName.Off,
                    createCheckBoxAppearanceStream(checkBoxValue.get(i).getDocument(), widget, false));
            apNDict.setItem(COSName.ON,
                    createCheckBoxAppearanceStream(checkBoxValue.get(i).getDocument(), widget, true));

            PDAppearanceDictionary appearance = new PDAppearanceDictionary();
            PDAppearanceEntry appearanceNEntry = new PDAppearanceEntry(apNDict);
            appearance.setNormalAppearance(appearanceNEntry);
            // appliquer l'apparence dans le widget
            widget.setBorderStyle(borderStyleDictionary);
            widget.setPage(checkBoxValue.get(i).getPage());
            widget.setAppearance(appearance);
            widget.setParent(checkBox);
            widget.setAppearanceState("Off");
            // widget.setAnnotationName(key);
            widget.setPrinted(true);
            checkBoxValue.get(i).getPage().getAnnotations().add(widget);
            widgets.add(widget);
            checkBox.setWidgets(widgets);
        }
    }
}

// les methodes ci_dessous sert a creer l'apparence des checkBox selon leur
// état coché ou non
private static PDAppearanceStream createCheckBoxAppearanceStream(final PDDocument document,
        PDAnnotationWidget widget, boolean on) throws IOException {
    PDRectangle rect = widget.getRectangle();
    PDAppearanceStream onAP = new PDAppearanceStream(document);
    onAP.setResources(new PDResources());
    onAP.setBBox(new PDRectangle(rect.getWidth(), rect.getHeight()));
    PDPageContentStream onAPCS = new PDPageContentStream(document, onAP);

    PDAppearanceCharacteristicsDictionary appearanceCharacteristics = widget.getAppearanceCharacteristics();
    PDColor backgroundColor = appearanceCharacteristics.getBackground();
    PDColor borderColor = appearanceCharacteristics.getBorderColour();
    float lineWidth = getLineWidth(widget);
    onAPCS.setLineWidth(lineWidth);
    onAPCS.setNonStrokingColor(backgroundColor);
    onAPCS.fill();
    onAPCS.setStrokingColor(borderColor);
    onAPCS.stroke();

    if (on) {
        onAPCS.setFont(PDType1Font.ZAPF_DINGBATS, 14.5f);
        onAPCS.beginText();
        onAPCS.newLineAtOffset(0, 0);
        onAPCS.showText("\u2714");
        onAPCS.endText();
        onAPCS.fill();
    }

    onAPCS.close();
    return onAP;
}

static float getLineWidth(PDAnnotationWidget widget) {
    PDBorderStyleDictionary bs = widget.getBorderStyle();
    if (bs != null) {
        return bs.getWidth();
    }
    return 1;
}

这是我得到的结果:

here is the result that i'am getting

这就是我应该拥有的:

and here is what i am supposed to have

1 个答案:

答案 0 :(得分:1)

您执行路径填充和路径描边操作之前没有定义路径:

onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.fill();
onAPCS.setStrokingColor(borderColor);
onAPCS.stroke();

尝试像这样定义路径(矩形):

onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.setStrokingColor(borderColor);
onAPCS.addRect(0, 0, rect.getWidth(), rect.getHeight());
onAPCS.fillAndStroke();

(或者您可能希望使用稍小的矩形,例如onAPCS.addRect(1, 1, rect.getWidth() - 2, rect.getHeight() - 2)。)


顺便说一句,进一步,您再次使用fill,这次没有任何明显的原因:

if (on) {
    ...
    onAPCS.endText();
    onAPCS.fill();
}

您应该删除该fill,因为严格来说,它甚至是无效的:fillstroke仅在路径定义之后才被允许!