在Vaadin example of how to print a dynamically generated PDF中,它们有两个步骤,首先单击OkButton
,然后单击PrintButton
。问题在于,他们打开PDF的代码依赖于创建新的BrowserWindowOpener
,然后扩展Print
中ClickListener
中的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
,因为您第一次单击它将不起作用。然后,我想如果在链接BrowserWindowOpener
和ClickListener
的类中使用虚假资源在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文件时都必须更改文件名,以避免缓存问题。