Вопрос по java, graphics – Как вы рисуете строку по центру в Java?

20

Я знаю, что это простая концепция, но я борюсь с метриками шрифта. Центрирование по горизонтали не слишком сложно, но по вертикали кажется немного сложным.

Я пытался использовать методы FontMetrics getAscent, getLeading, getXXXX в различных комбинациях, но независимо от того, что я пробовал, текст всегда отключен на несколько пикселей. Есть ли способ измерить точную высоту текста, чтобы он был точно по центру.

Ваш Ответ

4   ответа
1

Другим вариантом являетсяGetBounds метод изКласс TextLayout.

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

Не уверен, что это помогает, ноdrawString(s, x, y) устанавливаетbaseline текста у

Я работал с некоторым вертикальным центрированием и не мог заставить текст выглядеть правильно, пока не заметил такое поведение, упомянутое в документах. Я предполагал, что нижняя часть шрифта была у.

Для меня исправить было вычестьfm.getDescent() от координаты у.

11

Я нашел рецептВот.

Решающие методы, кажется,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.

(примечание: приведенный выше кодЛицензия MIT как отмечено на странице.)

Да ... я знаком с этим понятием ... но это неправильно. Метод fm.getAscent () является проблемой. Он не сообщает о реальном росте шрифта в пикселях и приводит к тексту, который находится ближе к нижней части, чем к верхней. Paul Alexander
48

Обратите внимание, выdo нужно точно учитывать, что вы подразумеваете под вертикальным центрированием.

Шрифты отображаются на базовой линии, проходящей вдоль нижней части текста. Вертикальное пространство распределяется следующим образом:

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

Начальная буква - это просто рекомендуемое расстояние между строками шрифта. Ради центрирования по вертикали между двумя точками следует игнорировать ведение (это - ведение, кстати, не прохождение; в обычной типографии это / было расстояние между отведениями, вставленное между линиями на печатной пластине).

Таким образом, для центрирования текста по возрастанию и спуску, вы хотите

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

Без окончательного "+ подъем" у вас есть позиция для верхней части шрифта; поэтому добавление восхождения идет от вершины до базовой линии.

Также отметим, что высота шрифта должна включать начальные символы, но некоторые шрифты не включают ее, и из-за различий в округлении высота шрифта может не совпадать (начальные + всплывающие + спускающиеся).

Ого, это идеальное объяснение. Большое спасибо! (также для объяснения ведущего, не знал этого)
Есть причина, по которой вы добавляете 1?
@ Алекс: Потому что (снизу + 1 сверху) высота; если низ и верх одинаковы, высота равна единице, а не нулю. Чистый эффект заключается в округлении вниз в случае, если средняя точка составляет n.5 пикселей.

Похожие вопросы