如何计算JavaFX中String的像素宽度?

Don*_*lls 25 java javafx javafx-2

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

jew*_*sea 36

如果您只是在没有CSS的情况下测量默认字体:

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

如果您需要申请CSS:

  1. 将要测量的字符串放在Text对象中.
  2. 创建一次性场景并将Text对象放置在场景中.
  3. 拍摄文本的快照(如果您使用的是Java 7)或调用applyCss for 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

示例程序输出

如果将文本打印到带有设置字体的graphicscontext,如何(如果有的话)会发生变化?

将字体应用于包含将绘制到画布的相同消息的文本对象.与测量绘制到场景图形的文本不同,绘制到画布的项目没有应用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 有兴趣的读者可以查看[this](https://bugs.openjdk.java.net/browse/JDK-8090775)增强请求. (3认同)
  • @Urs快照用于强制Java 7的CSS布局传递.我更新了我的答案以进一步解释这一点. (2认同)

Sta*_*tas 16

这个解决方案可以工作到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();
Run Code Online (Sandbox Code Playgroud)

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

  • 可悲的是,这是一种沮丧的访问......它不是Java 8.25上的api (4认同)
  • `com.sun.javafx.tk.Toolkit`是一个受限制的,非公开的,未记录的类,虽然实际上是可访问的,但是非常不鼓励使用,因为它可以(并且将会!)在某些时候被替换.**永远不要**使用未记录的类,这些类总是**临时**解决方案,并将在未来通过一些更新来破坏您的代码.一般来说,应避免使用整个`com.sun`包 (4认同)
  • 这也可以在单元测试和其他地方使用,因为(与快照相对)它不需要在FX应用程序线程上执行代码. (3认同)

Leo*_*tos 12

我试过这个:

Text theText = new Text(theLabel.getText());
theText.setFont(theLabel.getFont());
double width = theText.getBoundsInLocal().getWidth();
Run Code Online (Sandbox Code Playgroud)

它似乎工作正常.