Обчисліть ширину відображення рядка в Java


91

Як обчислити довжину (у пікселях) рядка в Java?

Переважно без використання Swing.

EDIT: Я хотів би намалювати рядок за допомогою drawString () у Java2D і використовувати довжину для переносу слів.


4
Без гойдалки? Який пристрій ви використовуєте? Який шрифт? Який розмір? Який стиль? Усі ці речі змінюють ширину дисплея.
S.Lott

3
Як ви збираєтесь намалювати струну? З AWT? Або з якимсь іншим набором інструментів? Розмір рядка в пікселях залежить від API малювання, який буде малювати піксель пізніше (і, звичайно, який шрифт ви використовуєте та якого розміру шрифту, і якщо шрифт виділений жирним / курсивом тощо). Без знання API малювання та властивостей шрифту, рядок не має жодного розміру.
Мекі

1
@S. Лотт. У вас це в одному. У мене було спокуса закрити це як не питання.
Девід Арно

1
@ Девід Арно: Я софі на n00bz. Я додаю тег [для початківців].
S.Lott

Для .NET еквівалента є TextRenderer клас, см stackoverflow.com/questions/604298 / ...
Spoike

Відповіді:


137

Якщо ви просто хочете використовувати AWT, тоді скористайтеся Graphics.getFontMetrics(необов’язково вказавши шрифт, для шрифту, який не за замовчуванням), щоб отримати, FontMetricsа потім FontMetrics.stringWidthзнайти ширину для вказаного рядка.

Наприклад, якщо у вас є Graphicsвикликана змінна g, ви б використали:

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

Що стосується інших наборів інструментів, вам потрібно буде надати нам більше інформації - вона завжди буде залежати від набору інструментів.


8
Можливо, буде зрозуміліше, якщо ви надасте приклад використання, спочатку я намагався використовувати його як статичний метод, оскільки ви це так написали.
Aequitas

Застаріле! але все-таки найкращий метод !, Чому вони відмовляються від методу, коли немає кращого способу !!! Я просто не розумію!
Іман

2
@Zich: Я не впевнений, який із запропонованих вами методів є застарілим - наскільки я бачу, жоден з них не позначений як застарілий ...
Джон Скіт,

2
@Zich: Це метод Graphics, а не FontMetrics. Але ви дзвоните Toolkit.getFontMetrics, що насправді застаріло, і не про що говорить цей метод ... вам потрібно бути дуже обережними щодо такого роду речей, особливо перед тим, як почати говорити про повідомлення про помилки ...
Джон Скіт

1
@Zich: Ну, я б не здогадувався - я б використав Toolkit.getFontMetricsзамість цього застарілий метод або не застарілі методи .
Джон Скіт,

55

Це не завжди повинно залежати від інструментарію, або не завжди потрібно використовувати підхід FontMetrics, оскільки для цього потрібно спочатку отримати графічний об’єкт, який відсутній у веб-контейнері або в безголовому середовищі.

Я перевірив це у веб-сервлеті, і він обчислює ширину тексту.

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

Додайте необхідні значення до цих розмірів, щоб створити будь-яке необхідне поле.


1
Я не думаю, що створення affineTransform і fontRenderContext таким чином призведе до хорошої поведінки. Я думаю, font.getTransfrom () було б більш логічним.
Літ

1
У вашому прикладі все ще використовується функціональність AWT. Наприклад, із SWT Font він не буде працювати, ось чому "він завжди буде залежати від інструментарію"
serg.nechaev

1
@Olofu Mark - getStringBounds дає лише логічні межі. Щоб покращити його, слід скористатися об'єктами getBounds () та LineMetrics для отримання фактичної висоти, включаючи підйом + спуск.
Джонс

8

Використовуйте метод getWidth у наступному класі:

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

А тепер щось зовсім інше. Далі передбачається аріальний шрифт і робиться дика здогадка на основі лінійної інтерполяції символу проти ширини.

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

Цікаво, але, можливо, не дуже практично.


1

Я особисто шукав щось, що дозволило б мені обчислити багаторядкову область рядка, щоб я міг визначити, чи є дана область достатньо великою для друку рядка - із збереженням конкретного шрифту.

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.