【问题标题】:JavaFX fullscreen - resizing elements based upon screen sizeJavaFX 全屏 - 根据屏幕大小调整元素大小
【发布时间】:2013-05-12 10:50:34
【问题描述】:

有没有办法让全屏(如果可能的话也调整大小)而不是重新排列所有内容(实际上它所做的是重新排列元素,如调整大小但到整个屏幕)来制作实际的全屏模式? (比如游戏通常会改变屏幕分辨率),以便按钮和文本根据屏幕/窗口的大小相应增长

另外,如何删除消息以及单击“esc”键退出全屏模式的效果?

编辑:使用这种方式来调整大小

@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);
        }
    });
}

【问题讨论】:

    标签: javafx-2 fullscreen


    【解决方案1】:

    有几种方法可以调整 UI 大小。

    按字号缩放

    您可以通过在场景样式表的.root 中设置-fx-font-size 来缩放所有控件。

    例如,如果您将以下样式表应用到您的场景中,那么所有控件的大小都会加倍(因为默认字体大小为 13px)。

    .root { -fx-字体大小:26px; }

    以上内容适用于缩放控件,这对于完全基于控件的事物来说很好,但对于基于图形和形状的事物来说不是那么好。

    按变换缩放

    将一个以 (0,0) 为轴心的 Scale 变换应用到场景的根节点。

    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 中可以:

    RT-15314 Allow trusted apps to disable the fullscreen overlay warning and disable the "Exit on ESC" behavior

    这样做会很好,因为这样我的游戏就不会有那种“看着我 - 我看起来像测试版”的感觉。

    【讨论】:

    • 非常感谢,试了一点代码,好像还可以,虽然没想到全屏会这么麻烦,这么难……
    • 稍微修改了监听器的代码,但是改变根的宽度/高度不起作用,所以当场景变得比原来大时,根元素会在它之外,但是当更小时,不会没有涵盖整个场景,可以帮我解决这个问题吗?代码在以下链接上:codepaste.net/cm5jzn(我以以下方式初始化场景 Scene s = new Scene(new Controller()),其中 Controller 扩展了一个窗格(由于我更改了窗格,因此可能会有所不同);
    • 抱歉,您的解决方案与我的有点不同,我无法真正为您调试。我确实整理了一个executable example of the letter boxing snippet from this post,以防可能对您有所帮助。祝你好运:-)
    • 好吧,我的问题是Region.setPrefWidth()Region.setPrefSize() 和类似的都不起作用,甚至尝试将 min、max 和 pref 同时设置为场景值或任何随机值,但窗格大小没有受到影响
    • 似乎问题在于无法修改根宽度/高度,以工作方式编辑帖子(在场景和视图之间使用窗格作为根)
    【解决方案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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-19
        • 2017-12-02
        • 1970-01-01
        • 2020-09-29
        • 2014-06-20
        • 2015-07-16
        相关资源
        最近更新 更多