user1713946
user1713946

Reputation: 93

javafx maximized window moves if dialog shows up

If I create a javafx dialog using the following method:

public static void showDialog(Event event) throws IOException {
    dialogStage = new Stage();
    GridPane grid = (GridPane) Start.createLoader().load(Start.class.getResource("file.fxml").openStream());
    dialogStage.setScene(new Scene(grid));
    dialogStage.setTitle("Title");
    dialogStage.initModality(Modality.WINDOW_MODAL);
    dialogStage.initOwner(((Node) event.getSource()).getScene().getWindow());
    dialogStage.showAndWait();
}

the ower window moves in case it is maximized. This also happens if I use:

Modality.APPLICATION_MODAL

It works if I combine:

dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(primaryStage.getOwner());

but in this case the owner window is not blocked. I want my dialog showing up on a maximized window without moving it. The maximized window should be blocked while the dialog is open. How can I do this?

Btw. I am using java 8 and javafx on linux.

Tanks!

Upvotes: 4

Views: 830

Answers (2)

Dmitry Ovchinnikov
Dmitry Ovchinnikov

Reputation: 718

Finally I found another solution that works pretty fine on Linux. It uses a trick: if the user restores the window from the maximized state manually by double clicking on the title, and then maximizes it again by double clicking on the title, this bug is not reproduced anymore. To emulate double clicking I use the Robot:

stage.setMaximized(true);                                                                             
if (PlatformUtil.isLinux()) { // a workaround of a bug of modal dialogs shown on top of the stage     
  stage.setAlwaysOnTop(true);                                                                         
  stage.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<>() {                              
    @Override                                                                                         
    public void handle(WindowEvent windowEvent) {                                                     
      stage.removeEventHandler(WindowEvent.WINDOW_SHOWN, this);                                       
      new Thread(() -> {                                                                              
        doubleClick();                                                                                
        LockSupport.parkNanos(10_000_000L);                                                           
        doubleClick();                                                                                
        Platform.runLater(() -> stage.setAlwaysOnTop(false));                                         
      }).start();                                                                                     
    }                                                                                                 
                                                                                                      
    private void doubleClick() {                                                                      
      robotAction(stage, r -> r.mouseClick(MouseButton.PRIMARY));                                     
      LockSupport.parkNanos(1_000_000L);                                                              
      robotAction(stage, r -> r.mouseClick(MouseButton.PRIMARY));                                     
    }                                                                                                 
                                                                                                      
    private void robotAction(Stage stage, Consumer<Robot> action) {                                   
      var latch = new CountDownLatch(1);                                                              
      Platform.runLater(() -> {                                                                       
        try {                                                                                         
          var robot = new Robot();                                                                    
          var centerX = stage.getX() + stage.getWidth() / 2d;                                         
          robot.mouseMove(centerX, stage.getY() + 3d);                                                
          action.accept(robot);                                                                       
        } finally {                                                                                   
          latch.countDown();                                                                          
        }                                                                                             
      });                                                                                             
      try {                                                                                           
        latch.await();                                                                                
      } catch (InterruptedException e) {                                                              
        throw new IllegalStateException(e);                                                           
      }                                                                                               
    }                                                                                                 
  });                                                                                                 
}                                                                                                     
stage.show();                                                                                         

Upvotes: 0

Dmitry Ovchinnikov
Dmitry Ovchinnikov

Reputation: 718

As a workaround for Linux it's possible to use this trick:

  stage.setMaximized(true);
  if (PlatformUtil.isLinux()) {
    stage.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<>() {
      @Override
      public void handle(WindowEvent windowEvent) {
        stage.removeEventHandler(WindowEvent.WINDOW_SHOWN, this);
        Platform.runLater(() -> {
          var bounds = new Rectangle2D(stage.getX(), stage.getY(), stage.getWidth(), stage.getHeight());
          stage.setMaximized(false);
          stage.setX(bounds.getMinX());
          stage.setY(bounds.getMinY());
          stage.setWidth(bounds.getWidth());
          stage.setHeight(bounds.getHeight());
          stage.setMaximized(true);
        });
      }
    });
  }

Upvotes: 0

Related Questions