以像素为单位正确设置文本大小
Correct setting of the text size in pixels
我在设置文本大小时遇到问题。虽然我找到了计算方法here,但计算仍然不准确,如本例所示。
import java.awt.Toolkit;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class TextHeight extends javafx.application.Application {
@Override
public void start(Stage stage) {
var text = new Text("EXAMPLE");
var fontSize = 100 * Toolkit.getDefaultToolkit().getScreenResolution() / 72.0;
text.setFont(Font.loadFont(getClass().getResourceAsStream("GT Pressura Mono Regular Regular.ttf"), fontSize));
text.setFill(Color.BLUE);
text.setX(0);
text.setY(100);
var pane = new Pane(text, new Rectangle(500, 0, 10, 100));
stage.setScene(new Scene(pane, 600, 120));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我现在根本不想解决文字的位置问题。只是字体的高度不是100px,而是94px左右。
尺寸计算有问题吗?还是跟字体有关? (我下载了here)还是其他地方的问题?
请帮忙
谢谢
正如评论中所指出的(link 对字体规格的真正精彩讨论),字体的大小不是其大写字母的高度。
可能(我很想看看其他建议)实现你想要的最好方法是定义一个自定义 Region
来保存你的文本节点,它覆盖 layoutChildren()
以便它调整字体大小,使高度适合区域的大小。
几个实施说明:
Text.setBoundsType()
确定文本边界的测量方式。默认值为 LOGICAL
,它基于字体的规格而不是呈现的实际文本。我认为你想要的是VISUAL
边界。
- 这个实现是content-biased垂直的;这意味着它的宽度取决于它的高度。知道高度后,将计算字体大小,并将首选宽度计算为文本的宽度。
这有些局限(没有多行文本等),但如果您想要更复杂的内容,应该可以为您提供一个起点。
public class TextPane extends Region {
private final Text text ;
public TextPane(Text text) {
this.text = text ;
getChildren().add(text);
}
@Override
protected void layoutChildren() {
adjustFontSize(getHeight());
text.setY(getHeight());
text.setX(0);
}
private void adjustFontSize(double height) {
double textHeight = text.getBoundsInLocal().getHeight();
if (Math.abs(height - textHeight) > 1) {
Font currentFont = text.getFont() ;
double fontSize = currentFont.getSize() ;
text.setFont(Font.font(currentFont.getFamily(), height * fontSize / textHeight));
}
}
@Override
protected double computePrefWidth(double height) {
adjustFontSize(height);
return text.getBoundsInLocal().getWidth();
}
@Override
public Orientation getContentBias() {
return Orientation.VERTICAL;
}
}
这是一个示例,通过将文本窗格的高度固定为 100
:
,基本上实现了您想要做的事情
public class TextHeight extends javafx.application.Application {
@Override
public void start(Stage stage) {
Text text = new Text("EXAMPLE");
text.setBoundsType(TextBoundsType.VISUAL);
text.setTextOrigin(VPos.BOTTOM);
text.setFill(Color.BLUE);
TextPane textPane = new TextPane(text);
textPane.setMinHeight(100);
textPane.setMaxHeight(100);
Pane root = new Pane(textPane, new Rectangle(620, 0, 10, 100));
stage.setScene(new Scene(root, 700, 120));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
如果文本具有下降的字形(例如,如果将 "EXAMPLE"
更改为 "Example"
,则 p
下降到基线以下),文本的总高度将包括后裔:
下面是一个使用文本窗格作为根节点的示例(因此它始终与场景大小相同)。更改 window 大小将导致文本自动更新以垂直填充场景:
public class TextHeight extends javafx.application.Application {
@Override
public void start(Stage stage) {
Text text = new Text("Example");
text.setBoundsType(TextBoundsType.VISUAL);
text.setTextOrigin(VPos.BOTTOM);
text.setFill(Color.BLUE);
TextPane textPane = new TextPane(text);
textPane.setPrefHeight(100);
stage.setScene(new Scene(textPane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我在设置文本大小时遇到问题。虽然我找到了计算方法here,但计算仍然不准确,如本例所示。
import java.awt.Toolkit;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class TextHeight extends javafx.application.Application {
@Override
public void start(Stage stage) {
var text = new Text("EXAMPLE");
var fontSize = 100 * Toolkit.getDefaultToolkit().getScreenResolution() / 72.0;
text.setFont(Font.loadFont(getClass().getResourceAsStream("GT Pressura Mono Regular Regular.ttf"), fontSize));
text.setFill(Color.BLUE);
text.setX(0);
text.setY(100);
var pane = new Pane(text, new Rectangle(500, 0, 10, 100));
stage.setScene(new Scene(pane, 600, 120));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我现在根本不想解决文字的位置问题。只是字体的高度不是100px,而是94px左右。
尺寸计算有问题吗?还是跟字体有关? (我下载了here)还是其他地方的问题?
请帮忙
谢谢
正如评论中所指出的(link 对字体规格的真正精彩讨论),字体的大小不是其大写字母的高度。
可能(我很想看看其他建议)实现你想要的最好方法是定义一个自定义 Region
来保存你的文本节点,它覆盖 layoutChildren()
以便它调整字体大小,使高度适合区域的大小。
几个实施说明:
Text.setBoundsType()
确定文本边界的测量方式。默认值为LOGICAL
,它基于字体的规格而不是呈现的实际文本。我认为你想要的是VISUAL
边界。- 这个实现是content-biased垂直的;这意味着它的宽度取决于它的高度。知道高度后,将计算字体大小,并将首选宽度计算为文本的宽度。
这有些局限(没有多行文本等),但如果您想要更复杂的内容,应该可以为您提供一个起点。
public class TextPane extends Region {
private final Text text ;
public TextPane(Text text) {
this.text = text ;
getChildren().add(text);
}
@Override
protected void layoutChildren() {
adjustFontSize(getHeight());
text.setY(getHeight());
text.setX(0);
}
private void adjustFontSize(double height) {
double textHeight = text.getBoundsInLocal().getHeight();
if (Math.abs(height - textHeight) > 1) {
Font currentFont = text.getFont() ;
double fontSize = currentFont.getSize() ;
text.setFont(Font.font(currentFont.getFamily(), height * fontSize / textHeight));
}
}
@Override
protected double computePrefWidth(double height) {
adjustFontSize(height);
return text.getBoundsInLocal().getWidth();
}
@Override
public Orientation getContentBias() {
return Orientation.VERTICAL;
}
}
这是一个示例,通过将文本窗格的高度固定为 100
:
public class TextHeight extends javafx.application.Application {
@Override
public void start(Stage stage) {
Text text = new Text("EXAMPLE");
text.setBoundsType(TextBoundsType.VISUAL);
text.setTextOrigin(VPos.BOTTOM);
text.setFill(Color.BLUE);
TextPane textPane = new TextPane(text);
textPane.setMinHeight(100);
textPane.setMaxHeight(100);
Pane root = new Pane(textPane, new Rectangle(620, 0, 10, 100));
stage.setScene(new Scene(root, 700, 120));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
如果文本具有下降的字形(例如,如果将 "EXAMPLE"
更改为 "Example"
,则 p
下降到基线以下),文本的总高度将包括后裔:
下面是一个使用文本窗格作为根节点的示例(因此它始终与场景大小相同)。更改 window 大小将导致文本自动更新以垂直填充场景:
public class TextHeight extends javafx.application.Application {
@Override
public void start(Stage stage) {
Text text = new Text("Example");
text.setBoundsType(TextBoundsType.VISUAL);
text.setTextOrigin(VPos.BOTTOM);
text.setFill(Color.BLUE);
TextPane textPane = new TextPane(text);
textPane.setPrefHeight(100);
stage.setScene(new Scene(textPane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}