【问题标题】:JavaFX Stage size unpredictable after a show()在 show() 之后 JavaFX 舞台大小不可预测
【发布时间】:2018-07-02 15:04:19
【问题描述】:

操作系统:RHEL 7.4
DE:KDE Plasma 4.11.19 和 GNOME 3.22.2
Java 版本:9 和 10

在调用 show() 后,我在尝试计算 Stage 的大小时遇到​​问题。在 Java 8/RHEL 6 之前一切都运行良好,并且在 show() 之后我可以始终如一地获得舞台的大小。我只会听宽度和高度属性,但看起来舞台本身有一个更新,然后另一个更新添加了装饰尺寸,但是如果装饰尺寸为 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,数字不同)
案例一:
更改为显示属性后的舞台宽度和高度: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

编辑:似乎不能保证第二遍添加装饰,偶尔会在第一遍中完成。

【问题讨论】:

    标签: javafx redhat gnome kde-plasma javafx-9


    【解决方案1】:

    我无法给出明确的答案,因为我对 JavaFX 不是很有经验。

    所有的窗户都装饰了吗?如果没有,您可以先检查StageStyle,仅在装饰完成后回复。

    如果所有窗口都已装饰,是否等待应用更改是一个选项? 如果等待不是一个选项,属性outputScaleXouputScaleY 在应用可能的装饰后是否更新?如果没有,请改用它们。

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

    否则,您可以将这两个事件作为最后的手段。

    【讨论】:

    • outputScale 和 renderScale 属性在整个测试执行期间始终为 1.0。我宁愿不只是等待任意数量的时间,因为显示显示所需的时间会随着它的复杂性而增加。我也许可以遍历场景图来了解它的复杂程度以及等待它的基本时间,但我真的宁愿避免这种解决方法,因为仍然没有绝对的保证。关于使用 renderScale 属性,我不确定您的第三段是什么意思。对两者都做出反应是个问题,因为我什么时候停止?
    • 对不起,renderScaleX/Y 是我的错误,Java SE/SDK 9 窗口...最后一段是关于响应宽度和高度的变化,因为我认为它不会改变太频繁了
    【解决方案2】:

    最终选择了这个answer。稍作修改以等待至少 2 个事件(初始宽度和高度),然后再等待一段时间后查看是否还有更多事件。

    我对这个解决方案并不完全满意,但它现在可以工作并且仍然感觉很活泼。除了挂接到本机库之外,我不确定我还能做什么。

    但是,此解决方案引起的问题是在移动到我想要的位置之前显示在错误的位置。尝试在 show() 之前使用 setOpacity(0) ,然后在初始化之后使用 setOpacity(1) 似乎只能在一定程度上缓解问题,因为它偶尔仍会在一瞬间显示在错误的位置。

    【讨论】:

      猜你喜欢
      • 2016-12-13
      • 1970-01-01
      • 1970-01-01
      • 2018-07-05
      • 2013-07-22
      • 1970-01-01
      • 2017-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多