Tính chiều rộng hiển thị của một chuỗi trong Java


91

Làm cách nào để tính chiều dài (tính bằng pixel) của một chuỗi trong Java?

Thích hợp mà không cần sử dụng Swing.

CHỈNH SỬA: Tôi muốn vẽ chuỗi bằng drawString () trong Java2D và sử dụng độ dài để gói từ.


4
Nếu không có Swing? Bạn đang sử dụng thiết bị nào? Phông chữ gì? Cỡ nào? Phong cách gì? Tất cả những điều này thay đổi chiều rộng hiển thị.
S.Lott

3
Bạn định vẽ chuỗi như thế nào? Với AWT? Hoặc với một số bộ công cụ khác? Kích thước của chuỗi tính bằng pixel phụ thuộc vào API vẽ sẽ vẽ pixel sau này (và tất nhiên là bạn sử dụng phông chữ nào và cỡ chữ nào và phông chữ có đậm / nghiêng hay không, v.v.). Nếu biết API bản vẽ và các thuộc tính phông chữ, một chuỗi không có kích thước nào.
Mecki

1
@S. Lott. Bạn có nó trong một. Tôi đã muốn kết thúc điều này như một câu hỏi không phải câu hỏi.
David Arno

1
@David Arno: Tôi là một người yêu thích trò chơi n00bz. Tôi sẽ thêm thẻ [người mới bắt đầu].
S.Lott

Đối với .NET tương đương, có lớp TextRenderer, hãy xem stackoverflow.com/questions/604298/…
Spoike

Câu trả lời:


137

Nếu bạn chỉ muốn sử dụng AWT, thì hãy sử dụng Graphics.getFontMetrics(tùy chọn chỉ định phông chữ, đối với phông chữ không phải mặc định) để lấy a FontMetricsvà sau đó FontMetrics.stringWidthtìm chiều rộng cho chuỗi được chỉ định.

Ví dụ: nếu bạn có một Graphicsbiến được gọi là g, bạn sẽ sử dụng:

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

Đối với các bộ công cụ khác, bạn sẽ cần cung cấp thêm thông tin cho chúng tôi - nó sẽ luôn phụ thuộc vào bộ công cụ.


8
Có thể rõ ràng hơn nếu bạn cung cấp cách sử dụng ví dụ, ban đầu tôi đã cố gắng sử dụng nó như một phương thức tĩnh, như bạn đã viết theo cách đó.
Aequitas

Không được chấp nhận! nhưng vẫn là phương pháp tốt nhất !, Tại sao họ lại phản đối một phương pháp khi không có cách nào tốt hơn !!! Tôi chỉ không nhận được nó!
Iman

2
@Zich: Tôi không chắc chắn phương pháp nào bạn đang nói là bị phản đối - không phải của họ được đánh dấu là bị phản đối trong tài liệu Java 8 như xa như tôi có thể nhìn thấy ...
Jon Skeet

2
@Zich: Đó là một phương pháp trong Graphics, không phải FontMetrics. Nhưng bạn đang gọi Toolkit.getFontMetrics, thực sự không được dùng nữa, và đó không phải là điều mà phương pháp này nói về ... bạn cần phải thực sự cẩn thận về loại điều này, đặc biệt là trước khi bạn bắt đầu nói về việc báo cáo lỗi ...
Jon Skeet

1
@Zich: Chà, tôi sẽ không đoán - tôi sẽ sử dụng phương pháp không dùng nữa hoặc các phương pháp không dùng nữa được Toolkit.getFontMetricsđề xuất thay thế.
Jon Skeet

55

Nó không phải lúc nào cũng phụ thuộc vào bộ công cụ hoặc không phải lúc nào cũng cần sử dụng phương pháp FontMetrics vì nó yêu cầu người ta phải có được đối tượng đồ họa trước tiên không có trong vùng chứa web hoặc trong môi trường không có đầu.

Tôi đã thử nghiệm điều này trong một dịch vụ web và nó tính toán chiều rộng văn bản.

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

Thêm các giá trị cần thiết vào các thứ nguyên này để tạo bất kỳ lợi nhuận cần thiết nào.


1
Tôi không nghĩ rằng việc tạo một affineTransform và một fontRenderContext theo cách này sẽ dẫn đến một hành vi tốt. Tôi đoán font.getTransfrom () sẽ hợp lý hơn.
Lyth

1
Ví dụ của bạn vẫn đang sử dụng chức năng AWT. Với SWT Font, ví dụ, nó sẽ không làm việc, đây là lý do tại sao "nó luôn luôn sẽ là bộ công cụ phụ thuộc"
serg.nechaev

1
@Olofu Mark - getStringBounds chỉ đưa ra các giới hạn hợp lý. Để làm cho nó tốt hơn, nó nên sử dụng đối tượng getBounds () và LineMetrics để truy xuất chiều cao thực bao gồm, ascent + descent.
Jones

8

Sử dụng phương thức getWidth trong lớp sau:

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

Và bây giờ cho một cái gì đó hoàn toàn khác. Phần sau giả định phông chữ arial và đưa ra phỏng đoán dựa trên phép nội suy tuyến tính của ký tự so với chiều rộng.

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

Thú vị, nhưng có lẽ không thực tế lắm.


1

Cá nhân tôi đang tìm kiếm thứ gì đó để cho phép tôi tính toán vùng chuỗi nhiều dòng, vì vậy tôi có thể xác định xem vùng đã cho có đủ lớn để in chuỗi hay không - với việc bảo toàn phông chữ cụ thể.

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.