Berechnen Sie die Anzeigebreite einer Zeichenfolge in Java

89

Wie berechnet man die Länge (in Pixel) eines Strings in Java?

Am besten ohne Swing.

BEARBEITEN: Ich möchte den String mit drawString () in Java2D zeichnen und die Länge für den Zeilenumbruch verwenden.

eflles
quelle
4
Ohne Schaukel? Welches Gerät benutzt du? Welche Schriftart? Welche Größe? Welcher Stil? All diese Dinge verändern die Anzeigebreite.
S.Lott
3
Wie wirst du die Schnur ziehen? Mit AWT? Oder mit einem anderen Toolkit? Die Größe der Zeichenfolge in Pixel hängt von der Zeichnungs-API ab, die das Pixel später zeichnet (und natürlich von der verwendeten Schriftart und der Schriftgröße und davon, ob die Schrift fett / kursiv ist usw.). Ohne Kenntnis der Zeichnungs-API und der Schrifteigenschaften hat eine Zeichenfolge keinerlei Größe.
Mecki
1
@S. Lott. Du hast es in einem. Ich war versucht, dies als Nicht-Frage zu schließen.
David Arno
1
@ David Arno: Ich bin ein Softie auf dem n00bz. Ich werde das [Anfänger] -Tag hinzufügen.
S.Lott
Für .NET-Äquivalente gibt es die TextRenderer-Klasse, siehe stackoverflow.com/questions/604298/…
Spoike

Antworten:

135

Wenn Sie nur AWT verwenden möchten, verwenden Sie Graphics.getFontMetrics(optional die Schriftart angeben , für eine nicht standardmäßige), um eine zu erhalten FontMetricsund dann FontMetrics.stringWidthdie Breite für die angegebene Zeichenfolge zu ermitteln.

Wenn Sie beispielsweise eine GraphicsVariable namens haben g, verwenden Sie:

int width = g.getFontMetrics().stringWidth(text);

Für andere Toolkits müssen Sie uns weitere Informationen geben - es wird immer Toolkit-abhängig sein.

Jon Skeet
quelle
7
Es ist möglicherweise klarer, wenn Sie eine Beispielverwendung angeben. Zunächst habe ich versucht, sie als statische Methode zu verwenden, da Sie sie so geschrieben haben.
Aequitas
Veraltet! aber immer noch die beste Methode! Warum lehnen sie eine Methode ab, wenn es keinen besseren Weg gibt !!! Ich verstehe es einfach nicht!
Iman
2
@Zich: Ich bin nicht sicher, welche Methode Sie sagen, ist veraltet - keine von ihnen ist in der Java 8-Dokumentation als veraltet markiert, soweit ich sehen kann ...
Jon Skeet
2
@Zich: Es ist eine Methode in Graphics, nicht FontMetrics. Aber Sie rufen an Toolkit.getFontMetrics, was in der Tat veraltet ist und worüber diese Methode nicht spricht ... Sie müssen bei solchen Dingen wirklich vorsichtig sein, insbesondere bevor Sie über das Melden von Fehlern sprechen ...
Jon Skeet
1
@Zich: Nun, ich würde nicht raten - ich würde die nicht veraltete Methode oder die nicht veralteten Methoden verwenden, die Toolkit.getFontMetricsstattdessen vorschlagen .
Jon Skeet
54

Es muss nicht immer vom Toolkit abhängig sein oder es muss nicht immer der FontMetrics-Ansatz verwendet werden, da zuerst ein Grafikobjekt abgerufen werden muss, das in einem Webcontainer oder in einer kopflosen Umgebung fehlt.

Ich habe dies in einem Web-Servlet getestet und es berechnet die Textbreite.

import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;

...

String text = "Hello World";
AffineTransform affinetransform = new AffineTransform();     
FontRenderContext frc = new FontRenderContext(affinetransform,true,true);     
Font font = new Font("Tahoma", Font.PLAIN, 12);
int textwidth = (int)(font.getStringBounds(text, frc).getWidth());
int textheight = (int)(font.getStringBounds(text, frc).getHeight());

Fügen Sie diesen Dimensionen die erforderlichen Werte hinzu, um den erforderlichen Rand zu erstellen.

Olofu Mark
quelle
1
Ich denke nicht, dass das Erstellen einer affineTransform und eines fontRenderContext auf diese Weise zu einem guten Verhalten führt. Ich denke, font.getTransfrom () wäre logischer.
Lyth
1
Ihr Beispiel verwendet weiterhin die AWT-Funktionalität. Mit SWT Font zum Beispiel wird es nicht funktionieren, deshalb "wird es immer Toolkit-abhängig sein"
serg.nechaev
1
@Olofu Mark - getStringBounds gibt nur die logischen Grenzen an. Um es besser zu machen, sollte es getBounds () und LineMetrics verwenden, um die tatsächliche Höhe einschließlich Aufstieg + Abstieg abzurufen.
Jones
7

Verwenden Sie die Methode getWidth in der folgenden Klasse:

import java.awt.*;
import java.awt.geom.*;
import java.awt.font.*;

class StringMetrics {

  Font font;
  FontRenderContext context;

  public StringMetrics(Graphics2D g2) {

    font = g2.getFont();
    context = g2.getFontRenderContext();
  }

  Rectangle2D getBounds(String message) {

    return font.getStringBounds(message, context);
  }

  double getWidth(String message) {

    Rectangle2D bounds = getBounds(message);
    return bounds.getWidth();
  }

  double getHeight(String message) {

    Rectangle2D bounds = getBounds(message);
    return bounds.getHeight();
  }

}
Ed Poor
quelle
1

Und jetzt zu etwas ganz anderem. Das Folgende nimmt eine ariale Schriftart an und macht eine wilde Vermutung basierend auf einer linearen Interpolation von Zeichen gegen Breite.

// Returns the size in PICA of the string, given space is 200 and 'W' is 1000.
// see https://p2p.wrox.com/access/32197-calculate-character-widths.html

static int picaSize(String s)
{
    // the following characters are sorted by width in Arial font
    String lookup = " .:,;'^`!|jl/\\i-()JfIt[]?{}sr*a\"ce_gFzLxkP+0123456789<=>~qvy$SbduEphonTBCXY#VRKZN%GUAHD@OQ&wmMW";
    int result = 0;
    for (int i = 0; i < s.length(); ++i)
    {
        int c = lookup.indexOf(s.charAt(i));
        result += (c < 0 ? 60 : c) * 7 + 200;
    }
    return result;
}

Interessant, aber vielleicht nicht sehr praktisch.

John Henckel
quelle
1

Ich persönlich habe nach etwas gesucht, mit dem ich den mehrzeiligen Zeichenfolgenbereich berechnen kann, damit ich feststellen kann, ob der angegebene Bereich groß genug ist, um die Zeichenfolge zu drucken - unter Beibehaltung einer bestimmten Schriftart.

private static Hashtable hash = new Hashtable();
private Font font;
private LineBreakMeasurer lineBreakMeasurer;
private int start, end;

public PixelLengthCheck(Font font) {
    this.font = font;
}

public boolean tryIfStringFits(String textToMeasure, Dimension areaToFit) {
    AttributedString attributedString = new AttributedString(textToMeasure, hash);
    attributedString.addAttribute(TextAttribute.FONT, font);
    AttributedCharacterIterator attributedCharacterIterator =
            attributedString.getIterator();
    start = attributedCharacterIterator.getBeginIndex();
    end = attributedCharacterIterator.getEndIndex();

    lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator,
            new FontRenderContext(null, false, false));

    float width = (float) areaToFit.width;
    float height = 0;
    lineBreakMeasurer.setPosition(start);

    while (lineBreakMeasurer.getPosition() < end) {
        TextLayout textLayout = lineBreakMeasurer.nextLayout(width);
        height += textLayout.getAscent();
        height += textLayout.getDescent() + textLayout.getLeading();
    }

    boolean res = height <= areaToFit.getHeight();

    return res;
}
wmioduszewski
quelle