我們在開發桌面程式時,對於視窗的放大縮小一直都不好控制,畫面一旦複雜起來,在縮放的過程中常常容易跑版。
於是就想說,如果可以像遊戲一樣,對整個畫面進行等比放大,那就會方便許多。
以下方法就是類似於遊戲整體放大方法,我們先以一個預設解析度來設計UI,最後讓者個畫面有等比縮放功能。
1.建立畫面架構
我們需要一個以GridPane為根的底,然後塞入一層AnchorPane。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="gp_test" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="768.0" prefWidth="1366.0" stylesheets="@../css/style.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.lugia.controllers.TestActivityController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<AnchorPane fx:id="ap_test" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="768.0" prefWidth="1366.0" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
</children>
</GridPane>
在GridPane中,主要需要設定好寬高,以pref參數為主,其他min與max的寬高度都設為USE_PREF_SIZE
在AnchorPane中,要設定valignment與halignment為CENTER,如上面程式碼。
接下來就可以在AnchorPane中放入自己的元件了。
2.畫面的main程式設定
package com.lugia;
import com.lugia.controllers.MainActivityController;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;
public class MainActivity extends Application {
private MainActivityController controller;
@Override
public void start(Stage primaryStage) throws Exception{
//反鋸齒
System.setProperty("prism.lcdtext", "false");
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getClassLoader().getResource("fxml/main_activity.fxml"));
Pane root = fxmlLoader.load();
primaryStage.setTitle("Test");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
//視窗顯示確定大小後,再做最小尺寸限制
primaryStage.setMinWidth(primaryStage.getWidth());
primaryStage.setMinHeight(primaryStage.getHeight());
controller = fxmlLoader.getController();
letterbox(scene, root);
// primaryStage.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;
//如須能縮小,則設為0(或一個最小的倍數)
if (scaleFactor >= 1) {
Scale scale = new Scale(scaleFactor, scaleFactor);
//如需要中心放大,則使用(newWidth/2),(newHeight/2),測試用的root元件為GridPane,Alignment設為TOP_LEFT,第二層為AnchorPane,V/Halignment設為CENTER
scale.setPivotX(newWidth/2);
scale.setPivotY(newHeight/2);
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));
}
}
}
public static void main(String[] args) {
launch(args);
}
@Override
public void stop() {
controller.onClose();
}
}
3.執行效果
原始大小(約1366*768):

畫面放到最大(約1920*1080):注意頂部TITLE跟畫面UI的比例,視窗整個放大後不會跑版

-END-
發佈留言