Изменение размера текста с использованием FontMetrics

Добавлено : 29 Mar 2009, 10:31

Содержание

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).

Теги: font swing