【问题标题】:How to dynamically change font size in UI to always be the same width in JavaFX?如何动态更改 UI 中的字体大小以在 JavaFX 中始终保持相同的宽度?
【发布时间】:2019-06-26 23:14:11
【问题描述】:

我要做的是在 fxml 中创建一个标签,使用 Scenebuilder,它会更新其字体大小以始终确保标签的内容大小相同。

一些背景信息是我正在使用AnchorPane,它已最大化且不可调整大小。

我不需要文本的高度相同——只要宽度相同。另外,我只想调整大小如果它太大而无法容纳。所以如果标签只有 1 个字母,我不希望它是一个巨大的单个字母。我只有初步的想法,下面是一些伪代码。谢谢!

lengthOfLabel = menuLabel.getText().length();

if(lengthOfLabel > numOfCharsThatCanFitInWidth){
    menuLabel.setStyle("-fx-font-size: " + (int) (someConstant/lengthOfLabel) + ";")
}

【问题讨论】:

    标签: css user-interface javafx dynamic fxml


    【解决方案1】:

    您可以使用 temp Text 对象来测量文本大小,如果不合适则缩放字体。像这样的:

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.text.Font;
    import javafx.scene.text.Text;
    import javafx.stage.Stage;
    
    public class Main extends Application {
    
        //maximum width of the text/label
        private final double MAX_TEXT_WIDTH = 400;
        //default (nonscaled) font size of the text/label
        private final double defaultFontSize = 32;
        private final Font defaultFont = Font.font(defaultFontSize);
    
        @Override
        public void start(Stage primaryStage) {
    
            final TextField tf = new TextField("Label text goes here");
    
            final Label lbl = new Label();
            lbl.setFont(defaultFont);
            lbl.textProperty().addListener((observable, oldValue, newValue) -> {
                //create temp Text object with the same text as the label
                //and measure its width using default label font size
                Text tmpText = new Text(newValue);
                tmpText.setFont(defaultFont);
    
                double textWidth = tmpText.getLayoutBounds().getWidth();
    
                //check if text width is smaller than maximum width allowed
                if (textWidth <= MAX_TEXT_WIDTH) {
                    lbl.setFont(defaultFont);
                } else {
                    //and if it isn't, calculate new font size,
                    // so that label text width matches MAX_TEXT_WIDTH
                    double newFontSize = defaultFontSize * MAX_TEXT_WIDTH / textWidth;
                    lbl.setFont(Font.font(defaultFont.getFamily(), newFontSize));
                }
    
            });
            lbl.textProperty().bind(tf.textProperty());
    
            final AnchorPane root = new AnchorPane(lbl, tf);
            AnchorPane.setLeftAnchor(tf, 0d);
            AnchorPane.setRightAnchor(tf, 0d);
            AnchorPane.setBottomAnchor(tf, 0d);
    
    
            primaryStage.setScene(new Scene(root, MAX_TEXT_WIDTH, 200));
            primaryStage.show();
        }
    }
    

    请注意,tmpText.getLayoutBounds() 返回的边界不包含任何转换/效果(如果需要这些,您必须将文本对象添加到临时场景并在父场景中计算其边界)。

    【讨论】:

    • 这正是我想要的。谢谢!后续问题。如果我希望文本的垂直位置保持不变,我是否必须将标签的 y 位置绑定到大小,或者是否有可以更改为垂直居中的属性。 (好像 y 位置是指标签的顶部,所以较小的文本会挤到顶部)无论如何,谢谢!
    • 您可以使用绑定,但更容易设置标签的高度并根据需要对齐内部文本:设置高度(自己选择首选高度)lbl.setPrefHeight(50);;将文本垂直居中:lbl.setAlignment(Pos.CENTER_LEFT); 或将其与底部边缘对齐:lbl.setAlignment(Pos.BOTTOM_LEFT);。当然,如果标签的高度已经受到限制,则无需显式设置。
    • 它对我不起作用,因为我在 css 中设置了默认字体。每次更改标签的文本值时,ScenePulseListener 都会覆盖我刚刚设置的字体。表示字体始终是 css 中指定的字体。有什么想法可以解决这个问题吗?
    • @SuperSmartWorld 在这种情况下,您应该使用内联样式(它们优先于 css 文件中定义的样式):lbl.setStyle("-fx-font-size: " + newFontSize + "px;");
    • @Guest21 感谢您的建议。我通过将 fontProperty 绑定到另一个标签的字体(也在 css 中定义)来解决它。然后当我再次更改字体大小时解除绑定属性。使用内联样式应该也可以,而且可能更整洁一些。
    猜你喜欢
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2023-03-16
    相关资源
    最近更新 更多