JavaFX FontMetrics

Fra*_*ank 5 fonts javafx

我正在尝试将文本准确地放置在窗格的水平和垂直中心.使用fontmetrics和测试程序,我得到以下结果:

在此输入图像描述

该测试提出了以​​下问题:

  1. 为什么上升值(顶部黑线)如此之高?我预计它会越过'T'的顶部.洋红色线是'lineheight'值,所以我假设它是它上面任何文本的基线.
  2. 如果黑线包括行间距,为什么没有测量'T'的顶部?
  3. 有没有办法获得一个准确的边界框或我是否必须以图形方式扫描文本图像以找到边界?显然左右值也包含某种间距,因此扫描似乎是唯一的解决方案.

jew*_*sea 9

以下是Frank reportSize功能的替代实现:

public void reportSize(String s, Font myFont) {
    Text text = new Text(s);
    text.setFont(myFont);
    Bounds tb = text.getBoundsInLocal();
    Rectangle stencil = new Rectangle(
            tb.getMinX(), tb.getMinY(), tb.getWidth(), tb.getHeight()
    );

    Shape intersection = Shape.intersect(text, stencil);

    Bounds ib = intersection.getBoundsInLocal();
    System.out.println(
            "Text size: " + ib.getWidth() + ", " + ib.getHeight()
    );
}
Run Code Online (Sandbox Code Playgroud)

此实现使用形状交集来确定渲染形状的边界框的大小,没有空格.该实现不依赖com.sun于Java 9+中的用户应用程序代码可能无法直接访问的包类.


Fra*_*ank 4

经过一番实验后,我想出了这个解决方案:

在此输入图像描述

这是生成它的代码:

public void getBoundingBox(String s, Font myFont) {                             

    final FontMetrics fm = Toolkit.getToolkit().getFontLoader().getFontMetrics(myFont); 

    final Canvas canvas = new Canvas(fm.computeStringWidth(s), fm.getAscent() + fm.getDescent());        
    final GraphicsContext gc = canvas.getGraphicsContext2D();

    gc.setFill(Color.RED);                  // Just an abitrary color
    gc.setTextBaseline(VPos.TOP);           // This saves having to scan the bottom
    gc.setFont(myFont);

    gc.fillText(s, -fm.getLeading(), 0);    // This saves having to scan the left

    // Get a snapshot of the canvas
    final WritableImage image = canvas.snapshot(null, null);
    final PixelReader pr = image.getPixelReader();

    final int h = (int) canvas.getHeight();
    final int w = (int) canvas.getWidth();

    int x;
    int y = 0;

    // Scan from the top down until we find a red pixel

    boolean found = false;
    while (y < h && !found) {
        x = 0;
        while (x < w && !found) {
            found = pr.getColor(x, y).equals(Color.RED);
            x++;
        }
        y++;
    }
    int yPos = y - 2;

    // Scan from right to left until we find a red pixel

    x = w;        
    found = false;
    while (x > 0 && !found) {
        y = 0;           
        while (y < h && !found) {
            found = pr.getColor(x, y).equals(Color.RED);
            y++;
        }
        x--;
    }
    int xPos = x + 3;

    // Here is a visible representation of the bounding box

    Rectangle mask = new Rectangle(0, yPos, xPos, h - yPos);

    mask.setFill(Color.rgb(0, 0, 255, 0.25));       
    root.getChildren().addAll(canvas, mask);   // root is a global AnchorPane

    System.out.println("The width of the bounding box is " + xPos);
    System.out.println("The height of the bounding box is " + (h - yPos));
}
Run Code Online (Sandbox Code Playgroud)

FontMetrics 需要两次导入:

 import com.sun.javafx.tk.FontMetrics;
 import com.sun.javafx.tk.Toolkit;
Run Code Online (Sandbox Code Playgroud)

并像这样调用边界框:

 Font myFont = new Font("Arial", 100.0); 
 getBoundingBox("Testing", myFont);
Run Code Online (Sandbox Code Playgroud)

它解决了我的问题,我希望这对其他人也有用。

  • 在 Java9 中,fm.computeStringWidth(String) 已替换为 getCharWidth(char),因此此示例不再有效。 (3认同)
  • 正如您所描述的,我已成功使用 Toolkit.getToolkit().getFontLoader().getFontMetrics(..) ,但 com.sun.javafx.tk.Toolkit 以及 com.sun.javafx.tk.FontMetrics 是'内部'包。有谁知道如何仅使用公共 javafx.* 包获取等效信息?另请参阅https://bugs.openjdk.java.net/browse/JDK-8090775 (2认同)