Vaadin – 如何从单个按钮打开BrowserWindowOpener
在如何打印动态生成的PDF的Vaadin示例中,他们有两步法,首先单击OkButton
然后单击PrintButton
。 问题是他们打开PDF的代码依赖于创建一个新的BrowserWindowOpener
,然后在ClickListener
为OKButton
扩展Print
按钮。 换句话说,他们有:
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
FOR THE 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
完成所有这些ClickListener
,这与其他所有内容完全分离。
摆脱BrowserWindowOpener
并使用UI.getPage().open()
来查看你的pdf文件。
getUI().getPage().open(resource, "_blank", false);
请注意,此方法已弃用。
从Vaadin 7.0.0开始,在页面中打开资源的function已经被基于字符串URL的类似方法所取代。 这是因为资源的使用在内存管理方面存在问题,并且在某些浏览器中具有安全function。 建议改为使用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文件时都必须更改文件名以避免缓存问题。