尝试在控制器中同时使用原始和全屏版本的Panes也会更改窗口版本中的Panes

时间:2019-06-12 22:03:17

标签: java javafx hashmap

我有一个ScreenController类,该类可以轻松切换JavaFX程序中的根窗格。它使用HashMap进行此操作,该HashMap使用String键存储Pane值。

我试图进行设置,以便每当将新Panes添加到SceneController对象时,它都会创建给定Pane的全屏版本,并将其添加到第二个HashMap中,该HashMap具有与第一个相同的String键。

但是,每当我现在切换屏幕时,总是使用全屏版本的窗格。

即使Java是按值传递的,我用来创建全屏窗格版本的goFullscreen()方法似乎也在修改这两个方法。

如何在我的ScreenController类windowedRootMap中获取HashMap属性,而不用全屏缩放返回原始窗格?

/**
 * Creates an appropriately scaled fullscreen version of the argument Pane object.
 * 
 * @param contentPane The Pane to create a fullscreen version of.
 * @return Pane
 */
private static Pane goFullscreen(Pane contentPane) {

   // get original dimensions and their ratio.
   final double windowedWidth = 1280.0;
   final double windowedHeight = 800.0;
   final double windowedRatio = windowedWidth / windowedHeight;

   // get fullscreen width and height from monitor dimensions
   final double fullscreenWidth = Screen.getPrimary().getBounds().getWidth();
   final double fullscreenHeight = Screen.getPrimary().getBounds().getHeight();

   // find how much to scale by
   double scaleFactor;
   if (fullscreenWidth / fullscreenHeight > windowedRatio)
      scaleFactor = fullscreenHeight / windowedHeight;
   else
      scaleFactor = fullscreenWidth / windowedWidth;

   // scale the contents of the Pane appropriately
   Scale scale = new Scale(scaleFactor, scaleFactor);
   contentPane.getTransforms().setAll(scale);
   contentPane.setPrefWidth(fullscreenWidth / scaleFactor);
   contentPane.setPrefWidth(fullscreenHeight / scaleFactor);

   return contentPane;
}

/**
 * Allows switching root nodes easily.
 */
private class ScreenController {

   private HashMap<String, Pane> windowedRootMap = new HashMap<>();
   private HashMap<String, Pane> fullscreenRootMap = new HashMap<>();
   private Scene currentScene;

   private ScreenController(Scene currentScene) {

      this.currentScene = currentScene;
   }

   private void addScreen(String name, Pane pane) {

      this.windowedRootMap.put(name, pane);
      this.fullscreenRootMap.put(name, goFullscreen(pane));
   }

   private void activate(String name) {

      this.currentScene.setRoot(this.windowedRootMap.get(name));
   }
}

1 个答案:

答案 0 :(得分:2)

您是正确的,Java是按值传递,但是传递“值”是错误的。在Java中,它是对复制对象的引用,但是新引用仍然指向同一对象 instance 。以下问题的许多出色答案对此进行了详细解释:

假设您不想维护两个不同的Pane实例,一种选择是根据所处的模式简单地设置属性。我不确定要显示的代码是什么像最后一样,但看起来可能像这样:

import java.util.Map;
import java.util.HashMap;
import javafx.geometry.Dimension2D;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.transform.Scale;

public class ScreenController {

    private final Map<String, Foo> map = new HashMap<>();
    private final Scene scene;

    public ScreenController(Scene scene) {
        this.scene = scene;
    }

    public void register(String name, Pane pane) {
        map.put(name, pane);
    }

    public void activate(String name) {
        scene.setRoot(map.get(name).pane);
    }

    private static class Foo {

        private final Pane pane;
        private final Dimension2D normalSize;
        private final Dimension2D fullScreenSize;
        private final Scale scale;

        private Foo(Pane pane) {
            this.pane = pane;
            // set the other fields...
        }

        private void enterFullScreenMode() {
             pane.setPrefSize(fullScreenSize.getWidth(), fullScreenSize.getHeight());
             pane.getTransforms().add(scale);
        }

        private void exitFullScreenMode() {
             pane.setPrefSize(normalSize.getWidth(), normalSize.getHeight());
             pane.getTransforms().remove(scale);
        }

    }

}

注意:我未包含任何参数或状态验证。

但是请记住,Scene的根的大小与场景图中“常规”节点的大小不同。设置首选大小可能不会起作用。来自documentation

  

应用程序必须通过设置Node属性来为场景图指定根root。如果将Group用作根,则场景图的内容将被场景的宽度和高度限制,并且更改场景的大小(如果用户调整舞台的大小)将不会更改场景图的布局。如果将可调整大小的节点(布局RegionControl)设置为根,则根的大小将跟踪场景的大小,从而根据需要中继内容。


如果只有一定数量的屏幕,请考虑使用enum作为Map的键,而不是String。还可以看看java.util.EnumMap