Richtige Einstellung der Textgröße in Pixel

Aug 25 2020

Ich habe Probleme beim Einstellen der Textgröße. Obwohl ich hier einen Weg gefunden habe , dies zu berechnen, ist die Berechnung immer noch ungenau, wie dieses Beispiel zeigt.

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);
    }
}

Ich möchte die Position des Textes jetzt überhaupt nicht lösen. Es ist nur so, dass die Schrift keine Höhe von 100 Pixel hat, sondern ungefähr 94 Pixel.

Gibt es ein Problem bei der Größenberechnung? Oder hängt es mit der Schriftart zusammen? (Ich habe es hier heruntergeladen ) Oder liegt das Problem woanders?

Bitte helfen Sie

Vielen Dank

Antworten

3 James_D Aug 25 2020 at 20:05

Wie in einem Kommentar (mit einem Link zu einer wirklich hervorragenden Diskussion der Schriftmetriken) ausgeführt, entspricht die Größe einer Schrift nicht der Höhe ihrer Großbuchstaben.

Wahrscheinlich (ich würde gerne andere Vorschläge sehen) besteht der beste Weg, um das zu erreichen, was Sie wollen, darin, eine benutzerdefinierte Funktion Regionfür Ihren Textknoten zu definieren , die überschreibt, layoutChildren()sodass die Schriftgröße so angepasst wird, dass die Höhe der Größe der Region entspricht.

Einige Implementierungshinweise:

  • Text.setBoundsType()legt fest, wie die Grenzen des Textes gemessen werden. Die Standardeinstellung ist LOGICAL, dass die Grenzen eher auf den Metriken der Schriftart als auf dem tatsächlich gerenderten Text basieren. Ich denke, was Sie hier wollen, sind VISUALGrenzen.
  • Diese Implementierung ist inhaltlich auf vertikal ausgerichtet. was bedeutet, dass seine Breite von seiner Höhe abhängt. Sobald die Höhe bekannt ist, wird die Schriftgröße berechnet und die bevorzugte Breite als Breite des Textes berechnet.

Dies ist etwas eingeschränkt (kein mehrzeiliger Text usw.), sollte Ihnen jedoch einen Ausgangspunkt geben, wenn Sie etwas Anspruchsvolleres wünschen.

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;
    }
}

Hier ist ein Beispiel, das im Grunde das implementiert, wonach Sie gesucht haben, indem Sie die Höhe des Textfensters auf Folgendes festlegen 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);
    }
}

Wenn der Text Glyphen mit Abstieg hat (zB wenn Sie ändern "EXAMPLE"zu "Example", so dass die nach punten bewegt unter der Grundlinie), gehört die Gesamthöhe des Textes den Abstieg:

Und hier ist ein Beispiel, in dem das Textfenster als Stammknoten verwendet wird (es hat also immer die gleiche Größe wie die Szene). Wenn Sie die Fenstergröße ändern, wird der Text automatisch aktualisiert, um die Szene vertikal auszufüllen:

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);
    }
}