英文:
Correct setting of the text size in pixels
问题
我在设置文本大小方面遇到了问题。尽管我已经找到了一种计算方法此处,但计算仍然不准确,正如这个示例所示。
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);
}
}
我现在不想解决文本的位置问题。只是字体的高度不是100像素,而是约94像素。
尺寸计算有问题吗?还是与字体有关?(我在这里下载了它)还是问题出在其他地方?
请帮忙解答,谢谢。
英文:
I'm having trouble setting the text size. Although I have found a way here to calculate this, the calculation is still inaccurate, as this example shows.
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);
}
}
I don't want to solve the position of the text at all now. It's just that the font doesn't have a height of 100px, but about 94px.
Is there a problem in the size calculation? Or is it related to the font? (I downloaded it here) Or is the problem somewhere else?
Please help
Thank you
答案1
得分: 3
以下是您提供的内容的翻译部分:
如评论中指出的(附有关于字体度量的真正优秀的讨论链接),字体的大小并不是其大写字母的高度。
很可能(我会很乐意看到其他建议)实现您想要的最佳方法是定义一个自定义的Region
来容纳您的文本节点,覆盖layoutChildren()
方法以便调整字体大小,使其高度适应区域的大小。
一些实现注意事项:
Text.setBoundsType()
确定文本边界如何测量。默认值是LOGICAL
,它基于字体的度量而不是实际渲染的文本。我认为您在这里想要的是VISUAL
边界。- 此实现在垂直方向上偏向于内容;也就是说宽度取决于高度。一旦高度确定,就会计算字体大小,然后将首选宽度计算为文本的宽度。
这在某种程度上有限(无多行文本等),但如果您想要更复杂的东西,这应该是一个起点。
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
在基线以下),文本的总高度将包括下降部分:
这里还有一个示例,它将文本窗格用作根节点(因此它的大小始终与场景相同)。改变窗口大小将导致文本自动更新以垂直填充场景:
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);
}
}
英文:
As pointed out in a comment (with a link to a truly excellent discussion of font metrics), the size of a font is not the height of its capital letters.
Probably (I would be interested to see other suggestions) the best way to achieve what you want is to define a custom Region
to hold your text node, which overrides layoutChildren()
so that it adjusts the font size so that the height fits the size of the region.
A couple of implementation notes:
Text.setBoundsType()
determines how the bounds of the text are measured. The default isLOGICAL
, which bases the bounds on the metrics of the font, rather than the actual text being rendered. I think what you want here areVISUAL
bounds.- This implementation is content-biased to vertical; meaning that its width depends on its height. Once the height is known, the font size is computed and the preferred width is calculated as the width of the text.
This is somewhat limited (no multiline text, etc.) but should give you a starting point if you want something more sophisticated.
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;
}
}
Here's an example which basically implements what you were looking to do, by fixing the height of the text pane to 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);
}
}
If the text has glyphs with descent (e.g. if you change "EXAMPLE"
to "Example"
, so the p
descends below the baseline), the total height of the text will include the descent:
And here's an example which uses the text pane as the root node (so it's always the same size as the scene). Changing the window size will result in the text automatically updating to vertically fill the scene:
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);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论