How to center a window properly in Java FX?

2019-01-18 07:02发布

问题:

Java FX provides Window.centerOnScreen() to - guess what - center a window on a screen. HOWEVER, the Java FX' definition of "center of a screen" seems to be at (0.5x;0.33y). I hoped this was a bug, but I was told it's not.

Anyway. Has someone came up with a clean and easy solution on how to center a Window before displaying it? My first approach leads to flickering of the screen, since the window has to be displayed first, before it can be centered.

public static void centerOnScreen(Stage stage) {
  stage.centerOnScreen();
  stage.setY(stage.getY() * 3f / 2f);
}

Update: What I forgot to mention; I don't know the size of the window beforehand, so in order to center it manually I have to display it first - what causes it to flicker one time. So I'm looking for a solution to center it without displaying it first - like Java FX is able to do it, however the wrong way.

回答1:

This is how you do it before the stage was made visible:

    double width = 640;
    double height = 480;

    Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
    stage.setX((screenBounds.getWidth() - width) / 2); 
    stage.setY((screenBounds.getHeight() - height) / 2);  

    final Scene scene = new Scene( new Group(), width, height);
    stage.setScene(scene);
    stage.show();

and this after the stage was made visible, i. e. you can use the properties of the stage:

    double width = 640;
    double height = 480;

    final Scene scene = new Scene( new Group(), width, height);
    stage.setScene(scene);
    stage.show();

    Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
    stage.setX((screenBounds.getWidth() - stage.getWidth()) / 2); 
    stage.setY((screenBounds.getHeight() - stage.getHeight()) / 2);  

If you have multiple screens, you can calculate the position manually using the list of Screen objects which is returned by the Screen.getScreens() method.



回答2:

The general trick to responding to initialization of a value is to create a listener for the property that removes itself when the property is initialized. So you can do

    Screen screen = Screen.getPrimary();
    Rectangle2D sbounds = screen.getBounds();

    double sw = sbounds.getWidth() ;
    double sh = sbounds.getHeight();

    listenToSizeInitialization(primaryStage.widthProperty(), 
            w -> primaryStage.setX(( sw - w) /2));
    listenToSizeInitialization(primaryStage.heightProperty(), 
            h -> primaryStage.setY(( sh - h) /2));


    primaryStage.show();

with

private void listenToSizeInitialization(ObservableDoubleValue size, 
        DoubleConsumer handler) {

    ChangeListener<Number> listener = new ChangeListener<Number>() {
        @Override
        public void changed(ObservableValue<? extends Number> obs, 
                Number oldSize, Number newSize) {
            if (newSize.doubleValue() != Double.NaN) {
                handler.accept(newSize.doubleValue());
                size.removeListener(this);
            }
        }
    };
    size.addListener(listener);
}


回答3:

for this code you have to import

import java.awt.Dimension;
import java.awt.Toolkit;

then

Dimension d= Toolkit.getDefaultToolkit().getScreenSize(); // get screen size
primaryStage.show(); //show stage because you wouldn't be able to get Height & width of the stage
primaryStage.setX(d.width/2-(primaryStage.getWidth()/2));
primaryStage.setY(d.height/2-(primaryStage.getHeight()/2));

if you want to do it before that stage is show then at the place of primaryStage.getWidth()/2 replace it with the height you gonna pass in scenes constructor.

primaryStage.setX(d.width/2-(300/2));
primaryStage.setY(d.height/2-(300/2));
Scene scene = new Scene(root , 300 ,300);


回答4:

I know this has post was answered about three and a half ages ago, but it seems to me that everybody has overlooked the problem.

you just need to type the stage.centerOnScreen(); right after the stage.show() because if you write it before the code will be executed once and then it goes to its original state(that is how its explained in my head).



标签: javafx