Java'da bir dizenin görüntü genişliğini hesaplayın


91

Java'da bir dizenin uzunluğu (piksel cinsinden) nasıl hesaplanır?

Swing kullanmadan tercih edilir.

DÜZENLEME: Java2D'de drawString () kullanarak dizeyi çizmek ve kelime kaydırma için uzunluğu kullanmak istiyorum.


4
Swing olmadan mı? Hangi cihazı kullanıyorsun? Hangi yazı tipi? Hangi beden? Ne stili? Bütün bunlar ekran genişliğini değiştirir.
S.Lott

3
İpi nasıl çekeceksin? AWT ile mi? Veya başka bir araç setiyle? Dizenin piksel cinsinden boyutu, pikseli daha sonra çizecek olan çizim API'sine bağlıdır (ve tabii ki hangi yazı tipini ve hangi yazı tipi boyutunu ve yazı tipinin kalın / italik olup olmadığı vb.). Çizim API'sini ve yazı tipi özelliklerini bilmeden, bir dizenin hiçbir boyutu yoktur.
Mecki

1
@S. Lott. Birinde var. Bunu sorgusuz sualsiz kapatmak istedim.
David Arno

1
@David Arno: N00bz'de bir softie'yim. [Başlangıç] etiketini ekleyeceğim.
S.Lott

.NET eşdeğeri için TextRenderer sınıfı vardır, bkz. Stackoverflow.com/questions/604298/…
Spoike

Yanıtlar:


137

Sadece AWT'yi kullanmak istiyorsanız, a almak için Graphics.getFontMetrics(isteğe bağlı olarak yazı tipini, varsayılan olmayan bir yazı tipini belirtmek) FontMetricsve ardından FontMetrics.stringWidthbelirtilen dizenin genişliğini bulmak için kullanın.

Örneğin, Graphicsadında bir değişkeniniz varsa g, şunu kullanırsınız:

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

Diğer araç takımları için, bize daha fazla bilgi vermeniz gerekecek - her zaman araç takımına bağlı olacaktır.


8
Örnek bir kullanım sağlarsanız daha anlaşılır olabilir, bu şekilde yazdığınız için başlangıçta onu statik bir yöntem olarak kullanmaya çalıştım.
Aequitas

Kullanımdan kaldırıldı! ama yine de en iyi yöntem !, Daha iyi bir yol olmadığında neden bir yöntemi reddediyorlar !!! Sadece anlamıyorum!
Iman

2
@Zich: Söylediğiniz yöntemin kullanımdan kaldırıldığından emin değilim - görebildiğim kadarıyla ikisi de Java 8 belgelerinde kullanımdan kaldırıldı olarak işaretlenmemiş ...
Jon Skeet

2
@Zich: Bu bir yöntem Graphicsdeğil FontMetrics. Ama arıyorsun Toolkit.getFontMetrics, ki bu gerçekten kullanımdan kaldırıldı ve bu yöntemin bahsettiği şey bu değil ... Bu tür şeyler hakkında gerçekten dikkatli olmalısın, özellikle hataları bildirmeden önce ...
Jon Skeet

1
@Zich: Tahmin edemem - Kullanımdan kaldırılmamış yöntemi veya Toolkit.getFontMetricsonun yerine öneren, kullanımdan kaldırılmamış yöntemleri kullanırdım.
Jon Skeet

55

Her zaman araç setine bağlı olması gerekmez veya her zaman FontMetrics yaklaşımının kullanılması gerekmez, çünkü ilk önce bir web kabında veya başsız bir ortamda bulunmayan bir grafik nesnesini elde etmeyi gerektirir.

Bunu bir web sunucu uygulamasında test ettim ve metin genişliğini hesaplıyor.

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

Gerekli marjı oluşturmak için bu boyutlara gerekli değerleri ekleyin.


1
Bu şekilde affineTransform ve fontRenderContext oluşturmanın iyi bir davranışla sonuçlanacağını düşünmüyorum. Sanırım font.getTransfrom () daha mantıklı olacaktır.
Lyth

1
Örneğiniz hala AWT işlevselliğini kullanıyor. Örneğin SWT Yazı Tipi ile işe yaramayacak, bu yüzden "her zaman araç setine bağlı olacak"
serg.nechaev

1
@Olofu Mark - getStringBounds yalnızca mantıksal sınırları verir. Daha iyi hale getirmek için ascent + descent dahil gerçek yüksekliği almak için getBounds () ve LineMetrics nesnesini kullanmalıdır.
Jones

8

Aşağıdaki sınıfta getWidth yöntemini kullanın:

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

Ve şimdi tamamen farklı bir şey için . Aşağıdaki, bir yazı tipini varsayar ve karaktere karşı genişliğin doğrusal enterpolasyonuna dayalı vahşi bir tahmin yapar.

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

İlginç, ama belki de pek pratik değil.


1

Kişisel olarak çok satırlı dize alanını hesaplamama izin verecek bir şey arıyordum, böylece belirli bir yazı tipini koruyarak verilen alanın dizeyi yazdıracak kadar büyük olup olmadığını belirleyebildim.

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.