2008-12-15 22 views

Trả lời

19

Các getStringBounds() phương pháp dưới đây được dựa trên GlyphVector cho Graphics2D phông chữ hiện tại, trong đó hoạt động rất tốt cho một chuỗi dòng văn bản:

public class StringBoundsPanel extends JPanel 
{ 
    public StringBoundsPanel() 
    { 
     setBackground(Color.white); 
     setPreferredSize(new Dimension(400, 247)); 
    } 

    @Override 
    protected void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 

     Graphics2D g2 = (Graphics2D) g; 

     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
          RenderingHints.VALUE_ANTIALIAS_ON); 

     // must be called before getStringBounds() 
     g2.setFont(getDesiredFont()); 

     String str = "My Text"; 
     float x = 140, y = 128; 

     Rectangle bounds = getStringBounds(g2, str, x, y); 

     g2.setColor(Color.red); 
     g2.drawString(str, x, y); 

     g2.setColor(Color.blue); 
     g2.draw(bounds); 

     g2.dispose(); 
    } 

    private Rectangle getStringBounds(Graphics2D g2, String str, 
             float x, float y) 
    { 
     FontRenderContext frc = g2.getFontRenderContext(); 
     GlyphVector gv = g2.getFont().createGlyphVector(frc, str); 
     return gv.getPixelBounds(null, x, y); 
    } 

    private Font getDesiredFont() 
    { 
     return new Font(Font.SANS_SERIF, Font.BOLD, 28); 
    } 

    private void startUI() 
    { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(this); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) throws Exception 
    { 
     final StringBoundsPanel tb = new StringBoundsPanel(); 

     SwingUtilities.invokeAndWait(new Runnable() 
     { 
      public void run() 
      { 
       tb.startUI(); 
      } 
     }); 
    } 
} 

Lưu ý rằng tôi đã bỏ qua hàng nhập khẩu cho rõ ràng.

Kết quả:

Result screenshot.

+1

@nierito Câu trả lời hay và tuyệt vời! Dựa trên những gì bạn đã nói, tôi đã cố gắng rút ngắn mã của bạn (giả sử rằng đã xác định một 'Font' và nhận' FontMetrics' từ nó.) Nó hoạt động khá tốt. 'font.createGlyphVector (fontMetrics.getFontRenderContext(), text) .getVisualBounds(). getHeight(); ' –

+0

Làm thế nào để sử dụng GlyphVector.getPixelBounds so sánh với Font.getStringBounds và TextLayout.getBounds? Có một lợi thế lớn cho mã phức tạp hơn? Trong một thử nghiệm đơn giản, tôi thấy rằng phương thức Phông chữ đã báo cáo chiều cao so với hai phương pháp kia. Tôi thích nó và TextLayout không yêu cầu điểm x và y. – jla

+0

là 8 năm, nhưng khi tôi sử dụng g2d.scale (x, x); nó không thể hiển thị đúng! – yelliver

11

Điều gì khiến bạn nghĩ rằng nó trả về giá trị sai? Đó là nhiều hơn nữa có thể xảy ra mà mong đợi của bạn về những gì nó trả về không phù hợp với đặc điểm kỹ thuật. Lưu ý rằng nó hoàn toàn tốt nếu một số glyph trong Font đi qua hoặc dưới các giá trị đó.

getMaxDescent()getMaxAscent() sẽ cho bạn biết giá trị cực đại tuyệt đối của các trường đó cho bất kỳ hình tượng nào trong Phông chữ.

Nếu bạn muốn biết số liệu cho một Chuỗi cụ thể, thì bạn chắc chắn muốn gọi getLineMetrics().

2

getHeight() không thể cắt bỏ phần tử con của chuỗi, chỉ vẽ chuỗi có thể làm điều đó. Bạn đang sử dụng chiều cao được trả về từ getHeight để vẽ chuỗi bằng cách nào đó và có khả năng bạn đang lạm dụng chiều cao. Ví dụ: nếu bạn định vị điểm bắt đầu của chuỗi ở cuối hộp là getHeight() cao, thì đường cơ sở của văn bản của bạn sẽ nằm ở cạnh dưới cùng của hộp và rất có thể con cháu sẽ bị cắt bớt.

Hình học văn bản là một chủ đề phức tạp, được truyền với các tạo phẩm kỳ lạ trong lịch sử. Như những người khác đã đề xuất, hãy sử dụng getAscentgetDescent để cố định vị trí đường cơ sở chính xác trong hộp của bạn.

3

Gần đây tôi đã viết đoạn code dưới đây như tôi cần điểm ảnh đo hoàn hảo chiều cao cho các phạm vi cụ thể của phông chữ (ví dụ: tất cả các nhân vật thấp hơn, hoặc tất cả các số).

Nếu bạn cần mã nhanh hơn (tôi có cho vòng) Tôi khuyên bạn nên chạy nó một lần lúc khởi động để nhận tất cả các giá trị (ví dụ từ 1 đến 100) trong một mảng và sau đó sử dụng mảng thay thế. Mã này về cơ bản vẽ tất cả các ký tự từ chuỗi đầu vào tại cùng một vị trí chồng chéo trên một bitmap 250x250 (tăng hoặc giảm nếu cần), nó bắt đầu tìm kiếm pixel từ trên xuống, sau đó từ dưới cùng, sau đó nó trả về chiều cao tối đa được tìm thấy . Nó hoạt động với các chuỗi bình thường ngay cả khi nó được thiết kế cho các phạm vi ký tự. Điều này có nghĩa là có một loại dự phòng khi đánh giá các chuỗi thông thường khi một số ký tự lặp lại. Vì vậy, nếu chuỗi imput của bạn vượt quá số bảng chữ cái (26), hãy sử dụng như imput 'tRange': "abcd ... z" và các ký tự khác có thể được sử dụng. Nó nhanh hơn.

Hy vọng điều đó sẽ hữu ích.

public int getFontPixelHeight(float inSize, Paint sourcePaint, String tRange) 
{ 
    // It is assumed that the font is already set in the sourcePaint 

    int bW = 250, bH = 250;          // bitmap's width and height 
    int firstContact = -1, lastContact = -2;     // Used when scanning the pixel rows. Initial values are set so that if no pixels found, the returned result is zero. 
    int tX = (int)(bW - inSize)/2, tY = (int)(bH - inSize)/2; // Used for a rough centering of the displayed characters 

    int tSum = 0; 

    // Preserve the original paint attributes 
    float oldSize = sourcePaint.getTextSize(); 
    int oldColor = sourcePaint.getColor(); 
    // Set the size/color 
    sourcePaint.setTextSize(inSize); sourcePaint.setColor(Color.WHITE); 

    // Create the temporary bitmap/canvas 
    Bitmap.Config bConf = Bitmap.Config.ARGB_8888; 
    Bitmap hld = Bitmap.createBitmap(250, 250, bConf); 
    Canvas canv = new Canvas(hld); 

    for (int i = 0; i < bH; i++) 
    { 
     for (int j = 0; j < bW; j++) 
     { 
      hld.setPixel(j, i, 0); // Zero all pixel values. This might seem redundant, but I am not quite sure that creating a blank bitmap means the pixel color value is indeed zero, and I need them to be zero so the addition performed below is correct. 
     } 
    } 

    // Display all characters overlapping at the same position 
    for (int i = 0; i < tRange.length(); i++) 
    { 
     canv.drawText("" + tRange.charAt(i), tX, tY, sourcePaint); 
    } 

    for (int i = 0; i < bH; i++) 
    { 
     for (int j = 0; j < bW; j++) 
     { 
      tSum = tSum + hld.getPixel(j, i); 
     } 

     if (tSum > 0) // If we found at least a pixel, save row index and exit loop 
     { 
      firstContact = i; 
      tSum = 0; // Reset 
      break; 
     } 
    } 

    for (int i = bH - 1; i > 0 ; i--) 
    { 
     for (int j = 0; j < bW; j++) 
     { 
      tSum = tSum + hld.getPixel(j, i); 
     } 

     if (tSum > 0) // If we found at least a pixel, save row index and exit loop 
     { 
      lastContact = i; 
      break; 
     } 
    } 

    // Restore the initial attributes, just in case the paint was passed byRef somehow 
    sourcePaint.setTextSize(oldSize); 
    sourcePaint.setColor(oldColor); 

    return lastContact - firstContact + 1; 
} 
Các vấn đề liên quan