【问题标题】:How to calculate the pixel width of a String in JavaFX?如何计算 JavaFX 中字符串的像素宽度?
【发布时间】:2012-10-12 12:21:08
【问题描述】:

在 Java FX 2.2 中似乎没有 API 调用来计算文本字符串的宽度(以像素为单位)。在其他论坛上已经提出了解决方法的建议,但是我创建或查找返回字符串宽度的任何代码(使用默认字体或其他方式)的努力都失败了。任何帮助将不胜感激。

【问题讨论】:

    标签: java javafx-2 javafx


    【解决方案1】:

    如果你只是测量没有 CSS 的默认字体:

    1. 将要测量的字符串放在 Text 对象中。
    2. 获取 Text 对象的布局边界的宽度。

    如果需要应用 CSS:

    1. 将要测量的字符串放在 Text 对象中。
    2. 创建一次性场景并将文本对象放置在场景中。
    3. 获取文本快照(如果您使用 Java 7)或调用 applyCss 获取 Java 8。
    4. 获取 Text 对象的布局边界的宽度。

    这是有效的,因为它强制对计算其布局边界的 Text 进行布局传递。 第 2 步中的场景是必需的,因为这正是 CSS 处理器的工作方式(它需要一个节点位于场景中才能完成其工作)。如果您想进一步了解处理过程,请务必阅读 applyCss 的链接 javadoc。

    示例代码

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.text.Text;
    import javafx.stage.Stage;
    
    // displays the width in pixels of an arbitrary piece of text.
    public class MeasureText extends Application {
      public static void main(String[] args) { launch(args); }
      @Override public void start(Stage stage) throws Exception {
        final Text text = new Text("XYZZY");
        new Scene(new Group(text));
    
        // java 7 => 
        //    text.snapshot(null, null);
        // java 8 =>
        text.applyCss(); 
    
        final double width = text.getLayoutBounds().getWidth();
    
        stage.setScene(new Scene(new Label(Double.toString(width))));
        stage.show();
      }
    }
    

    示例程序输出(以像素为单位显示任意文本的宽度):

    如果将文本打印到具有设置字体的图形上下文中,这将如何(如果有的话)发生变化?

    将字体应用于包含您将绘制到画布上的相同消息的文本对象。与测量绘制到场景图的文本不同,绘制到画布的项目没有应用 CSS,因此您无需在测量文本之前将 Text 对象放置在场景中并应用 CSS。您可以测量文本对象的布局边界,它将与使用相同字体在画布内绘制的文本的边界相同。

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.canvas.*;
    import javafx.scene.control.Label;
    import javafx.scene.layout.VBox;
    import javafx.scene.text.*;
    import javafx.stage.Stage;
    
    // displays the width in pixels of an arbitrary piece of text (which has been plotted on a canvas).
    public class MeasureText extends Application {
        @Override
        public void start(Stage stage) throws Exception {
            final String msg = "XYZZY";
            final Text text = new Text(msg);
            Font font = Font.font("Arial", 20);
            text.setFont(font);
    
            final double width = text.getLayoutBounds().getWidth();
    
            Canvas canvas = new Canvas(200, 50);
            GraphicsContext gc = canvas.getGraphicsContext2D();
            gc.setFont(font);
            gc.fillText(msg, 0, 40);
    
            stage.setScene(new Scene(
                    new VBox(new Label(Double.toString(width)), canvas))
            );
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 如果我想在 Windows 和 Mac OX 上计算文本宽度,这个工具是根据操作系统计算字符串的宽度吗?
    • 是的,无论使用何种操作系统,都会返回正确的宽度。
    • 如果在拍摄快照之前将样式应用于文本,此解决方案是否还会考虑样式文本?
    • @Urs 快照用于强制 Java 7 的 CSS 布局传递。我更新了答案以进一步解释这一点。
    • 有兴趣的读者可以看看this的增强请求。
    【解决方案2】:

    此解决方案在 java 8 之前有效:

    float width = com.sun.javafx.tk.Toolkit.getToolkit().getFontLoader().computeStringWidth("", gc.getFont());
    float height = com.sun.javafx.tk.Toolkit.getToolkit().getFontLoader().getFontMetrics(gc.getFont()).getLineHeight();
    

    这些类已被删除,并且在较新的 java 版本中不可用!

    【讨论】:

    • 这也可以用于单元测试和其他地方,因为(与快照相反)它不需要在 FX 应用程序线程上执行代码。
    • 遗憾的是,这是一个不鼓励的访问......它不在 Java 8.25 的 api 上
    • @Supuhstar GraphicsContext
    • 我真的很喜欢你的这个解决方案:FontMetrics metrics = Toolkit.getToolkit().getFontLoader().getFontMetrics(yourFontObject);然后你可以用它来做一些花哨的 FontMetrics 东西 (more info)
    • com.sun.javafx.tk.Toolkit 是一个受限制的、非公开的、未记录的类,尽管它实际上可以访问,但强烈建议不要使用它,因为它可以(并且将会!)在某些时候被替换。 永远不要使用未记录的类,这些总是临时解决方案,将来会通过一些更新破坏您的代码。一般来说,应该避免使用整个com.sun
    【解决方案3】:
    Bounds bounds = TextBuilder.create().text(text).font(font).build().getLayoutBounds();
    双倍宽度=bounds.getWidth();
    双倍高度=bounds.getHeight();

    【讨论】:

    • TextBuilder 已弃用。
    • 不适用于 javafx 8,因为 TextBuilder 类已被删除。
    【解决方案4】:

    我试过了:

    Text theText = new Text(theLabel.getText());
    theText.setFont(theLabel.getFont());
    double width = theText.getBoundsInLocal().getWidth();
    

    它似乎工作正常。

    【讨论】:

      猜你喜欢
      • 2013-08-22
      • 2011-09-15
      • 2010-12-04
      • 1970-01-01
      • 1970-01-01
      • 2019-04-08
      • 1970-01-01
      • 2018-11-28
      • 2018-05-25
      相关资源
      最近更新 更多