Java: более удобный способ получить экземпляр FontMetrics - PullRequest
4 голосов
/ 02 мая 2010

Есть ли более удобный способ получить экземпляр FontMetrics, чем

FontMetrics fm = Graphics.getFontMetrics(Font);

Я ненавижу этот путь из-за следующего примера:

Если вы хотите создать в игре меню и хотите, чтобы все пункты меню находились в центре экрана, вам нужна метрика шрифта. Но, в основном, пункты меню кликабельны. Поэтому я создаю массив Rectangles, и все прямоугольники помещаются вокруг элементов, поэтому, когда мышь нажата, я могу просто использовать

for (int i = 0; i < rects.length; i++)
if (rects[i].contains(mouseX, mouseY)) { ... }

Но для создания ректов мне также нужны FontMetrics для их координат. Так что это означает, что я должен построить все свои прямоугольники в методе рисования моего меню.

Итак, я хочу получить метод FontMetrics, чтобы я мог построить прямоугольники в методе, вызываемом конструктором.

Ответы [ 6 ]

10 голосов
/ 09 августа 2013

Для меня проще всего было:

Font font = new Font("Helvetica",Font.PLAIN,12);
Canvas c = new Canvas();
FontMetrics fm = c.getFontMetrics(font);

Преимущества:

  1. Если вы вызовете c.getGraphics (), он вернет ноль (таким образом, нет графического объекта)
  2. Это (холст) также будет работать в режиме без головы.

Теперь вы можете легко получить высоту и ширину ...

5 голосов
/ 06 февраля 2013

Действительно правильный ответ - использовать Toolkit.

Font font = new Font("Courier New", Font.PLAIN, 14);
FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
2 голосов
/ 02 мая 2010

После того, как фоновый компонент, т. Е. Все, что находится за вашим меню, рендерится, у него появляется объект Graphics, который можно использовать для получения метрик для данного шрифта только один раз.

Вы, конечно, не хотите делать это в методе paint, который должен быть максимально легким. Я бы повесил этот код на слушателя, который вызывается при первой визуализации компонента. Он может хранить получившийся объект FontMetrics где-нибудь, где вы сможете впоследствии получить к нему доступ, либо в методе paint для отрисовки этих элементов меню.

Вместо того, чтобы определять измерения графики вашего меню в последний момент, т. Е. При paint использовании, было бы неплохо вместо этого создать некоторые компоненты для представления вашего меню. Вы можете разместить эти компоненты на стеклянной панели подробнее здесь , чтобы они плавали над всем остальным, и у вас будет дополнительный бонус, что все эти компоненты способны принимать щелчки мыши и запускать события слушателя на их, и поскольку они фиксируют события только по своей геометрии, вам даже не нужно выяснять, какая часть меню была нажата при щелчке, если вообще.

Еще одним преимуществом использования компонентов здесь является то, что вы можете полностью обойти требование манипулирования метриками шрифта. Есть готовые пункты меню, или вы можете просто использовать JLabels, и вы можете указать их выравнивание, вы можете использовать LayoutManager, чтобы установить размеры ячеек в соответствии с шириной самой большой метки и т. Д.

1 голос
/ 02 мая 2010

Предполагая, что текст меню фиксирован, вы можете предварительно нарисовать текст в BufferedImage с альфа-прозрачностью и затем выполнить ваши вычисления. Затем, когда вам понадобится текст меню, просто нарисуйте изображение.

Вам все равно придется выполнить некоторые вычисления смещения для центрирования изображения (при условии, что размер панели может измениться), но они должны быть относительно легкими.

0 голосов
/ 11 мая 2014

В дополнение к тому, что сказал Лонзак, как на счет этого:

public static FontMetrics getFontMetrics(Font font){
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gd = ge.getDefaultScreenDevice();
    GraphicsConfiguration config = gd.getDefaultConfiguration();

    Canvas c = new Canvas(config);
    return c.getFontMetrics(font);
}

Вы можете сохранить переменную 'config' как статическую переменную, чтобы она создавалась один раз в некотором служебном шрифтовом классе, который содержит другую информацию о шрифтах для вашей игры / среды разработки. Я думаю, вы могли бы сделать это с помощью переменной canvas.

0 голосов
/ 02 мая 2010

Я думаю, что это хорошее решение

private static HashMap<Font, FontMetrics> fontmetrics = new HashMap<Font, FontMetrics>();


public static FontMetrics getFontMetrics(Font font)
{
    if (fontmetrics.containsKey(font))
    {
        return fontmetrics.get(font);
    }
    FontMetrics fm = createFontMetrics(font);
    fontmetrics.put(font, fm);
    return fm;
}

private static FontMetrics createFontMetrics(Font font)
{
    BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics g = bi.getGraphics();
    FontMetrics fm = g.getFontMetrics(font);
    g.dispose();
    bi = null;
    return fm;
}
...