Ответ 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));
}
}
}
}
Вот скриншот, в котором вы можете видеть, как почтовый ящик и масштабирование вступают в силу. Зеленая трава посередине является основным экраном игрового контента и масштабируется вверх и вниз, чтобы соответствовать доступной площади экрана. Текстура древесины вокруг снаружи обеспечивает границу гибкого размера, которая заполняет область, где черные полосы почтового ящика обычно бывают, если вы смотрели телевизионную программу с другим соотношением сторон на экране. Обратите внимание, что фон на скриншоте ниже размывается на титульном листе, потому что я делаю это так, когда игра начинается, эффект размытия удаляется, а представление четкое, независимо от размера.
Оконная версия:
Масштабированная полноэкранная версия:
Вы можете подумать, что метод масштабирования выше может сделать все чересчур блочным и пиксельным, но это не так. Все шрифты и элементы управления масштабируются. Все стандартные чертежные и графические команды и стили на основе CSS основаны плавно, поскольку все они основаны на векторе. Даже растровые изображения хорошо масштабируются, потому что JavaFX использует фильтры с довольно высоким качеством при масштабировании изображений.
Один трюк для хорошего масштабирования изображений - это предоставление изображений с высоким разрешением, поэтому, когда экран масштабируется, система JavaFX имеет больше исходных данных для работы. Например, если предпочтительный размер окна для приложения составляет четверть от размера экрана, и он содержит значок 64x64, вместо этого используйте значок 128x128, так что, когда приложение будет помещено в полный экран, и все элементы масштабируются, пиксельных данных для использования для интерполяции значений.
Масштабирование также выполняется быстро, поскольку аппаратное ускорение.
как удалить сообщение и эффект нажатием клавиши "esc", чтобы выйти из полноэкранного режима?
Невозможно удалить сообщение завершения полного экрана в JavaFX 2.2, это будет возможно в JavaFX 8:
Будет хорошо, когда это будет сделано, потому что тогда у моих игр не будет такого "взгляда на меня - я выгляжу как бета", о них.