Calcule a largura de exibição de uma string em Java

92

Como calcular o comprimento (em pixels) de uma string em Java?

Preferível sem usar Swing.

EDIT: Eu gostaria de desenhar a string usando o drawString () em Java2D e usar o comprimento para quebra de linha.

eflles
fonte
4
Sem Swing? Que dispositivo você está utilizando? Qual fonte? Que tamanho? Que estilo? Todas essas coisas mudam a largura da tela.
S.Lott
3
Como você vai puxar o barbante? Com AWT? Ou com algum outro kit de ferramentas? O tamanho da string em pixels depende da API de desenho que desenhará o pixel posteriormente (e, claro, qual fonte você usa e qual tamanho de fonte e se a fonte está em negrito / itálico, etc.). Sem conhecer a API de desenho e as propriedades da fonte, uma string não tem tamanho algum.
Mecki
1
@S. Lott. Você tem isso em um. Fiquei tentado a encerrar isso sem questionar.
David Arno
1
@David Arno: Sou um molenga no n00bz. Vou adicionar a tag [iniciante].
S.Lott
Para .NET equivalente, existe a classe TextRenderer, consulte stackoverflow.com/questions/604298/…
Spoike,

Respostas:

138

Se você quiser apenas usar AWT, use Graphics.getFontMetrics(opcionalmente especificando a fonte, para uma fonte não padrão) para obter um FontMetricse, em seguida, FontMetrics.stringWidthpara encontrar a largura da string especificada.

Por exemplo, se você tem uma Graphicsvariável chamada g, você usa:

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

Para outros kits de ferramentas, você precisará nos fornecer mais informações - sempre dependerá do kit de ferramentas.

Jon Skeet
fonte
9
Pode ficar mais claro se você fornecer um uso de exemplo, inicialmente tentei usá-lo como um método estático, já que você escreveu dessa forma.
Aequitas de
Descontinuada! mas ainda assim o melhor método! Por que eles desaprovam um método quando não existe uma maneira melhor !!! Eu simplesmente não entendo!
Iman,
2
@Zich: Não tenho certeza de qual método você está dizendo que está obsoleto - nenhum deles está marcado como obsoleto na documentação do Java 8, tanto quanto posso ver ...
Jon Skeet,
2
@Zich: É um método Graphics, não FontMetrics. Mas você está chamando Toolkit.getFontMetrics, o que está de fato obsoleto, e não é sobre o que esse método fala ... você precisa ter muito cuidado com esse tipo de coisa, principalmente antes de começar a falar sobre relatar bugs ...
Jon Skeet
1
@Zich: Bem, eu não acho - eu usaria o método não obsoleto ou os métodos não obsoletos que Toolkit.getFontMetricssugerem.
Jon Skeet,
56

Nem sempre precisa ser dependente do kit de ferramentas ou nem sempre é necessário usar a abordagem FontMetrics, pois ela exige que primeiro se obtenha um objeto gráfico que está ausente em um contêiner da web ou em um ambiente sem periféricos.

Eu testei isso em um servlet da web e ele calcula a largura do texto.

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

Adicione os valores necessários a essas dimensões para criar qualquer margem necessária.

Olofu Mark
fonte
1
Não acho que criar um affineTransform e um fontRenderContext dessa forma resultará em um bom comportamento. Acho que font.getTransfrom () seria mais lógico.
Lyth,
1
Seu exemplo ainda está usando a funcionalidade AWT. Com a fonte SWT, por exemplo, não vai funcionar, é por isso que "sempre vai ser dependente do kit de ferramentas"
serg.nechaev
1
@Olofu Mark - getStringBounds fornece apenas os limites lógicos. Para torná-lo melhor, deve usar getBounds () e o objeto LineMetrics para recuperar a altura real, incluindo subida + descida.
Jones,
8

Use o método getWidth na seguinte classe:

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
fonte
1

E agora algo completamente diferente. O seguinte assume uma fonte arial e faz uma suposição com base em uma interpolação linear de caracteres x largura.

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

Interessante, mas talvez não muito prático.

John Henckel
fonte
1

Eu pessoalmente estava procurando por algo que me permitisse calcular a área da string multilinha, para que eu pudesse determinar se determinada área é grande o suficiente para imprimir a string - preservando a fonte específica.

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
fonte