Calculer la largeur d'affichage d'une chaîne en Java

91

Comment calculer la longueur (en pixels) d'une chaîne en Java?

Préférable sans utiliser Swing.

EDIT: Je voudrais dessiner la chaîne en utilisant le drawString () dans Java2D et utiliser la longueur pour le retour à la ligne.

eflles
la source
4
Sans Swing? Quel appareil utilisez-vous? Quelle police? Quelle taille? Quel style? Toutes ces choses modifient la largeur d'affichage.
S.Lott
3
Comment allez-vous dessiner la ficelle? Avec AWT? Ou avec une autre boîte à outils? La taille de la chaîne en pixels dépend de l'API de dessin qui dessinera le pixel plus tard (et bien sûr de la police que vous utilisez et de la taille de la police et si la police est en gras / italique, etc.). Sans connaître l'API de dessin et les propriétés de la police, une chaîne n'a aucune taille.
Mecki
1
@S. Lott. Vous l'avez en un. J'ai été tenté de clore cela comme une non-question.
David Arno
1
@David Arno: Je suis un softie sur le n00bz. J'ajouterai la balise [beginner].
S.Lott
Pour l'équivalent .NET, il existe une classe TextRenderer, voir stackoverflow.com/questions/604298
...

Réponses:

137

Si vous souhaitez simplement utiliser AWT, utilisez Graphics.getFontMetrics(en spécifiant éventuellement la police, pour une police autre que celle par défaut) pour obtenir un FontMetrics, puis FontMetrics.stringWidthpour trouver la largeur de la chaîne spécifiée.

Par exemple, si vous avez une Graphicsvariable appelée g, vous utiliserez:

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

Pour les autres boîtes à outils, vous devrez nous donner plus d'informations - cela dépendra toujours de la boîte à outils.

Jon Skeet
la source
8
Cela pourrait être plus clair si vous fournissez un exemple d'utilisation, j'ai d'abord tenté de l'utiliser comme méthode statique, comme vous l'avez écrit de cette façon.
Aequitas
Obsolète! mais toujours la meilleure méthode !, Pourquoi abandonnent-ils une méthode alors qu'il n'y a pas de meilleur moyen !!! Je ne comprends tout simplement pas!
Iman
2
@Zich: Je ne sais pas quelle méthode vous dites est obsolète - aucune d'elles n'est marquée comme obsolète dans la documentation Java 8 pour autant que je puisse le voir ...
Jon Skeet
2
@Zich: C'est une méthode Graphics, non FontMetrics. Mais vous appelez Toolkit.getFontMetrics, ce qui est en effet obsolète, et ce n'est pas ce dont parle cette méthode ... vous devez faire très attention à ce genre de chose, en particulier avant de commencer à parler de rapport de bogues ...
Jon Skeet
1
@Zich: Eh bien, je ne devinerais pas - j'utiliserais la méthode non obsolète, ou les méthodes non obsolètes qui Toolkit.getFontMetricssuggèrent à la place.
Jon Skeet
55

Il n'est pas toujours nécessaire de dépendre de la boîte à outils ou on n'a pas toujours besoin d'utiliser l'approche FontMetrics car elle nécessite d'obtenir d'abord un objet graphique qui est absent d'un conteneur Web ou d'un environnement sans tête.

J'ai testé cela dans un servlet Web et il calcule la largeur du texte.

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

Ajoutez les valeurs nécessaires à ces dimensions pour créer toute marge requise.

Marque Olofu
la source
1
Je ne pense pas que créer un affineTransform et un fontRenderContext de cette façon entraînera un bon comportement. Je suppose que font.getTransfrom () serait plus logique.
Lyth
1
Votre exemple utilise toujours la fonctionnalité AWT. Avec SWT Font, par exemple, cela ne fonctionnera pas, c'est pourquoi "cela dépendra toujours de la boîte à outils"
serg.nechaev
1
@Olofu Mark - getStringBounds ne donne que les limites logiques. Pour l'améliorer, il doit utiliser getBounds () et l'objet LineMetrics pour récupérer la hauteur réelle, y compris la montée + la descente.
Jones
8

Utilisez la méthode getWidth dans la classe suivante:

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
la source
1

Et maintenant pour quelque chose de complètement différent. Ce qui suit suppose une police arial et fait une supposition sauvage basée sur une interpolation linéaire du caractère par rapport à la largeur.

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

Intéressant, mais peut-être pas très pratique.

John Henckel
la source
1

Personnellement, je cherchais quelque chose pour me permettre de calculer la zone de chaîne multiligne, afin que je puisse déterminer si la zone donnée est suffisamment grande pour imprimer la chaîne - en préservant la police spécifique.

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
la source