使用 FontMetrics 计算文本长度

假设你要在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方法来获取字符的高度。这个高度被用于替换818这样的固定数值。

通常一个程序通过调用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提供了getMaxAscentgetMaxDescent方法来获取字符的最大值。还有一个被称为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来获取边框,它是画在文字四周的。这在你希望同时布置文字和图像,并希望知道字符站多大空间时,是非常有用的。

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值