Vaadin - How to open BrowserWindowOpener from a SINGLE BUTTON

不问归期 提交于 2019-12-23 02:22:05

问题


In the Vaadin example of how to print a dynamically generated PDF they have a two step approach, first you click on the OkButton and then the PrintButton. The problem is that their code to open the PDF relies on creating a new BrowserWindowOpener which then extends the Print button in the ClickListener for the OKButton. In other words they have:

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);
    }
}

This is great because the Print button is now linked to BrowserWindowOpener and will immediately open the window/tab when you click on the PrintButton.

The problem I have is that I don't want an OkButton, I just want to have a PrintButton. In this case I can't add

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);
    }
}

In the ClickListener FOR THE PrintButton because the first time you click it wont work. I then thought what if I had BrowserWindowOpener declared outside of the ClickListener, in the class that links the PrintButton and ClickListener, using something a dummy resource:

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

And then pass the opener to the ClickListener so that I could do something like:

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

However the issue here is that the first click generates a blank page.

My question is how can I get the example working where the dynamically generated PDF is pushed to the browser window with just a SINGLE BUTTON. All the examples for BrowserWindowOpener seem to always use two buttons. And the examples that declare it higher in the class hierarchy don't work for me, it's always an initial blank page.

Lastly, I would love to be able to do all this within the ClickListener, that is totally decoupled from everything else.


回答1:


Get rid of BrowserWindowOpener and use UI.getPage().open() to view your pdf file.

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

Notice that this method is deprecated.

As of Vaadin 7.0.0, the functionality for opening a Resource in a Page has been replaced with similar methods based on a String URL. This is because the usage of Resource is problematic with memory management and with security features in some browsers. Is is recommended to instead use Link for starting downloads.

Don't think it is possible to use BrowserWindowOpener in one button only without hacking in JavaScript.

EDIT: I've achieved desired effect using BrowserWindowOpener. I've extended the class and added pdf generation every time when BrowserWindowOpenerState is requested. The thing is that I've searched for a method that is invoked after the click and before BrowserWindowOpener opens up new tab. The only method I could find is getState() - and only when the state of the component is dirty. I had to also add a flag in overriden getState method because:

  1. setResource method invoke getState() method too, so I had infinite loop

  2. to generate pdf only when its really needed

    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;
    }
    }
    

And pdf generation in your main UI class:

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);
}

And getResource method:

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;
}

Notice that I had to change the filename everytime I generate new pdf file to avoid caching problems.



来源:https://stackoverflow.com/questions/31224728/vaadin-how-to-open-browserwindowopener-from-a-single-button

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!