我想调整我的应用程序的大小。我想根据高度和宽度调整所有子元素及其字体大小和图像的大小。但我不希望字体大小和图像低于或超过某个值。
我按照以下页面上的说明进行操作:在 JavaFX 中绑定字体大小?
我附上了我的代码片段:
FXFontBindApp.java
:
package how.to.resize.in.java.fx;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class FXFontBindApp extends Application {
private DoubleProperty fontSize = new SimpleDoubleProperty(10);
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FontResizeExample.fxml"));
StackPane pane = fxmlLoader.load();
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.setTitle("Font Resize Example");
fontSize.bind(scene.widthProperty().add(scene.heightProperty()).divide(50));
pane.styleProperty().bind(Bindings.concat("-fx-font-size: ", fontSize.asString()));
primaryStage.show();
}
}
FXFontBindController.java
:
package how.to.resize.in.java.fx;
import javafx.fxml.Initializable;
import java.net.URL;
import java.util.ResourceBundle;
public class FXFontBindController implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
}
}
FontResizeExample.fxml
:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.collections.FXCollections?>
<?import java.lang.String?>
<StackPane fx:id="stackPane" stylesheets="@root.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="how.to.resize.in.java.fx.FXFontBindController">
<AnchorPane fx:id="anchorPane">
<VBox fx:id="outerVBox" spacing="10.0" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
<VBox fx:id="header" alignment="TOP_CENTER" VBox.vgrow="ALWAYS">
<Label fx:id="headerTitle" styleClass="title" text="Please enter username and password"/>
</VBox>
<VBox fx:id="enterRootPasswords" alignment="CENTER" VBox.vgrow="ALWAYS">
<VBox fx:id="rootPasswordFields" spacing="5.0" VBox.vgrow="ALWAYS">
<PasswordField fx:id="pin1" promptText="Pin" />
<HBox VBox.vgrow="ALWAYS">
<Region HBox.hgrow="ALWAYS" />
<Hyperlink fx:id="forgotPassword" alignment="CENTER" text="Forgot Password?" textAlignment="JUSTIFY" HBox.hgrow="ALWAYS" />
</HBox>
</VBox>
</VBox>
<VBox alignment="CENTER" VBox.vgrow="ALWAYS">
<VBox alignment="CENTER" VBox.vgrow="ALWAYS">
<Label fx:id="selectCardReaderLabel" text="Select Smart Card Reader" />
<ComboBox fx:id="selectCardReaderCombo" promptText="Select Smart Card Reader">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Three"/>
<String fx:value="Two"/>
<String fx:value="One"/>
</FXCollections>
</items>
</ComboBox>
</VBox>
</VBox>
<VBox fx:id="footer" alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<HBox fx:id="hBoxOkCancel" VBox.vgrow="ALWAYS">
<Region HBox.hgrow="ALWAYS" />
<Button fx:id="btnLogin" graphicTextGap="10.0" text="OK" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<Image url="@hook.png" />
</ImageView>
</graphic>
</Button>
</HBox>
</VBox>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
</AnchorPane>
</StackPane>
root.css
:
.label {
-fx-font-size: 0.9375em;
-fx-font-family: "Arial Black";
}
.title{
-fx-font-size: 1.25em;
-fx-font-family: "Arial Black";
}
.password-field {
-fx-font-size: 0.9375em;
-fx-font-family: "Arial Black";
}
.hyperlink {
-fx-font-size: 0.75em;
-fx-font-family: "Arial Black";
-fx-text-fill: #005f6a;
}
.button {
-fx-background-color: green;
-fx-text-fill: #ffffff;
-fx-font-family: "Arial Black";
-fx-font-size: 1em;
-fx-cursor: hand;
}
.button:hover {
-fx-background-color: darkgreen;
}
.combo-box-base {
-fx-background-color: green;
-fx-background-radius: 0;
-fx-font-size: 0.875em;
}
.combo-box-base:hover {
-fx-background-color: darkgreen;
}
.combo-box .list-cell {
-fx-text-fill: white;
-fx-font-size: 0.875em;
-fx-font-family: "Arial Black";
}
.combo-box-base .arrow-button .arrow {
-fx-background-color: white;
}
.combo-box-base:showing {
-fx-background-color: darkgreen;
}
.combo-box-base:showing:hover {
-fx-background-color: darkgreen;
}
.combo-box .combo-box-popup .list-view .list-cell {
-fx-background-color: green;
}
.combo-box .combo-box-popup .list-view .list-cell:hover,
.combo-box .combo-box-popup .list-view .list-cell:selected {
-fx-background-color: darkgreen;
}
此外,如下所示,这两行稍微改变了字体大小。我怎样才能另外解决这个问题?
fontSize.bind(scene.widthProperty().add(scene.heightProperty()).divide(50));
pane.styleProperty().bind(Bindings.concat("-fx-font-size: ", fontSize.asString()));
正如我在评论中指出的,您可能可以将字体大小绑定到计算大小和所需的最小大小的 max 。这样尺寸就永远不会低于您的最小值。
我没有尝试基于字体大小的解决方案,并且该答案的其余部分使用不同的方法,但基于字体大小的解决方案可能仍然是您的有效方法。
基于 DaveB 在评论中的建议的示例:
使用scaleX和scaleY缩放窗口的根元素
使用旧问题的解决方案更新:
解决方案背后的概念已在上面的答案中提供,因此我不再重复。
两种 UI 缩放方法各有优缺点,我在本网站上提供的有关界面缩放的其他一些答案中也讨论了这些方法。
标准方法是既不使用基于字体大小的缩放,也不使用基于缩放的缩放,而是使用布局窗格来调整界面,如原始 JavaFX 布局的 Oracle 教程中所述。
缩放通常最好保留在以下情况之一适用的情况下:
但是,对于窗口 UI,通常最好使 UI 元素保持相同的比例。 如果调整窗口大小,请调整 UI 以显示更多或更少的内容,而不是放大固定数量的内容。 如果尺寸发生根本变化(例如从笔记本电脑屏幕尺寸变为手机屏幕尺寸),那么通常会首选完全不同的 UI 设计。
UI 采用默认尺寸(也配置为最小尺寸)。
UI 全屏显示。
LetterBoxingApp.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class LetterBoxingApp extends Application {
// a MIN_SCALE >= 1 will ensure that the scene content is never sized below its initial size.
private static final double MIN_SCALE = 1;
@Override
public void start(Stage stage) throws Exception {
// load the content
FXMLLoader fxmlLoader = new FXMLLoader(
LetterBoxingApp.class.getResource(
"letterboxingSample.fxml"
)
);
Parent root = fxmlLoader.load();
// create a letterboxed scene.
LetterBoxer letterBoxer = new LetterBoxer();
Scene scene = letterBoxer.box(
root,
MIN_SCALE
);
// show the stage.
stage.setScene(scene);
stage.setTitle("Letterboxing Example");
stage.show();
// optional code to set the minimum stage size to the preferred size.
stage.setMinWidth(stage.getWidth());
stage.setMinHeight(stage.getHeight());
}
}
LetterBoxer.java
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.transform.Scale;
public class LetterBoxer {
public Scene box(final Parent node) {
return box(node, 1);
}
public Scene box(final Parent node, final double minScale) {
Scene scene = new Scene(new Group(node));
// generate a layout pass.
scene.getRoot().applyCss();
scene.getRoot().layout();
// determine the default ratio of laid out components.
final Bounds layoutBounds = scene.getRoot().getLayoutBounds();
final double initWidth = layoutBounds.getWidth();
final double initHeight = layoutBounds.getHeight();
final double ratio = initWidth / initHeight;
// configure a listener to adjust the size of the scene content (by scaling it).
BoxParams boxParams = new BoxParams(
scene, minScale, ratio, initHeight, initWidth, scene.getRoot()
);
// place the root in a stack to keep it centered.
// the root is also wrapped in Group so that the stack centers
// the scaled node rather than the untransformed node.
scene.setRoot(
new StackPane(
new Group(
scene.getRoot()
)
)
);
// adjust the size of the scene content (by scaling it) if the size changes.
BoxSizeAdjuster boxSizeAdjuster = new BoxSizeAdjuster(boxParams);
scene.widthProperty().addListener(boxSizeAdjuster);
scene.heightProperty().addListener(boxSizeAdjuster);
return scene;
}
private record BoxParams(
Scene scene,
double minScale,
double ratio,
double initHeight, double initWidth,
Parent content
) { }
private record BoxSizeAdjuster(BoxParams boxParams)
implements ChangeListener<Number> {
@Override
public void changed(
ObservableValue<? extends Number> observableValue,
Number oldValue,
Number newValue
) {
final double newWidth = boxParams.scene.getWidth();
final double newHeight = boxParams.scene.getHeight();
double scaleFactor =
Math.max(
newWidth / newHeight > boxParams.ratio
? newHeight / boxParams.initHeight
: newWidth / boxParams.initWidth,
boxParams.minScale
);
Scale scale = new Scale(scaleFactor, scaleFactor);
scale.setPivotX(0);
scale.setPivotY(0);
boxParams.content.getTransforms().setAll(scale);
}
}
}
letterBoxingSample.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import javafx.collections.FXCollections?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane stylesheets="@root.css" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1">
<center>
<VBox fx:id="outerVBox" spacing="10.0">
<VBox alignment="TOP_RIGHT" spacing="5.0">
<children>
<PasswordField fx:id="pin1" promptText="Pin" />
<Hyperlink fx:id="forgotPassword" alignment="CENTER" text="Forgot Password?" textAlignment="JUSTIFY" />
</children>
</VBox>
<VBox alignment="CENTER">
<Label fx:id="selectCardReaderLabel" text="Select Smart Card Reader" />
<ComboBox fx:id="selectCardReaderCombo" promptText="Select Smart Card Reader">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Three" />
<String fx:value="Two" />
<String fx:value="One" />
</FXCollections>
</items>
</ComboBox>
</VBox>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
</center>
<top>
<Label fx:id="headerTitle" styleClass="title" text="Please enter username and password" BorderPane.alignment="CENTER" />
</top>
<bottom>
<Button fx:id="btnLogin" graphicTextGap="10.0" text="OK" BorderPane.alignment="CENTER_RIGHT">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<Image url="@hook.png" />
</ImageView>
</graphic>
</Button>
</bottom>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</BorderPane>
钩子.png
问题中的复选框图像。
root.css
问题中的 CSS 示例。