Calcular el ancho de visualización de una cadena en Java


91

¿Cómo calcular la longitud (en píxeles) de una cadena en Java?

Preferible sin usar Swing.

EDITAR: Me gustaría dibujar la cadena usando drawString () en Java2D y usar la longitud para el ajuste de palabras.


4
¿Sin swing? ¿Qué dispositivo estás usando? ¿Qué tipo de letra? ¿Qué tamaño? ¿Que estilo? Todas estas cosas cambian el ancho de la pantalla.
S.Lott

3
¿Cómo vas a dibujar la cuerda? ¿Con AWT? ¿O con alguna otra caja de herramientas? El tamaño de la cadena en píxeles depende de la API de dibujo que dibujará el píxel más adelante (y, por supuesto, qué fuente utiliza y qué tamaño de fuente y si la fuente es negrita / cursiva, etc.). Sin conocer la API de dibujo y las propiedades de la fuente, una cadena no tiene ningún tamaño.
Mecki

1
@S. Lott. Lo tienes en uno. Estuve tentado a cerrar esto como si no fuera una pregunta.
David Arno

1
@David Arno: Soy un blando en el n00bz. Agregaré la etiqueta [principiante].
S.Lott

Para el equivalente de .NET, existe la clase TextRenderer, consulte stackoverflow.com/questions/604298/…
Spoike

Respuestas:


137

Si solo desea usar AWT, use Graphics.getFontMetrics(especificando opcionalmente la fuente, para una que no sea la predeterminada) para obtener un FontMetricsy luego FontMetrics.stringWidthpara encontrar el ancho de la cadena especificada.

Por ejemplo, si tiene una Graphicsvariable llamada g, usaría:

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

Para otros conjuntos de herramientas, deberá proporcionarnos más información; siempre dependerá del conjunto de herramientas.


8
Podría ser más claro si proporciona un uso de ejemplo, inicialmente intenté usarlo como un método estático, como lo escribió de esa manera.
Aequitas

¡Obsoleto! ¡Pero sigue siendo el mejor método !, ¡¡¡Por qué desaprueban un método cuando no hay una mejor manera !!! ¡Simplemente no entiendo!
Iman

2
@Zich: No estoy seguro de qué método está diciendo que está en desuso; ninguno de ellos está marcado como obsoleto en la documentación de Java 8 por lo que puedo ver ...
Jon Skeet

2
@Zich: Es un método Graphics, no FontMetrics. Pero estás llamando Toolkit.getFontMetrics, lo que de hecho está desaprobado, y no es de lo que habla este método ... debes tener mucho cuidado con este tipo de cosas, especialmente antes de comenzar a hablar sobre informar errores ...
Jon Skeet

1
@Zich: Bueno, no adivinaría, usaría el método no obsoleto o los métodos no obsoletos que Toolkit.getFontMetricssugiere en su lugar.
Jon Skeet

55

No siempre es necesario que dependa del kit de herramientas o no siempre es necesario utilizar el enfoque FontMetrics, ya que requiere que primero se obtenga un objeto gráfico que está ausente en un contenedor web o en un entorno sin cabeza.

He probado esto en un servlet web y calcula el ancho del 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());

Agregue los valores necesarios a estas dimensiones para crear cualquier margen requerido.


1
No creo que crear un affineTransform y un fontRenderContext de esta manera resulte en un buen comportamiento. Supongo que font.getTransfrom () sería más lógico.
Lyth

1
Su ejemplo todavía usa la funcionalidad AWT. Con SWT Font, por ejemplo, no va a funcionar, es por eso que "siempre dependerá del conjunto de herramientas"
serg.nechaev

1
@Olofu Mark - getStringBounds solo da los límites lógicos. Para mejorarlo, debe usar getBounds () y el objeto LineMetrics para recuperar la altura real, incluido el ascenso + descenso.
Jones

8

Utilice el método getWidth en la siguiente clase:

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

}

1

Y ahora algo completamente diferente. Lo siguiente asume una fuente arial y hace una suposición salvaje basada en una interpolación lineal de caracteres frente a ancho.

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

Interesante, pero quizás no muy práctico.


1

Personalmente, estaba buscando algo que me permitiera calcular el área de la cadena de varias líneas, para poder determinar si el área dada es lo suficientemente grande para imprimir la cadena, conservando una fuente 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;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.