Hitung lebar tampilan string di Java

91

Bagaimana cara menghitung panjang (dalam piksel) string di Java?

Lebih disukai tanpa menggunakan Ayunan.

EDIT: Saya ingin menggambar string menggunakan drawString () di Java2D dan menggunakan panjangnya untuk membungkus kata.

eflles
sumber
4
Tanpa Swing? Perangkat apa yang kamu gunakan? Font apa? Ukuran apa? Gaya apa? Semua hal ini mengubah lebar layar.
S. Lott
3
Bagaimana Anda akan menggambar senar? Dengan AWT? Atau dengan toolkit lain? Ukuran string dalam piksel bergantung pada API gambar yang akan menggambar piksel nanti (dan tentu saja font mana yang Anda gunakan dan ukuran font apa dan apakah font tersebut tebal / miring, dll.). Tanpa mengetahui API gambar dan properti font, string tidak memiliki ukuran apa pun.
Mecki
1
@. Lott. Anda memilikinya di satu. Saya tergoda untuk menutup ini sebagai non-pertanyaan.
David Arno
1
@David Arno: Saya seorang softie di n00bz. Saya akan menambahkan tag [pemula].
S. Lott
Untuk .NET yang setara, ada kelas TextRenderer, lihat stackoverflow.com/questions/604298/…
Spoike

Jawaban:

137

Jika Anda hanya ingin menggunakan AWT, gunakan Graphics.getFontMetrics(opsional menentukan font, untuk non-default) untuk mendapatkan FontMetricsdan kemudian FontMetrics.stringWidthuntuk menemukan lebar untuk string yang ditentukan.

Misalnya, jika Anda memiliki Graphicsvariabel yang dipanggil g, Anda akan menggunakan:

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

Untuk toolkit lain, Anda perlu memberi kami lebih banyak informasi - selalu bergantung pada toolkit.

Jon Skeet
sumber
8
Mungkin lebih jelas jika Anda memberikan contoh penggunaan, awalnya saya mencoba menggunakannya sebagai metode statis, karena Anda telah menulisnya seperti itu.
Aequitas
Tidak digunakan lagi! tetapi tetap merupakan metode terbaik !, Mengapa mereka mencela suatu metode padahal tidak ada cara yang lebih baik !!! Saya tidak mengerti!
Iman
2
@Zich: Saya tidak yakin metode mana yang Anda katakan tidak digunakan lagi - tidak satu pun dari mereka yang ditandai sebagai tidak digunakan lagi dalam dokumentasi Java 8 sejauh yang saya lihat ...
Jon Skeet
2
@Zich: Ini adalah metode Graphics, bukan FontMetrics. Tetapi Anda menelepon Toolkit.getFontMetrics, yang memang sudah usang, dan yang tidak dibicarakan metode ini ... Anda harus sangat berhati-hati tentang hal semacam ini, terutama sebelum Anda mulai berbicara tentang melaporkan bug ...
Jon Skeet
1
@Zich: Yah, saya tidak akan menebak - saya akan menggunakan metode non-deprecated, atau metode non-deprecated yang Toolkit.getFontMetricsmenyarankan.
Jon Skeet
55

Itu tidak selalu harus bergantung pada toolkit atau seseorang tidak selalu perlu menggunakan pendekatan FontMetrics karena ini mengharuskan seseorang untuk terlebih dahulu mendapatkan objek grafis yang tidak ada dalam wadah web atau dalam lingkungan tanpa kepala.

Saya telah menguji ini di web servlet dan itu menghitung lebar teks.

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

Tambahkan nilai yang diperlukan ke dimensi ini untuk membuat margin yang diperlukan.

Olofu Mark
sumber
1
Saya tidak berpikir membuat affineTransform dan fontRenderContext dengan cara ini akan menghasilkan perilaku yang baik. Saya kira font.getTransfrom () akan lebih logis.
Lyth
1
Contoh Anda masih menggunakan fungsionalitas AWT. Dengan Font SWT, misalnya, tidak akan berfungsi, inilah mengapa "itu akan selalu bergantung pada toolkit"
serg.nechaev
1
@Olofu Mark - getStringBounds hanya memberikan batasan logis. Untuk membuatnya lebih baik, itu harus menggunakan objek getBounds () dan LineMetrics untuk mengambil tinggi sebenarnya termasuk, ascent + descent.
Jones
8

Gunakan metode getWidth di kelas berikut:

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 Miskin
sumber
1

Dan sekarang untuk sesuatu yang sama sekali berbeda. Yang berikut mengasumsikan font arial, dan membuat tebakan liar berdasarkan interpolasi linier karakter vs lebar.

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

Menarik, tapi mungkin tidak terlalu praktis.

John Henckel
sumber
1

Saya pribadi sedang mencari sesuatu untuk memungkinkan saya menghitung area string multiline, jadi saya dapat menentukan apakah area yang diberikan cukup besar untuk mencetak string - dengan mempertahankan font tertentu.

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
sumber