Horizontally centering a popup window in Vaadin
Asked Answered
S

2

6

I have added a popup window to my main UI as follows:

Window component = new Window();
UI.getCurrent().addWindow(component);

Now, I want my popup to be centered horizontally and e.g. 40 pixels from the top of the screen. As far as I can see Vaadin has 4 methods for positioning my window.

component.center()
component.setPosition(x, y)
component.setPositionX(x)
component.setPositionY(y)

None of these are really what I want. I was hoping at first that setPositionY might help me. This does allow me to get the right distance from the top, but the x-position is now set to 0, where I wanted it to be centered.

The setPosition might have helped if I was able to calculate what the x-position should be, but this would require me to know the width of the component in pixels, but component.getWidth just tells me 100%.

Next I tried to use CSS styling on the component, writing and explicit css rule and adding it to the component with addStyleName. It seems though that Vaadin overrides whatever I wrote in my css with its own defaults...

Any ideas how to get my Window component positioned correctly?

Samadhi answered 15/4, 2016 at 8:26 Comment(2)
I removed my answer since it was wrong. The thing seems to be, that the center() is executed on client side. Do you know the width of your popup window? (Usually you have to define the width)Unfurl
No, I do not know the width of my popup window, it is dependent on the content. And as I mentioned the getWidth method on a component is not much help, as it simply return 100 %.Samadhi
R
2

Solution 1: Use SizeReporter

Indeed, setPositionY() will reset the window's centered property to false. As the width of your pop-up and that of your browser window are not know before they appear on the screen, the only way I know to get those values is to use the SizeReporter add-on. Its use is quite straightforward:

public class MyUI extends UI {

    private Window popUp;

    private SizeReporter popUpSizeReporter;
    private SizeReporter windowSizeReporter;

    @Override
    protected void init(VaadinRequest request) {

        Button button = new Button("Content button");
        VerticalLayout layout = new VerticalLayout(button);
        layout.setMargin(true);

        popUp = new Window("Pop-up", layout);
        popUp.setPositionY(40);

        addWindow(popUp);

        popUpSizeReporter = new SizeReporter(popUp);
        popUpSizeReporter.addResizeListenerOnce(this::centerPopUp);

        windowSizeReporter = new SizeReporter(this);
        windowSizeReporter.addResizeListenerOnce(this::centerPopUp);
    }

    private void centerPopUp(ComponentResizeEvent event) {

        int popUpWidth = popUpSizeReporter.getWidth();
        int windowWidth = windowSizeReporter.getWidth();

        if (popUpWidth == -1 || windowWidth == -1) {
            return;
        }

        popUp.setPositionX((windowWidth - popUpWidth) / 2);
    }
}

This piece of code will be okay as long as you don't resize the pop-up. If you do, it will not be automatically recentered. If you replace addResizeListenerOnce() by addResizeListener() then it will automatically recenter the pop-up but you'll get some "UI glitches" as the add-on sends resize events almost continually while you're resizing your pop-up...

You could try to do it using CSS, but I personally avoid CSS as much as I can with Vaadin :).

You'll need to recompile the widgetset after you've added the add-on as a dependency.

Solution 2: Use com.vaadin.ui.JavaScript

I won't vouch for the portability of this solution but I guess it will work on most modern browsers.

public class MyUI extends UI {

    private Window popUp;

    @Override
    protected void init(VaadinRequest request) {

        Button button = new Button("Content button");
        VerticalLayout layout = new VerticalLayout(button);
        layout.setMargin(true);

        popUp = new Window("Pop-up", layout);
        popUp.setPositionY(40);
        popUp.addStyleName("window-center");

        addWindow(popUp);

        // Add a JS function that can be called from the client.
        JavaScript.getCurrent().addFunction("centerWindow", args -> {
            popUp.setPositionX((int) ((args.getNumber(1) - args.getNumber(0)) / 2));
        });

        // Execute the function now. In real code you might want to execute the function just after the window is displayed, probably in your enter() method.
        JavaScript.getCurrent().execute("centerWindow(document.getElementsByClassName('window-center')[0].offsetWidth, window.innerWidth)");
    }
}
Rola answered 15/4, 2016 at 21:42 Comment(3)
Unfortunately the project I am working on is not too fond of using various add-ons, especially not for such a small thing as this. I tried using CSS as well but without any luck. It seems that my only options might be to make my own custom component...Samadhi
No worries, I totally understand, this kind of thing should be built into Vaadin. Maybe you can open a ticket there (dev.vaadin.com). However, I believe I have found another solution, I will post it in a bit...Rola
Thanks, I will accept your answer. I would just have wished that the functionality was possible directly in Vaadin :-)Samadhi
C
3

I used the methods getBrowserWindowWidth() and getBrowserWindowHeight() from the com.vaadin.server.Page class for this.

I centered my "log" window horizontally in the lower part of the browser window with

myWindow.setHeight("30%");
myWindow.setWidth("96%");
myWindow.setPosition(
    (int) (Page.getCurrent().getBrowserWindowWidth() * 0.02),
    (int) (Page.getCurrent().getBrowserWindowHeight() * 0.65)
);
Chui answered 28/2, 2017 at 13:21 Comment(0)
R
2

Solution 1: Use SizeReporter

Indeed, setPositionY() will reset the window's centered property to false. As the width of your pop-up and that of your browser window are not know before they appear on the screen, the only way I know to get those values is to use the SizeReporter add-on. Its use is quite straightforward:

public class MyUI extends UI {

    private Window popUp;

    private SizeReporter popUpSizeReporter;
    private SizeReporter windowSizeReporter;

    @Override
    protected void init(VaadinRequest request) {

        Button button = new Button("Content button");
        VerticalLayout layout = new VerticalLayout(button);
        layout.setMargin(true);

        popUp = new Window("Pop-up", layout);
        popUp.setPositionY(40);

        addWindow(popUp);

        popUpSizeReporter = new SizeReporter(popUp);
        popUpSizeReporter.addResizeListenerOnce(this::centerPopUp);

        windowSizeReporter = new SizeReporter(this);
        windowSizeReporter.addResizeListenerOnce(this::centerPopUp);
    }

    private void centerPopUp(ComponentResizeEvent event) {

        int popUpWidth = popUpSizeReporter.getWidth();
        int windowWidth = windowSizeReporter.getWidth();

        if (popUpWidth == -1 || windowWidth == -1) {
            return;
        }

        popUp.setPositionX((windowWidth - popUpWidth) / 2);
    }
}

This piece of code will be okay as long as you don't resize the pop-up. If you do, it will not be automatically recentered. If you replace addResizeListenerOnce() by addResizeListener() then it will automatically recenter the pop-up but you'll get some "UI glitches" as the add-on sends resize events almost continually while you're resizing your pop-up...

You could try to do it using CSS, but I personally avoid CSS as much as I can with Vaadin :).

You'll need to recompile the widgetset after you've added the add-on as a dependency.

Solution 2: Use com.vaadin.ui.JavaScript

I won't vouch for the portability of this solution but I guess it will work on most modern browsers.

public class MyUI extends UI {

    private Window popUp;

    @Override
    protected void init(VaadinRequest request) {

        Button button = new Button("Content button");
        VerticalLayout layout = new VerticalLayout(button);
        layout.setMargin(true);

        popUp = new Window("Pop-up", layout);
        popUp.setPositionY(40);
        popUp.addStyleName("window-center");

        addWindow(popUp);

        // Add a JS function that can be called from the client.
        JavaScript.getCurrent().addFunction("centerWindow", args -> {
            popUp.setPositionX((int) ((args.getNumber(1) - args.getNumber(0)) / 2));
        });

        // Execute the function now. In real code you might want to execute the function just after the window is displayed, probably in your enter() method.
        JavaScript.getCurrent().execute("centerWindow(document.getElementsByClassName('window-center')[0].offsetWidth, window.innerWidth)");
    }
}
Rola answered 15/4, 2016 at 21:42 Comment(3)
Unfortunately the project I am working on is not too fond of using various add-ons, especially not for such a small thing as this. I tried using CSS as well but without any luck. It seems that my only options might be to make my own custom component...Samadhi
No worries, I totally understand, this kind of thing should be built into Vaadin. Maybe you can open a ticket there (dev.vaadin.com). However, I believe I have found another solution, I will post it in a bit...Rola
Thanks, I will accept your answer. I would just have wished that the functionality was possible directly in Vaadin :-)Samadhi

© 2022 - 2024 — McMap. All rights reserved.