简体   繁体   中英

JavaFX Stage size unpredictable after a show()

OS: RHEL 7.4
DE: KDE Plasma 4.11.19 and GNOME 3.22.2
Java version: 9 and 10

I'm having issues trying to figure out the size of a Stage after show() has been called. Everything was working fine before in Java 8/RHEL 6 and I could get the Stage's size consistently after a show(). I would just listen to the width and height property, but it looks like there is an update for the stage itself and then another update adding in the decoration size, but what if the decoration size is 0 as in this example the width of the decoration is 0 so I can't just listen for two changes each to the width and height property.

Am I doing this wrong? Is there some other event I can listen to that guarantees the Stage has been completely initialized after a show()? I added some sample code demonstrating the problem below.

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.stage.Stage;

public class JavaFXTest extends Application {

  public static void main(String[] args) {
      Application.launch(JavaFXTest.class);
  }

  @Override
  public void start(final Stage primaryStage) throws Exception {
    primaryStage.widthProperty().addListener(new ChangeListener<Number>() {
      @Override
      public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) {
       System.out.println("Width changed! Previous value = " + oldValue + ", new value = " + newValue);
      }
    });
    primaryStage.heightProperty().addListener(new ChangeListener<Number>() {
      @Override
      public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) {
       System.out.println("Height changed! Previous value = " + oldValue + ", new value = " + newValue);
      }
    });
    primaryStage.showingProperty().addListener(new ChangeListener<Boolean>() {
      @Override
      public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue, final Boolean newValue) {
        if(newValue) {
          Platform.runLater(() -> {
            final double width = primaryStage.getWidth();
            final double height = primaryStage.getHeight();
            System.out.println("Stage width and height after change to showing property (Platform.runLater): " + width + ", " + height);
          });
        }
      }
    });
    primaryStage.showingProperty().addListener(new ChangeListener<Boolean>() {
      @Override
      public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue, final Boolean newValue) {
        if(newValue) {
          final double width = primaryStage.getWidth();
          final double height = primaryStage.getHeight();
          System.out.println("Stage width and height after change to showing property: " + width + ", " + height);
        }
      }
    });
    primaryStage.show();
    Platform.runLater(() -> {
      final double width = primaryStage.getWidth();
      final double height = primaryStage.getHeight();
      System.out.println("Stage width and height immediately after show (Platform.runLater): " + width + ", " + height);
    });
    final double width = primaryStage.getWidth();
    final double height = primaryStage.getHeight();
    System.out.println("Stage width and height immediately after show:" + width + ", " + height);
  }
}

Here are some possible outputs of this program. The output is inconsistent.

Output on GNOME (and KDE, numbers differ)
Example Case 1:
Stage width and height after change to showing property: NaN, NaN
Stage width and height immediately after show: NaN, NaN
Stage width and height after change to showing property (Platform.runLater): NaN, NaN
Stage width and height immediately after show (Platform.runLater): NaN, NaN
Width changed! Previous value = NaN, new value = 318.0
Height changed! Previous value = NaN, new value = 171.0
Height changed! Previous value = 171.0, new value = 208.0

Example Case 2:
Stage width and height after change to showing property: NaN, NaN
Stage width and height immediately after show: NaN, NaN
Width changed! Previous value = NaN, new value = 318.0
Height changed! Previous value = NaN, new value = 171.0
Stage width and height after change to showing property (Platform.runLater): 318.0, 171.0
Stage width and height immediately after show (Platform.runLater): 318.0, 171.0
Height changed! Previous value = 171.0, new value = 208.0

EDIT: It also looks like a 2nd pass to add in decorations isn't guaranteed and will be done in the 1st pass occasionally.

I can't give a definite answer, as I am not very experienced with JavaFX.

Are all windows decorated? If not, you could perform a check on StageStyle first and only respond when decorating is finished.

If all windows are decorated, is waiting for the changes to be applied an option? If waiting isn't an option, are the properties outputScaleX and ouputScaleY updated after possible decoration is applied? If not, use those instead.

And finally, the Stage itself does not contain the width and height properties, those are properties of the Window it extends. You could always try using the renderScaleX and renderScaleY properties and take any space for a frame/margins/etc. into account when operating on those values.

Otherwise, you could respond to both events as a final resort.

Ended up going with this answer . Modified it slightly to wait for at least 2 events (an initial width and height) before waiting to see if there are any more after some time period.

I am not entirely satisfied with this solution, but it works for now and still feels snappy. Outside of hooking into native libraries I'm not sure what else I can do.

Issues caused by this solution however is a display showing up in the wrong place before being moved to where I want them. Trying to use setOpacity(0) before show() and then setOpacity(1) after initialization seems to only somewhat mitigate the problem as it occasionally still displays in the wrong position for a split second.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM