JavaFX полноэкранный режим - изменение размера элементов на основе размера экрана

Есть ли способ сделать полноэкранный режим (и, если возможно, изменить размер), вместо того, чтобы переупорядочить все (на самом деле это то, что он делает, чтобы изменить элементы, такие как изменение размера, но и весь экран), чтобы создать реальный полноэкранный режим? (например, игры, в которых обычно происходит изменение разрешения экрана), так что кнопки и текст растут соответственно размеру экрана/окна

Также как я могу удалить сообщение и эффект нажатием клавиши "esc", чтобы выйти из полноэкранного режима?

EDIT: используйте этот способ для изменения размера

@Override public void start(Stage stage) throws Exception{
    final int initWidth = 720;      //initial width
    final int initHeight = 1080;    //initial height
    final Pane root = new Pane();   //necessary evil

    Pane controller = new CtrlMainMenu();   //initial view
    controller.setPrefWidth(initWidth);     //if not initialized
    controller.setPrefHeight(initHeight);   //if not initialized
    root.getChildren().add(controller);     //necessary evil

    Scale scale = new Scale(1, 1, 0, 0);
    scale.xProperty().bind(root.widthProperty().divide(initWidth));     //must match with the one in the controller
    scale.yProperty().bind(root.heightProperty().divide(initHeight));   //must match with the one in the controller
    root.getTransforms().add(scale);

    final Scene scene = new Scene(root, initWidth, initHeight);
    stage.setScene(scene);
    stage.setResizable(true);
    stage.show();

    //add listener for the use of scene.setRoot()
    scene.rootProperty().addListener(new ChangeListener<Parent>(){
        @Override public void changed(ObservableValue<? extends Parent> arg0, Parent oldValue, Parent newValue){
            scene.rootProperty().removeListener(this);
            scene.setRoot(root);
            ((Region)newValue).setPrefWidth(initWidth);     //make sure is a Region!
            ((Region)newValue).setPrefHeight(initHeight);   //make sure is a Region!
            root.getChildren().clear();
            root.getChildren().add(newValue);
            scene.rootProperty().addListener(this);
        }
    });
}

Ответ 1

Существует несколько способов изменения размера пользовательского интерфейса.

Масштабирование по размеру шрифта

Вы можете масштабировать все элементы управления, установив -fx-font-size в .root вашей таблицы стилей.

Например, если вы примените следующую таблицу стилей к своей сцене, все элементы управления будут удвоены по размеру (поскольку размер шрифта по умолчанию составляет 13 пикселей).

.root {    -fx-font-size: 26px;  }

Вышеупомянутое будет работать над масштабированием элементов управления, что отлично подходит для вещей, которые полностью управляются на основе, но не настолько хороши для вещей, которые являются графическими и основанными на фигуре.

Масштабирование с помощью преобразования

Примените преобразование Scale, повернутое в (0,0) к корню вашей сцены node.

Scale scale = new Scale(scaleFactor, scaleFactor);
scale.setPivotX(0);
scale.setPivotY(0);
scene.getRoot().getTransforms().setAll(scale);

Чтобы масштабировать игру, которую я разработал, которая включает в себя графику и различные формы, я использовал технику письма с боксом, которая определяла игровое окно постоянным соотношением сторон (похоже на буквенный бокс, который вы видите при просмотре телешоу 4: 3 на экране 16: 9).

SceneSizeChangeListener в коде ниже прослушивает изменения размера сцены и масштабирует содержимое сцены, соответствующее размеру доступной сцены.

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;
import org.jewelsea.games.supersnake.layout.LayoutController;

import java.io.IOException;
import java.util.ResourceBundle;

/* Main JavaFX application class */
public class SuperSnake extends Application {
  public static void main(String[] args) { launch(args); }

  @Override public void start(final Stage stage) throws IOException {
    FXMLLoader loader = new FXMLLoader(
        getClass().getResource("layout/layout.fxml"),
        ResourceBundle.getBundle("org.jewelsea.games.supersnake.layout.text")
    );
    Pane root = (Pane) loader.load();

    GameManager.instance().setLayoutController(loader.<LayoutController>getController());

    Scene scene = new Scene(new Group(root));
    stage.setScene(scene);
    stage.show();

    GameManager.instance().showMenu();

    letterbox(scene, root);
    stage.setFullScreen(true);
  }

  private void letterbox(final Scene scene, final Pane contentPane) {
    final double initWidth  = scene.getWidth();
    final double initHeight = scene.getHeight();
    final double ratio      = initWidth / initHeight;

    SceneSizeChangeListener sizeListener = new SceneSizeChangeListener(scene, ratio, initHeight, initWidth, contentPane);
    scene.widthProperty().addListener(sizeListener);
    scene.heightProperty().addListener(sizeListener);
  }

  private static class SceneSizeChangeListener implements ChangeListener<Number> {
    private final Scene scene;
    private final double ratio;
    private final double initHeight;
    private final double initWidth;
    private final Pane contentPane;

    public SceneSizeChangeListener(Scene scene, double ratio, double initHeight, double initWidth, Pane contentPane) {
      this.scene = scene;
      this.ratio = ratio;
      this.initHeight = initHeight;
      this.initWidth = initWidth;
      this.contentPane = contentPane;
    }

    @Override
    public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
      final double newWidth  = scene.getWidth();
      final double newHeight = scene.getHeight();

      double scaleFactor =
          newWidth / newHeight > ratio
              ? newHeight / initHeight
              : newWidth / initWidth;

      if (scaleFactor >= 1) {
        Scale scale = new Scale(scaleFactor, scaleFactor);
        scale.setPivotX(0);
        scale.setPivotY(0);
        scene.getRoot().getTransforms().setAll(scale);

        contentPane.setPrefWidth (newWidth  / scaleFactor);
        contentPane.setPrefHeight(newHeight / scaleFactor);
      } else {
        contentPane.setPrefWidth (Math.max(initWidth,  newWidth));
        contentPane.setPrefHeight(Math.max(initHeight, newHeight));
      }
    }
  }
}

Вот скриншот, в котором вы можете видеть, как почтовый ящик и масштабирование вступают в силу. Зеленая трава посередине является основным экраном игрового контента и масштабируется вверх и вниз, чтобы соответствовать доступной площади экрана. Текстура древесины вокруг снаружи обеспечивает границу гибкого размера, которая заполняет область, где черные полосы почтового ящика обычно бывают, если вы смотрели телевизионную программу с другим соотношением сторон на экране. Обратите внимание, что фон на скриншоте ниже размывается на титульном листе, потому что я делаю это так, когда игра начинается, эффект размытия удаляется, а представление четкое, независимо от размера.

Оконная версия:

letterbox

Масштабированная полноэкранная версия:

letterbox-full-screen

Вы можете подумать, что метод масштабирования выше может сделать все чересчур блочным и пиксельным, но это не так. Все шрифты и элементы управления масштабируются. Все стандартные чертежные и графические команды и стили на основе CSS основаны плавно, поскольку все они основаны на векторе. Даже растровые изображения хорошо масштабируются, потому что JavaFX использует фильтры с довольно высоким качеством при масштабировании изображений.

Один трюк для хорошего масштабирования изображений - это предоставление изображений с высоким разрешением, поэтому, когда экран масштабируется, система JavaFX имеет больше исходных данных для работы. Например, если предпочтительный размер окна для приложения составляет четверть от размера экрана, и он содержит значок 64x64, вместо этого используйте значок 128x128, так что, когда приложение будет помещено в полный экран, и все элементы масштабируются, пиксельных данных для использования для интерполяции значений.

Масштабирование также выполняется быстро, поскольку аппаратное ускорение.

как удалить сообщение и эффект нажатием клавиши "esc", чтобы выйти из полноэкранного режима?

Невозможно удалить сообщение завершения полного экрана в JavaFX 2.2, это будет возможно в JavaFX 8:

RT-15314 Разрешить доверенным приложениям отключить всплывающее окно предупреждения и отключить поведение "Выход на ESC"

Будет хорошо, когда это будет сделано, потому что тогда у моих игр не будет такого "взгляда на меня - я выгляжу как бета", о них.

Ответ 2

"Также как удалить сообщение и эффект нажатием клавиши" esc ", чтобы выйти из полноэкранного режима?"

Используйте этот код:

stage.setFullScreenExitHint("");

Он изменит строковое сообщение "Нажмите Esc, чтобы выйти из полноэкранного режима" в пустую строку, чтобы он не отображался.

Ответ 3

Вы можете скопировать это в JavaFXApplication

Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
double width = resolution.getWidth();
double height = resolution.getHeight(); 
double w = width/1280;  // your window width
double h = height/720;  // your window height
Scale scale = new Scale(w, h, 0, 0);
root.getTransforms().add(scale);