show()之后,JavaFX舞台大小无法预测

时间:2018-07-02 15:04:20

标签: javafx redhat gnome kde javafx-9

OS:RHEL 7.4
DE:KDE Plasma 4.11.19和GNOME 3.22.2
Java版本:9和10

在调用show()后试图计算舞台的大小时遇到​​问题。在Java 8 / RHEL 6之前,一切工作正常,在show()之后,我可以一致地获得舞台的大小。我只是听一下width和height属性,但看起来舞台本身有一个更新,然后又添加了装饰大小的另一个更新,但是如果装饰大小为0,如本例中所示,那么装饰宽度是0,所以我不能只听每个width和height属性的更改。

我做错了吗?我还有其他事件可以确保舞台在show()之后被完全初始化吗?我添加了一些示例代码来演示以下问题。

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);
  }
}

以下是该程序的一些可能输出。输出不一致。

GNOME上的输出(和KDE,数字不同)
示例案例1:
更改为显示属性后的舞台宽度和高度:NaN,NaN
演出后立即显示舞台宽度和高度:NaN,NaN
更改为显示属性(Platform.runLater)后的舞台宽度和高度:NaN,NaN
放映后立即显示的舞台宽度和高度(Platform.runLater):NaN,NaN
宽度改变了!上一个值= NaN,新值= 318.0
高度改变了!上一个值= NaN,新值= 171.0
高度改变了!上一个值= 171.0,新值= 208.0

示例2:
更改为显示属性后的舞台宽度和高度:NaN,NaN
演出后立即显示舞台宽度和高度:NaN,NaN
宽度改变了!上一个值= NaN,新值= 318.0
高度改变了!上一个值= NaN,新值= 171.0
更改为显示属性后的舞台宽度和高度(Platform.runLater):318.0,171.0
放映后立即显示的舞台宽度和高度(Platform.runLater):318.0,171.0
高度改变了!上一个值= 171.0,新值= 208.0

编辑:看起来还不能保证第二遍添加装饰,并且偶尔会在第一遍完成。

2 个答案:

答案 0 :(得分:0)

我不能给出确切的答案,因为我对JavaFX的使用不是很熟练。

所有窗户都装饰好了吗?如果没有,您可以先对StageStyle进行检查,并且仅在装饰完成后做出响应。

如果所有窗户都装饰好了,是否可以选择等待更改? 如果无法等待,是否在应用可能的修饰后更新属性outputScaleXouputScaleY?如果没有,请改用那些。

最后,Stage本身不包含widthheight属性,它们是它扩展的Window的属性。您始终可以尝试使用renderScaleXrenderScaleY属性,并为框架/边距/等占用任何空间。在使用这些值时应考虑在内。

否则,您可以对这两个事件做出最后回应。

答案 1 :(得分:0)

最终使用此answer。对其进行了稍微修改,以等待至少2个事件(初始宽度和高度),然后再等待一段时间后再查看是否有其他事件。

我对这种解决方案并不完全满意,但是它目前可以使用,但仍然感觉很敏捷。除了迷上本机库外,我不确定还能做什么。

此解决方案引起的问题是显示器显示在错误的地方,然后转移到我想要的地方。尝试在show()之前使用setOpacity(0),然后在初始化之后使用setOpacity(1)似乎只能缓解该问题,因为它偶尔仍会在错误的位置显示一秒钟。