2016-10-18 2 views
2

Я новичок в JavaFX, и у меня возникла проблема с установкой позиции моего нового окна, связанной с положением родительского окна. Я хочу открыть новое окно в центре родительского окна.JavaFX - центральная дочерняя ступень до родительского этапа

Я попробовал эти два пути:

1) Init владелец - я думал, что владелец INIT откроет мое окно в центре родителя, но это не

FXMLLoader fxmlLoader = new  FXMLLoader(AddUserController.class.getResource("/view/addUserStage.fxml")); 
Parent root = fxmlLoader.load(); 
Stage stage = new Stage(); 
stage.initOwner(parentStage); 
stage.showAndWait(); 

2) Переставьте когда окно отображается - он работает, но после того, как окно показано, я вижу его первую позицию, а затем вижу, что он перемещен в новую расчетную позицию. Я не могу этого принять.

FXMLLoader fxmlLoader = new  FXMLLoader(AddUserController.class.getResource("/view/addUserStage.fxml")); 
Parent root = fxmlLoader.load(); 
Stage stage = new Stage(); 
stage.initOwner(parentStage); 
stage.setOnShown(event -> controller.onWindowShown()); 
stage.showAndWait(); 

В onWindowShown функции я устанавливаю новый X и Y положения моего окна, потому что только после того, как показано ширина и высота моего окна, как известно, и я могу вычислить Исли новую позицию.

Как установить положение дочернего окна в центре родительского окна перед функцией showAndWait?

ответ

2

Если вы хотите, чтобы показать Stage вы должны поместить содержимое, загруженное из файла FXML в Scene и это Scene будет установлен на Stage.

К сожалению, размер Stage неизвестен до его рендеринга (как вы упомянули), но чтобы переместить его в центр родителя Stage, вы должны знать размер.

Один трюк, который может работать, - hideStage перед тем, как он будет показан, переместите его, а затем make it visible еще раз в новой позиции.

Пример

public class Main extends Application { 
    @Override 
    public void start(Stage primaryStage) { 
     try { 
      BorderPane root = new BorderPane(); 
      Scene scene = new Scene(root, 400, 400); 

      Button button = new Button("Open another Stage"); 
      button.setOnAction(e -> { 

       Stage popUpStage = new Stage(); 

       // Here add the FXML content to the Scene 
       Scene popUpScene = new Scene(new Button()); 
       popUpStage.setScene(popUpScene); 

       // Calculate the center position of the parent Stage 
       double centerXPosition = primaryStage.getX() + primaryStage.getWidth()/2d; 
       double centerYPosition = primaryStage.getY() + primaryStage.getHeight()/2d; 

       // Hide the pop-up stage before it is shown and becomes relocated 
       popUpStage.setOnShowing(ev -> popUpStage.hide()); 

       // Relocate the pop-up Stage 
       popUpStage.setOnShown(ev -> { 
        popUpStage.setX(centerXPosition - popUpStage.getWidth()/2d); 
        popUpStage.setY(centerYPosition - popUpStage.getHeight()/2d); 
        popUpStage.show(); 
       }); 

       popUpStage.showAndWait(); 
      }); 

      root.setCenter(button); 


      primaryStage.setScene(scene); 
      primaryStage.show(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
0

Вы можете макет Scene перед показом Stage и определить позицию, основанную на Scene размера. Это не займет много оконных украшения во внимание, однако, так что положение может быть немного от, если у вас есть окно с таким же видом украшений принять размер этих украшений во внимание:

@Override 
public void start(Stage primaryStage) { 
    Button btnMain = new Button("show"); 
    btnMain.setOnAction(evt -> { 
     Stage stage = new Stage(); 
     Button btn = new Button("Close"); 
     btn.setOnAction((ActionEvent event) -> { 
      stage.close(); 
     }); 

     StackPane root = new StackPane(); 
     root.getChildren().add(btn); 

     Bounds mainBounds = primaryStage.getScene().getRoot().getLayoutBounds(); 
     Scene scene = new Scene(root, 400, 400); 

     stage.setScene(scene); 

     // layout new scene 
     scene.getRoot().applyCss(); 
     scene.getRoot().layout(); 

     Bounds rootBounds = scene.getRoot().getLayoutBounds(); 
     stage.setX(primaryStage.getX() + (mainBounds.getWidth() - rootBounds.getWidth())/2); 
     stage.setY(primaryStage.getY() + (mainBounds.getHeight() - rootBounds.getHeight())/2); 
     stage.showAndWait(); 
     System.out.println("done"); 
    }); 
    Scene mainScene = new Scene(new StackPane(btnMain), 600, 600); 
    primaryStage.setScene(mainScene); 
    primaryStage.show(); 
} 
+0

Я не знаю, почему, но я получаю нули в корневых границах, даже если я leayout функцию до получения оценки. – scoozi17

2

В другом ответе правильно заявляет, JavaFX вычисляет ширину и высоту сцены при отображении окна. Свойство onShowing() вызывается до того, как выполняется вычисление, и до того, как окно станет видимым, поэтому размещение команды stage.hide() там фактически ничего не делает. И, как говорится в этом вопросе, увидеть блики на экране перед тем, как переместить окно, является менее желательным результатом.

Единственный способ, который я нашел для решения этой проблемы (хотя мне бы хотелось узнать, существует ли лучший способ) заключается в том, чтобы добавить Listeners в свойства ширины и высоты сцены и позволить им запустить событие для изменения положение окна. Затем, как только окно станет видимым, удалите Listeners.

, например:

//Let's say we want to center the new window in the parent window 

ChangeListener<Number> widthListener = (observable, oldValue, newValue) -> { 
     double stageWidth = newValue.doubleValue(); 
     stage.setX(parentStage.getX() + parentStage.getWidth()/2 - stageWidth/2); 
}; 
ChangeListener<Number> heightListener = (observable, oldValue, newValue) -> { 
     double stageHeight = newValue.doubleValue(); 
     stage.setY(parentStage.getY() + parentStage.getHeight()/2 - stageHeight/2); 
}; 

stage.widthProperty().addListener(widthListener); 
stage.heightProperty().addListener(heightListener); 

//Once the window is visible, remove the listeners 
stage.setOnShown(e -> { 
    stage.widthProperty().removeListener(widthListener); 
    stage.heightProperty().removeListener(heightListener); 
}); 

stage.show(); 
+0

Это со мной работало.Я не могу верить, что они не включили такой метод, как setLocationRelativeTo (что-то) - был на Swing. –