假设你要在Swing中使用Graphics对象画一些字符。你的程序需要显示两行字符。程序调用Graphics.drawString方法画第一行,然后,在调用一次,画第二行。DrawString方法需要你为字符指定起始位置X, Y。对于第二行,你假设Y增加8将实现这一功能。就是,你假设字符的高度是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");
// handle window closing
frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(
WindowEvent e) {
System.exit(0);
}
});
final JPanel panel = new JPanel();
// set up a button and add an
// action listener to it
JButton button = new JButton("Draw Text");
button.addActionListener(
new ActionListener() {
public void actionPerformed(
ActionEvent e) {
Graphics g = panel.getGraphics();
// draw two lines of text
int BASE1 = 100;
int OFFSET1 = 8;
g.drawString("LINE 1", 100, BASE1);
g.drawString("LINE 2",
100, BASE1 + OFFSET1);
// draw two lines of text,
// using font metrics
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就不够了。
一种比较好的解决方案在FmDemo1的第二组drawString语句中进行了说明,他们画了两行小写字符。这个程序获取了一个FontMetrics对象。然后,在这个对象中调用getHeight方法来获取字符的高度。这个高度被用于替换8或18这样的固定数值。
通常一个程序通过调用Graphics.getFontMetrics来获取一个FontMetrics对象。返回的对象实际上是FontMetrics的一个子类,FontMetrics是一个抽象类。FontMetrics对象包含着有关一个给定字符的大小的信息。
如果想了解哪些信息有效,让我们类看另一个例子:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FmDemo2 {
public static void main(String args[]) {
JFrame frame = new JFrame("FmDemo2");
// handle window closing
frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(
WindowEvent e) {
System.exit(0);
}
});
// set up a panel and set its font
final JPanel panel = new JPanel();
Font f = new Font(
"Monospaced", Font.ITALIC, 48);
panel.setFont(f);
// set up a button and action listener
// for it
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);
// draw a text string
g.drawString(
test_string, XBASE, YBASE);
// draw the ascent line
g.setColor(Color.red);
g.drawLine(XBASE, YBASE - ascent,
XBASE + width, YBASE - ascent);
// draw the base line
g.setColor(Color.green);
g.drawLine(XBASE, YBASE,
XBASE + width, YBASE);
// draw the descent line
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按钮。你将看到右上中下三行线条组成的字符串。绿色的线是在基准线上。这是用于计算字符测量偏差的起始点。在抽象窗口工具集(AWT)画一个字符时,字符的X,Y参考点是在基准线的字符的左侧。
顶端的红线上浮线。这是从基准线到所有字符的最上端的偏差。蓝色线条是下浮线。它是从基准线到所有字符最下端的偏差。也可能有些字符有更大的上浮或下浮。FontMetrics提供了getMaxAscent和getMaxDescent方法来获取字符的最大值。还有一个被称为leading的属性,用于表示在一行字符的下浮和另一行字符的上浮之间保留的空间。
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");
// handle window closing
frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(
WindowEvent e) {
System.exit(0);
}
});
// set up a panel and set a font for it
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();
// draw a text string
g.drawString(
test_string, XBASE, YBASE);
// draw a bounding box around it
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来获取边框,它是画在文字四周的。这在你希望同时布置文字和图像,并希望知道字符站多大空间时,是非常有用的。