2009-06-28 70 views
20

Tôi biết đó là một khái niệm đơn giản nhưng tôi đang đấu tranh với các chỉ số phông chữ. Định tâm theo chiều ngang không quá khó nhưng theo chiều dọc có vẻ hơi khó.Làm cách nào để vẽ một chuỗi được căn giữa theo chiều dọc trong Java?

Tôi đã thử sử dụng các phương thức getMenny, getLeading, getXXXX của FontMetrics trong các kết hợp khác nhau nhưng không có vấn đề gì tôi đã thử văn bản luôn bị tắt bởi một vài pixel. Có cách nào để đo chiều cao chính xác của văn bản để nó được căn giữa chính xác không.

Trả lời

48

Lưu ý, bạn làm cần phải xem xét chính xác những gì bạn có nghĩa là bằng cách căn giữa dọc.

Phông chữ được hiển thị trên đường cơ sở, chạy dọc theo cuối văn bản. Không gian dọc được phân bổ như sau:

--- 
^ 
| leading 
| 
-- 
^    Y  Y 
|    Y Y 
|    Y Y 
| ascent   Y  y  y 
|     Y  y y 
|     Y  y y 
-- baseline ______Y________y_________ 
|       y     
v descent    yy 
-- 

Hàng đầu chỉ đơn giản là không gian được đề xuất của phông chữ giữa các dòng. Vì lợi ích của định tâm theo chiều dọc giữa hai điểm, bạn nên bỏ qua hàng đầu (nó ledding, BTW, không leeding; trong typography chung nó là/là khoảng cách dẫn chèn giữa các dòng trong một tấm in).

Vì vậy, đối centering ascenders văn bản và xuống của, bạn muốn

baseline=(top+((bottom+1-top)/2) - ((ascent + descent)/2) + ascent; 

Nếu không có trận chung kết "+ đi lên", bạn có vị trí cho phía trên cùng của phông chữ; do đó việc tăng độ cao đi từ đỉnh lên đường cơ sở. Ngoài ra, lưu ý rằng chiều cao phông chữ nên bao gồm hàng đầu, nhưng một số phông chữ không bao gồm nó, và do sự khác biệt làm tròn, chiều cao phông chữ có thể không chính xác bằng nhau (dẫn + đi lên + gốc).

+0

Oh wow, Đó là một lời giải thích hoàn hảo. Cảm ơn nhiều! (cũng cho lời giải thích hàng đầu, không biết điều đó) – brimborium

+1

Bất kỳ lý do nào khiến bạn thêm 1? – Max

+1

@Alex: Bởi vì (dưới cùng + 1-top) là chiều cao; nếu dưới cùng và trên cùng là chiều cao là một, không phải bằng không.Hiệu ứng ròng là làm tròn xuống trong trường hợp điểm giữa là n.5 pixel. –

11

Tôi đã tìm thấy công thức here.

Các phương pháp quan trọng dường như là getStringBounds()getAscent()

// Find the size of string s in font f in the current Graphics context g. 
FontMetrics fm = g.getFontMetrics(f); 
java.awt.geom.Rectangle2D rect = fm.getStringBounds(s, g); 

int textHeight = (int)(rect.getHeight()); 
int textWidth = (int)(rect.getWidth()); 
int panelHeight= this.getHeight(); 
int panelWidth = this.getWidth(); 

// Center text horizontally and vertically 
int x = (panelWidth - textWidth)/2; 
int y = (panelHeight - textHeight)/2 + fm.getAscent(); 

g.drawString(s, x, y); // Draw the string. 

(lưu ý:. Trên code được bao phủ bởi các MIT License như đã nêu trên trang)

+2

Vâng ... Tôi đã quen với khái niệm này ... nhưng không đúng. Phương thức fm.getAscent() là vấn đề. Nó không báo cáo độ dốc pixel thực của phông chữ và kết quả là văn bản gần với phần cuối hơn so với đầu. –

2

Không chắc chắn điều này hữu ích, nhưng drawString(s, x, y) đặt đường cơ sở của văn bản tại y.

Tôi đã làm việc với việc thực hiện một số căn giữa theo chiều dọc và không thể xem văn bản ở bên phải cho đến khi tôi nhận thấy hành vi được đề cập trong tài liệu. Tôi đã giả định dưới cùng của phông chữ là tại y.

Đối với tôi, bản sửa lỗi là trừ fm.getDescent() khỏi tọa độ y.

1

Một tùy chọn khác là phương pháp getBounds từ TextLayout class.

Font f; 
// code to create f 
String TITLE = "Text to center in a panel."; 
FontRenderContext context = g2.getFontRenderContext(); 

TextLayout txt = new TextLayout(TITLE, f, context); 
Rectangle2D bounds = txt.getBounds(); 
int xString = (int) ((getWidth() - bounds.getWidth())/2.0); 
int yString = (int) ((getHeight() + bounds.getHeight())/2.0); 
// g2 is the graphics object 
g2.setFont(f); 
g2.drawString(TITLE, xString, yString); 
Các vấn đề liên quan