คำนวณความกว้างการแสดงผลของสตริงใน Java


92

วิธีคำนวณความยาว (เป็นพิกเซล) ของสตริงใน Java

เหมาะกว่าโดยไม่ต้องใช้ Swing

แก้ไข: ฉันต้องการวาดสตริงโดยใช้ drawString () ใน Java2D และใช้ความยาวสำหรับการตัดคำ


4
ไม่มีสวิง? คุณใช้อุปกรณ์อะไร ฟอนต์อะไร? ขนาดเท่าไหร่? สไตล์ไหน? สิ่งเหล่านี้เปลี่ยนความกว้างของการแสดงผล
ล็อต

3
คุณจะวาดสตริงได้อย่างไร? ด้วย AWT? หรือด้วยชุดเครื่องมืออื่น ๆ ? ขนาดของสตริงเป็นพิกเซลขึ้นอยู่กับ API การวาดภาพที่จะดึงพิกเซลในภายหลัง (และแน่นอนว่าคุณใช้ฟอนต์ใดและขนาดฟอนต์ใดและฟอนต์เป็นตัวหนา / ตัวเอียงเป็นต้น) หากไม่ทราบ API รูปวาดและคุณสมบัติแบบอักษรสตริงจะไม่มีขนาดใด ๆ
Mecki

1
@ ส. Lott. คุณมีในหนึ่งเดียว ฉันถูกล่อลวงให้ปิดสิ่งนี้ในฐานะที่ไม่ใช่คำถาม
David Arno

1
@David Arno: ฉันเป็นคนอ่อนใน n00bz ฉันจะเพิ่มแท็ก [เริ่มต้น]
ล็อต

สำหรับ. NET ที่เทียบเท่ามีคลาส TextRenderer ดูstackoverflow.com/questions/604298/…
Spoike

คำตอบ:


138

หากคุณต้องการใช้ AWT ให้ใช้Graphics.getFontMetrics(ระบุแบบอักษรเป็นทางเลือกสำหรับแบบอักษรที่ไม่ใช่ค่าเริ่มต้น) เพื่อรับFontMetricsและFontMetrics.stringWidthค้นหาความกว้างของสตริงที่ระบุ

ตัวอย่างเช่นหากคุณมีGraphicsตัวแปรที่เรียกว่าgคุณจะใช้:

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

สำหรับชุดเครื่องมืออื่น ๆ คุณจะต้องให้ข้อมูลเพิ่มเติมกับเราซึ่งจะขึ้นอยู่กับชุดเครื่องมือเสมอ


9
มันอาจจะชัดเจนกว่าถ้าคุณให้ตัวอย่างการใช้งานตอนแรกฉันพยายามใช้มันเป็นวิธีคงที่ตามที่คุณเขียนไว้อย่างนั้น
Aequitas

เลิกใช้แล้ว! แต่ก็ยังเป็นวิธีที่ดีที่สุด!, ทำไมพวกเขาถึงเลิกใช้วิธีการในเมื่อไม่มีวิธีที่ดีกว่า !!! ฉันไม่เข้าใจ!
Iman

2
@Zich: ฉันไม่แน่ใจว่าวิธีใดที่คุณบอกว่าเลิกใช้แล้ว - ทั้งสองวิธีนี้ไม่ถูกทำเครื่องหมายว่าเลิกใช้แล้วในเอกสาร Java 8 เท่าที่ฉันเห็น ...
Jon Skeet

2
@Zich: มันเป็นวิธีการในGraphicsไม่ใช่FontMetrics. แต่คุณกำลังโทรหาToolkit.getFontMetricsซึ่งเลิกใช้งานจริงและวิธีนี้ไม่ได้พูดถึงอะไร ... คุณต้องระวังเรื่องประเภทนี้โดยเฉพาะอย่างยิ่งก่อนที่คุณจะเริ่มพูดถึงการรายงานข้อบกพร่อง ...
Jon Skeet

1
@Zich: ฉันจะไม่เดา - ฉันจะใช้วิธีที่ไม่เลิกใช้หรือวิธีที่ไม่เลิกใช้ที่Toolkit.getFontMetricsแนะนำแทน
Jon Skeet

56

ไม่จำเป็นต้องขึ้นอยู่กับชุดเครื่องมือเสมอไปหรือไม่จำเป็นต้องใช้วิธี FontMetrics เสมอไปเนื่องจากต้องใช้วิธีการหนึ่งในการรับวัตถุกราฟิกที่ไม่มีอยู่ในคอนเทนเนอร์ของเว็บหรือในสภาพแวดล้อมที่ไม่มีหัว

ฉันได้ทดสอบสิ่งนี้ในเว็บ servlet และคำนวณความกว้างของข้อความ

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 () น่าจะมีเหตุผลมากกว่า
Lyth

1
ตัวอย่างของคุณยังคงใช้ฟังก์ชัน AWT ตัวอย่างเช่นด้วย SWT Font มันจะไม่ทำงานนี่คือเหตุผลว่าทำไม "มันจะขึ้นอยู่กับชุดเครื่องมือเสมอ"
serg.nechaev

1
@Olofu Mark - getStringBounds ให้ขอบเขตตรรกะเท่านั้น เพื่อให้ดีขึ้นควรใช้ออบเจ็กต์ getBounds () และ LineMetrics เพื่อดึงความสูงที่แท้จริงรวมถึงการขึ้น + ลง
Jones

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

และตอนนี้สำหรับสิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิง ต่อไปนี้ถือว่าเป็นฟอนต์ arial และทำการเดาแบบไวด์ตามการแก้ไขเชิงเส้นของอักขระเทียบกับความกว้าง

// 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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.