Попытка использовать как оригинальную, так и полноэкранную версии панелей в моем контроллере также приводит к изменению панелей в оконной версии. - PullRequest
0 голосов
/ 13 июня 2019

У меня есть класс ScreenController, который позволяет легко переключать корневые панели в программе JavaFX. Это делается с помощью HashMap, в котором хранятся значения Pane с ключами String.

Я попытался настроить его так, чтобы при каждом добавлении новых панелей к объекту SceneController он создавал полноэкранную версию заданной панели и добавлял ее во вторую HashMap с тем же ключом String, что и первый.

Однако всякий раз, когда я переключаю экраны, всегда используется полноэкранная версия панели.

Похоже, что метод goFullscreen(), который я использую для создания полноэкранных версий Pane, изменяет обе версии, даже если Java передается по значению.

Как я могу получить атрибут HashMap в моем классе ScreenController, windowedRootMap, вернуть исходные панели без полноэкранного масштабирования?

/**
 * 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 Ответ

2 голосов
/ 13 июня 2019

Вы правы, что Java является передачей по значению , но ошибочно указываете, какое "значение" передается. В Java это ссылка на объект, который копируется, но эта новая ссылка все еще указывает на тот же объект экземпляр . Это объясняется более подробно многими замечательными ответами на следующий вопрос:

Если вы не хотите поддерживать два разных экземпляра 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 имеет размер, отличный от "обычных" узлов в графе сцены. Установка предпочтительного размера, скорее всего, не будет иметь никакого эффекта. Из документации .

Приложение должно указать корень Node для графа сцены, установив свойство root. Если в качестве корня используется Group, содержимое графа сцены будет обрезано по ширине и высоте сцены, и изменение размера сцены (если пользователь изменяет размер сцены) не изменит макет графа сцены. Если в качестве корня установлен узел с изменяемым размером (макет Region или Control), то размер корня будет отслеживать размер сцены, вызывая при необходимости ретрансляцию содержимого.


Если у вас есть только заданное количество экранов, рассмотрите возможность использования enum в качестве клавиши Map вместо String. Также взгляните на java.util.EnumMap.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...