Calcola la larghezza di visualizzazione di una stringa in Java


92

Come calcolare la lunghezza (in pixel) di una stringa in Java?

Preferibile senza usare Swing.

EDIT: vorrei disegnare la stringa usando drawString () in Java2D e usare la lunghezza per il wrapping delle parole.


4
Senza Swing? Che dispositivo stai usando? Quale carattere? Che misura? Che stile? Tutte queste cose cambiano la larghezza del display.
S.Lott

3
Come disegnerai la corda? Con AWT? O con qualche altro toolkit? La dimensione della stringa in pixel dipende dall'API di disegno che disegnerà il pixel in seguito (e ovviamente quale carattere si utilizza e quale dimensione del carattere e se il carattere è in grassetto / corsivo, ecc.). Senza conoscere l'API di disegno e le proprietà del carattere, una stringa non ha alcuna dimensione.
Mecki

1
@S. Lott. Ce l'hai in uno. Sono stato tentato di chiudere questo come non-domanda.
David Arno

1
@David Arno: sono un tenero su n00bz. Aggiungerò il tag [principiante].
S.Lott

Per .NET equivalente c'è classe TextRenderer, vedere stackoverflow.com/questions/604298/...
Spoike

Risposte:


138

Se vuoi solo usare AWT, usa Graphics.getFontMetrics(opzionalmente specificando il carattere, per uno non predefinito) per ottenere un FontMetricse poi FontMetrics.stringWidthper trovare la larghezza per la stringa specificata.

Ad esempio, se hai una Graphicsvariabile chiamata g, dovresti usare:

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

Per altri toolkit, dovrai fornirci maggiori informazioni: dipenderà sempre dal toolkit.


9
Potrebbe essere più chiaro se fornisci un esempio di utilizzo, inizialmente ho tentato di usarlo come metodo statico, poiché l'hai scritto in questo modo.
Aequitas

Deprecato! ma ancora il metodo migliore !, Perché deprecano un metodo quando non c'è un modo migliore !!! Semplicemente non capisco!
Iman

2
@Zich: Non sono sicuro di quale metodo stai dicendo sia deprecato - nessuno dei due è contrassegnato come deprecato nella documentazione Java 8 per quanto posso vedere ...
Jon Skeet

2
@Zich: è un metodo Graphics, no FontMetrics. Ma stai chiamando Toolkit.getFontMetrics, che è davvero deprecato e di cui non parla questo metodo ... devi stare molto attento a questo genere di cose, in particolare prima di iniziare a parlare di segnalazione di bug ...
Jon Skeet

1
@Zich: Beh, non immagino - userei il metodo non deprecato, o invece i metodi non deprecati che Toolkit.getFontMetricssuggerisce.
Jon Skeet

56

Non è sempre necessario che sia dipendente dal toolkit o non è sempre necessario utilizzare l'approccio FontMetrics poiché richiede prima di ottenere un oggetto grafico che è assente in un contenitore web o in un ambiente senza testa.

L'ho testato in un servlet web e calcola la larghezza del testo.

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

Aggiungi i valori necessari a queste dimensioni per creare qualsiasi margine richiesto.


1
Non credo che la creazione di un affineTransform e di un fontRenderContext in questo modo comporterà un buon comportamento. Immagino che font.getTransfrom () sarebbe più logico.
Lyth

1
Il tuo esempio utilizza ancora la funzionalità AWT. Con SWT Font, ad esempio, non funzionerà, ecco perché "dipenderà sempre dal toolkit"
serg.nechaev

1
@Olofu Mark - getStringBounds fornisce solo i limiti logici. Per renderlo migliore dovrebbe usare getBounds () e l'oggetto LineMetrics per recuperare l'altezza effettiva inclusa, salita + discesa.
Jones

8

Utilizza il metodo getWidth nella seguente 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();
  }

}

1

E ora qualcosa di completamente diverso. Quanto segue assume il carattere ariale e fa un'ipotesi selvaggia basata su un'interpolazione lineare di carattere rispetto alla larghezza.

// 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, ma forse non molto pratico.


1

Personalmente stavo cercando qualcosa che mi permettesse di calcolare l'area della stringa multilinea, in modo da poter determinare se l'area data è abbastanza grande da stampare la stringa, preservando il carattere specifico.

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.