Изменение размера текста с использованием FontMetrics
Содержание
1 Введение
2 Пример получения размеров шрифта
3 Результат работы
4 Рамка вокруг строки
5 Ссылки
Введение
Предположим, что вы используете объект Graphics в Swing для вывода какого-либо текста. Ваша программа должна вывести две строки текста. Программа вызывает метод Graphics.drawString для вывода первой строки и вызывает его снова для вывода второй. Метод drawString требует указания координат X,Y начальной позиции текста. Для второй строки вы предположили, что добавление 8 к Y достаточно для выполнения работы. То есть, вы предположили, что высота символов равна примерно 8. Например, первая строка начинается с 100,100, вторая - с 100,108. Код программы выглядит примерно так:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FmDemo1 {
public static void main(String args[]) {
JFrame frame = new JFrame("FmDemo1");
// обработать закрытие окна
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
final JPanel panel = new JPanel();
// создать кнопку и добавить к ней
// перехватчик действий
JButton button = new JButton("Draw Text");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Graphics g = panel.getGraphics();
// вывести две строки текста
int BASE1 = 100;
int OFFSET1 = 8;
g.drawString("LINE 1", 100, BASE1);
g.drawString("LINE 2", 100, BASE1 + OFFSET1);
// вывести две строки текста,
// используя метрику шрифта
FontMetrics fm = g.getFontMetrics();
int BASE2 = 150;
int OFFSET2 = fm.getHeight();
g.drawString("LINE 1", 100, BASE2);
g.drawString("LINE 2", 100, BASE2 + OFFSET2);
}
});
panel.add(button);
frame.getContentPane().add(panel);
frame.setSize(250, 250);
frame.setLocation(300, 200);
frame.setVisible(true);
}
}
Эта программа работает. Выберите кнопку Draw Text и вы увидите две строки текста, следующие после других двух строк. Обратите внимание, что первые две строки отображаются почти рядом. Проблема может быть решена изменением значения 8 на большее число, например, 18. Но такой подход упускает один момент. Если вы отображаете текст как часть набора графических операций, в вашей программе необходимо учитывать различные размеры шрифта. Другими словами, программа должна автоматически подстраивать себя в зависимости от размеров шрифтов, с которыми она имеет дело. Вы можете решить проблему изменением значения с 8 на 18 в примере FmDemo1, но вдруг вы будете работать с действительно большими шрифтами? В этом случае значения высоты 18 может быть недостаточно.
Пример получения размеров шрифта
Лучший подход продемонстрирован во второй группе операторов drawString в FmDemo1, которая отображает нижние две строки текста. Программа получает объект FontMetrics. Затем она вызывает метод getHeight обекта для получения значения высоты шрифта. Оно затем используется вместо фиксированных значений, таких как 8 или 18.
Чтобы увидеть, какая информация доступна, рассмотрим другой пример:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FmDemo2 {
public static void main(String args[]) {
JFrame frame = new JFrame("FmDemo2");
// обработать закрытие окна
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// создать панель и установить ее шрифт
final JPanel panel = new JPanel();
Font f = new Font("Monospaced", Font.ITALIC, 48);
panel.setFont(f);
// создать кнопку и перехватчик
// действий для нее
JButton button = new JButton("Draw Text");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int XBASE = 50;
int YBASE = 100;
String test_string = "hqQWpy`/\'|i\\,{_!^";
Graphics g = panel.getGraphics();
FontMetrics fm = g.getFontMetrics();
int ascent = fm.getAscent();
int descent = fm.getDescent();
int width = fm.stringWidth(test_string);
// отобразить текстовую строку
g.drawString(test_string, XBASE, YBASE);
// отобразить верхнюю линию
g.setColor(Color.red);
g
.drawLine(XBASE, YBASE - ascent, XBASE + width, YBASE
- ascent);
// отобразить основную линию
g.setColor(Color.green);
g.drawLine(XBASE, YBASE, XBASE + width, YBASE);
// отобразить нижнюю линию
g.setColor(Color.blue);
g.drawLine(XBASE, YBASE + descent, XBASE + width, YBASE
+ descent);
}
});
panel.add(button);
frame.getContentPane().add(panel);
frame.setSize(600, 250);
frame.setLocation(250, 200);
frame.setVisible(true);
}
}
Результат работы
Запустите эту программу и выберите кнопку Draw Text. Вы увидите строку текста с тремя цветными линиями над ней, внутри нее и под ней. Зеленая линия в середине является базовой линией. Это начальная точка для вычислений различных размеров шрифта. Когда Abstract Window Toolkit (AWT) рисует символ, точка отсчета X,Y для него расположена на левой границе символа и на базовой линии.
Красная линия сверху называется подъемом. Это расстояние от базовой линии к верхней границе большинства символов. Синяя линия называется спуском. Это расстояние от базовой линии к нижней границе большинства символов. Возможно, что некоторые символы будут иметь больший подъем или спуск. FontMetrics предоставляет методы getMaxAscent и getMaxDescent для получения максимальных значений для шрифта. Существует также свойство, называемое интерлиньяж, представляющее размер зарезервированного пустого места между спуском одной строки текста и подъемом следующей.
Программа FmDemo2 показывает также использование метода stringWidth, который вычисляет графическую ширину строки. Каждый символ шрифта имеет так называемую ширину опережения. Это позиция, с которой AWT должен разместить следующий символ после вывода текущего символа. Ширина опережения строки не обязательно равна сумме ширин ее символов, измеренных по отдельности, потому что ширины некоторых символов могут меняться в зависимости от контекста.
Рамка вокруг строки
Рассмотрим последний пример, показывающий как нарисовать ограничивающую рамку вокруг строки:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class FmDemo3 {
public static void main(String args[]) {
JFrame frame = new JFrame("FmDemo3");
// обработать закрытие окна
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// создать панель и установить для нее шрифт
final JPanel panel = new JPanel();
Font f = new Font("Monospaced", Font.ITALIC, 48);
panel.setFont(f);
JButton button = new JButton("Draw Text");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int XBASE = 50;
int YBASE = 100;
String test_string = "hqQWpy`/\'|i\\,{_!^";
Graphics g = panel.getGraphics();
FontMetrics fm = g.getFontMetrics();
// отобразить текстовую строку
g.drawString(test_string, XBASE, YBASE);
// нарисовать вокруг нее ограничивающую рамку
RectangularShape rs = fm.getStringBounds(test_string, g);
Rectangle r = rs.getBounds();
g.setColor(Color.red);
g.drawRect(XBASE + r.x, YBASE + r.y, r.width, r.height);
}
});
panel.add(button);
frame.getContentPane().add(panel);
frame.setSize(600, 250);
frame.setLocation(250, 200);
frame.setVisible(true);
}
}
В программе FmDemo3 используется метод getStringBounds для получения объекта RectangularShape. Затем программа вызывает getBounds для получения ограничивающей рамки, которая рисуется вокруг текста. Это полезно в тех случаях, когда вы пытаетесь расположить текст и графику вместе и хотите знать, сколько пространства занимает текст.
Ссылки
Дополнительная информация о измерении размеров текста с помощью FontMetrics находится в разделе "Font и FontMetrics" главы 4 книги "Графика в Java: освоение JFC, 3-е издание, том 1, AWT" David Geary (http://www.sun.com/books/catalog/Geary3/index.html).