JavaFX 中绑定字体大小?

问题描述 投票:0回答:5

我想让我的申请变得流畅。但是,当我将窗口变大时,与 UI 元素相比,字体看起来很小。最终,我希望在调整窗口大小时文本的大小变大或变小。我知道理论上我可以使用 style 属性来做到这一点,但在某些情况下我已经将该属性绑定到其他内容。

我知道有“fontProperty”方法,但我没有任何东西可以绑定到它,因为我不知道如何创建具有同步大小的动态 ObjectProperty。我该怎么办?

编辑:为了避免混淆,我试图根据其他因素来改变字体大小,而不是相反。

java user-interface data-binding fonts javafx
5个回答
17
投票

只需将所有想要更改字体大小的内容放入容器中,然后设置该样式或根据需要使用绑定。

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class FontBind extends Application {

    private DoubleProperty fontSize = new SimpleDoubleProperty(10);
    private IntegerProperty blues = new SimpleIntegerProperty(50);

    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button("click me, I change color");
        btn.setOnAction((evt)->{blues.set(blues.get()+20);});//max?
        Label lbl = new Label("I'm a label");
        TextArea ta = new TextArea("Lots of text can be typed\nand even number 1234567890");
        HBox hbox = new HBox(new Label("I never change"));
        VBox child = new VBox(btn, lbl, ta);
        VBox root = new VBox(child, hbox);
        Scene scene = new Scene(root, 300, 250);

        fontSize.bind(scene.widthProperty().add(scene.heightProperty()).divide(50));
        child.styleProperty().bind(Bindings.concat("-fx-font-size: ", fontSize.asString(), ";"
                                                  ,"-fx-base: rgb(100,100,",blues.asString(),");"));

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

我不确定你的样式已经绑定到什么,但你可以在样式字符串中设置多个 css 值。


10
投票

设置.root -fx-font-size

  1. 为您的应用程序创建一个自定义样式表

  2. 在 sylesheet

    .root
    选择器中,将
    -fx-font-size
    设置为您想要的值:

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

如果需要,可以按照

Stylesheet API
中的描述使用 data: URI 将样式表数据设置为字符串值。 这允许您以编程方式创建样式表数据,并根据需要在运行时应用它(例如,对于不同的计算字体大小)。

为什么这有效

这之所以有效,是因为:

  1. 所有默认控件均基于
    em
    单位(基于默认字体大小)。
  2. -fx-font-size
    是一种继承风格。
  3. 一切都从根源继承。

一旦执行此操作,所有控件(以及其中的文本)将自动调整大小以适合您指定的任何字体大小。

相关样本

相关资讯

em
是一个通用单位,并非特定于 JavaFX,em 单位也用于 HTML CSS 中。 如果有兴趣,您可以阅读有关 em 单位与其他单位的更广泛讨论

通过表达式绑定在 FXML 中使用 em 单位

仅设置默认字体大小即可使您达到所需位置的大约 90%,但不一定是通用修复,因为某些布局单位可能不使用 em 单位指定。 大多数情况下,这并不是真正的问题,但如果是您的情况,您还可以应用 Oracle 开发人员邮件列表帖子中描述的机制,该机制似乎有效,但有点笨拙。

使用表达式绑定怎么样。

对于 35em x 25em 你可以写:

prefWidth="${35*u.em}" prefHeight="${25*u.em}"

它不是 100% 简洁,但也许还过得去。

这些尺寸表达式可以在场景构建器 1.1 中使用,这很好。


这里是一个使用矩形来存储 fxml 文件的宽度和高度修饰符的示例。

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>

<StackPane xmlns:fx="http://javafx.com/fxml">
<fx:define>
  <Rectangle fx:id="s" width="13" height="13"/>
</fx:define>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="${22 * s.width}" prefWidth="${14 * s.height}">
  <children>
    <Button layoutX="${4 * s.width}" layoutY="${ 5 * s.height}" prefWidth="${6 * s.width}" text="Top" />
    <Button layoutX="${4 * s.width}" layoutY="${10 * s.height}" prefWidth="${6 * s.width}" text="Middle" />
    <Button layoutX="${4 * s.width}" layoutY="${15 * s.height}" prefWidth="${6 * s.width}" text="Bottom" />
  </children>
</AnchorPane>
</StackPane>

或者,您可以创建自己的单位类并在大小调整表达式中使用它,例如:

package org.jewelsea.measure;

public class Measurement {
  private double em;
  public  void   setEm(double em) { this.em = em; }
  public  double getEm()          { return em; }
}

. . .

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.jewelsea.measure.Measurement?>
<?scenebuilder-classpath-element .?>

<StackPane xmlns:fx="http://javafx.com/fxml">
  <fx:define>
    <Measurement fx:id="u" em="26.0" />
  </fx:define>
  <AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="${22*u.em}" prefWidth="${14*u.em}">
    <children>
      <Button layoutX="${4*u.em}" layoutY="${ 5*u.em}" prefWidth="${6*u.em}" text="Top" />
      <Button layoutX="${4*u.em}" layoutY="${10*u.em}" prefWidth="${6*u.em}" text="Middle" />
      <Button layoutX="${4*u.em}" layoutY="${15*u.em}" prefWidth="${6*u.em}" text="Bottom" />
    </children>
  </AnchorPane>
</StackPane>

7
投票

有一个最简单且正确的方法,将字体大小与容器大小绑定,以使其达到响应式字体缩放效果。

bind(Bindings.concat("-fx-font-size: "
是一个很好的选择,但是当您调整窗口大小时,它似乎非常慢,我认为这不是解决问题的正确方法。

您可以声明 FontProperty 并将此 FontProperty 绑定到组件(Label、Text 等),最后根据我们的设计创建一个事件将大小与 FontProperty 大小绑定:

private Label textTracking = new Label();
private ObjectProperty<Font> fontTracking = new SimpleObjectProperty<Font>(Font.getDefault());

然后在构造函数或某些 init 方法中,您可以将对象的字体属性与动态字体绑定:

textTracking.fontProperty().bind(fontTracking);

最后,需要将包装容器更改大小与动态字体大小绑定:

    widthProperty().addListener(new ChangeListener<Number>()
    {
        @Override
        public void changed(ObservableValue<? extends Number> observableValue, Number oldWidth, Number newWidth)
        {
            fontTracking.set(Font.font(newWidth.doubleValue() / 4));
        }
    });

使用此解决方案,动态字体调整非常流畅且快速,甚至比

bind(Bindings.concat("-fx-font-size: "
方法还要好。


0
投票

我也遇到了类似的问题,是这样解决的:

  1. 在 CSS 和 FXML 文件中,我以相对方式定义所有字体大小,仅使用“em”而不是“%”或“px”
  2. 在主窗口的控制器中,我将主窗格的样式属性中的双精度值绑定到某些场景大小属性(例如其对角线长度的粗略近似值)

它之所以有效,是因为为主窗格设置的样式将作为修饰符影响 FXML 中已定义的所有节点。已经具有样式类的节点也会受到影响,因为新样式作为级联样式表中附加的顶层样式出现。

该解决方案的主要优点是在单个位置处理字体大小缩放系数。因此,您不必找到每个具有 Font 属性的节点即可使其正常工作。

示例文件:

样式.css

.label {
    -fx-font-size: 1.1em;
}

.title {
    -fx-font-size: 1.5em;
    -fx-font-weight: bold;
}

main.fxml

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<BorderPane style="-fx-background-color: #fff;"
        xmlns="http://javafx.com/javafx/8"
        xmlns:fx="http://javafx.com/fxml/1"
        prefWidth="1280.0" prefHeight="720.0"
        fx:controller="controllers.MainController">
    <top>
        <Label text="Application title" styleClass="title"/>
    </top>
    <center>
        <Label text="Lorem ipsum"/>
    </center>
</BorderPane>

MainController.java

package controllers;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.BorderPane;

public class MainController implements Initializable {
    @FXML private BorderPane mainPane;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        initializeFontSizeManager();
    }

    private void initializeFontSizeManager() {
        // Cf. https://stackoverflow.com/questions/13246211/javafx-how-to-get-stage-from-controller-during-initialization
        mainPane.sceneProperty().addListener((observableScene, oldScene, newScene) -> {
            // We need a scene to work on
            if (oldScene == null && newScene != null) {
                DoubleProperty fontSize = new SimpleDoubleProperty(0);
                fontSize.bind(newScene.widthProperty().add(newScene.heightProperty())
                    .divide(1280 + 720) // I know, it's a very rough approximation :)
                    .multiply(100)); // get a suitable value to put before the '%' symbol in the style
                mainPane.styleProperty().bind(
                    Bindings.concat("-fx-font-size: ", fontSize.asString("%.0f")).concat("%;"));
            }
        });
    }
}

0
投票

我知道这是一个很老的问题 但从 19-ea+9 开始你可以使用 like

private DoubleProperty fontSize = new SimpleDoubleProperty(10);
node.styleProperty().bind(fontSize.map(size -> "-fx-font-size: "+size+";-fx-base: rgb(0,0,255);"));
© www.soinside.com 2019 - 2024. All rights reserved.