Vaadin example of how to print a dynamically generated PDF中,它们有两个步骤,首先单击OkButton,然后单击PrintButton。问题在于,他们打开PDF的代码依赖于创建新的BrowserWindowOpener,然后扩展PrintClickListener中的OKButton按钮。换句话说,它们具有:

okButton.addClickListener(new ClickListener()
 {
    @Override
    public void buttonClick(ClickEvent event)
    {
        // Dynamically generate PDF - this is greatly simplified.
        StreamResource pdfResource = new PdfStreamResource();
        BrowserWindowOpener opener = new BrowserWindowOpener(pdfResource);
        opener.extend(printButton);
    }
}


这很棒,因为Print按钮现在已链接到BrowserWindowOpener,并且当您单击PrintButton时将立即打开窗口/选项卡。

我的问题是我不想要OkButton,而只想拥有PrintButton。在这种情况下,我无法添加

printButton.addClickListener(new ClickListener()
 {
    @Override
    public void buttonClick(ClickEvent event)
    {
        // Dynamically generate PDF - this is greatly simplified.
        StreamResource pdfResource = new PdfStreamResource();
        BrowserWindowOpener opener = new BrowserWindowOpener(pdfResource);
        opener.extend(printButton);
    }
}


ClickListener中,对于PrintButton,因为您第一次单击它将不起作用。然后,我想如果在链接BrowserWindowOpenerClickListener的类中使用虚假资源在PrintButton之外声明了ClickListener怎么办:

BrowserWindowOpener opener = new BrowserWindowOpener("");
opener.extend(printButton);
PrintClickListener printClickListener = new PrintClickListener(opener);
printButton.addClickListener(printClickListener);


然后将opener传递给ClickListener,以便我可以执行以下操作:

printButton.addClickListener(new ClickListener()
 {
    @Override
    public void buttonClick(ClickEvent event)
    {
        // Dynamically generate PDF - this is greatly simplified.
        StreamResource pdfResource = new PdfStreamResource();
        opener.setResource(pdfResource);
    }
}


但是,这里的问题是第一次单击会生成空白页。

我的问题是,如何才能使示例工作,其中仅通过单个按钮将动态生成的PDF推送到浏览器窗口。 BrowserWindowOpener的所有示例似乎总是使用两个按钮。在类层次结构中声明较高级别的示例对我不起作用,它始终是初始空白页。

最后,我很希望能够在ClickListener内完成所有这些工作,而这与其他所有工作完全脱钩了。

最佳答案

摆脱BrowserWindowOpener并使用UI.getPage().open()查看您的pdf文件。

getUI().getPage().open(resource, "_blank", false);


请注意,此method已弃用。


  从Vaadin 7.0.0开始,在页面中打开资源的功能已被基于字符串URL的类似方法所取代。这是因为在某些浏览器中,资源的使用在内存管理和安全功能方面存在问题。建议您改用Link开始下载。


不要认为仅在一个按钮中使用BrowserWindowOpener而不用侵入JavaScript是不可能的。

编辑:
我已经使用BrowserWindowOpener达到了预期的效果。每当请求BrowserWindowOpenerState时,我都会扩展该类并添加pdf生成。事实是,我已经搜索了单击之后且BrowserWindowOpener打开新选项卡之前调用的方法。我可以找到的唯一方法是getState()-仅当组件的状态为脏状态时。我还必须在重写的getState方法中添加一个标志,因为:


setResource方法也调用getState()方法,所以我遇到了无限循环
仅在真正需要时才生成pdf

public class BrowserWindowOpenerWithBeforeClick extends BrowserWindowOpener
{

private boolean pdfGenerated = false;

public BrowserWindowOpenerWithBeforeClick(String url)
{
    super(url);
}

@Override
protected BrowserWindowOpenerState getState(boolean markAsDirty) {
    if(!pdfGenerated){
        StreamResource resource = ((RfgUI) UI.getCurrent()).getResource();
        pdfGenerated = true;
        this.setResource("url",resource);
    }
    return (BrowserWindowOpenerState) super.getState(markAsDirty);
}

public void setPdfGenerated(boolean generated){
    this.pdfGenerated = generated;
}
}



在主UI类中生成pdf:

void pdfgeneration(final VerticalLayout layout)
{
    name.setValue("Slartibartfast");
    final Button ok = new Button("OK");
    ok.setId("ok-button");
    final BrowserWindowOpenerWithBeforeClick bwo = new BrowserWindowOpenerWithBeforeClick("");
    bwo.extend(ok);
    name.addValueChangeListener(new ValueChangeListener()
    {
        @Override
        public void valueChange(ValueChangeEvent event)
        {
            bwo.setPdfGenerated(false);
            bwo.markAsDirty();
        }
    });
    layout.addComponent(name);
    layout.addComponent(ok);
}


和getResource方法:

public StreamResource getResource()
{
    StreamSource source = new MyPdfSource((String) name.getValue());
    String filename = new Random().nextInt() + "pdf_printing_example.pdf";
    StreamResource resource = new StreamResource(source, filename);
    resource.setMIMEType("application/pdf");
    resource.setCacheTime(0);
    resource.getStream().setParameter("Content-Disposition", "attachment; filename=" + filename);
    return resource;
}


请注意,每次生成新的pdf文件时都必须更改文件名,以避免缓存问题。

08-28 22:51