Как вы нарисовываете вертикальную строку по вертикали в Java?
Я знаю, что это простая концепция, но я борюсь с метриками шрифтов. Центрирование по горизонтали не слишком сложно, но по вертикали кажется немного сложным.
Я пробовал использовать методы getAscent, getLeading, getXXXX FontMetrics в разных комбинациях, но независимо от того, что я пробовал, текст всегда выключен на несколько пикселей. Есть ли способ измерить точную высоту текста так, чтобы он был точно центрирован.
Ответы
Ответ 1
Обратите внимание, что вам нужно точно рассмотреть, что вы подразумеваете под вертикальным центрированием.
Шрифты отображаются на базовой линии, проходящей вдоль нижней части текста. Вертикальное пространство распределяется следующим образом:
---
^
| leading
|
--
^ Y Y
| Y Y
| Y Y
| ascent Y y y
| Y y y
| Y y y
-- baseline ______Y________y_________
| y
v descent yy
--
Ведущим является просто рекомендуемое шрифтом место между строками. Для центрирования по вертикали между двумя точками вы должны игнорировать ведущие (это ведение, BTW, не leeding, в общей типографии это/было расстоянием между строками, вставленным между строками в печатной пластине).
Итак, для центрирования текстовых подрастеров и descenders вы хотите
baseline=(top+((bottom+1-top)/2) - ((ascent + descent)/2) + ascent;
Без окончательного "+ восхождения" у вас есть позиция для верхней части шрифта; поэтому добавление восхождения идет от вершины к базовой линии.
Также обратите внимание, что высота шрифта должна включать в себя ведущую, но некоторые шрифты не включают ее, и из-за округления различий высота шрифта может быть не совсем одинаковой (ведущий + восхождение + спуск).
Ответ 2
Я нашел рецепт здесь.
Ключевыми методами являются 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, как указано на странице.)
Ответ 3
Не уверен, что это помогает, но drawString(s, x, y)
устанавливает базовую линию текста в y.
Я работал с вертикальным центрированием и не мог заставить текст выглядеть правильно, пока не заметил это поведение, упомянутое в документах. Я предполагал, что нижняя часть шрифта была у.
Для меня исправить было вычитание fm.getDescent()
из y-координаты.
Ответ 4
Другим вариантом является метод 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);