使用 FontMetrics 计算文本长度

来源:互联网 发布:淘宝卖书的店铺 编辑:程序博客网 时间:2024/05/21 01:37

假设你要在Swing中使用Graphics对象画一些字符。你的程序需要显示两行字符。程序调用Graphics.drawString方法画第一行,然后,在调用一次,画第二行。DrawString方法需要你为字符指定起始位置X, Y。对于第二行,你假设Y增加8将实现这一功能。就是,你假设字符的高度是8。例如,如果第一行的起始位置是100,100,那么,第二行的起始位置是100,108。其代码段如下:

package EXP;

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对象包含着有关一个给定字符的大小的信息。

如果想了解哪些信息有效,让我们类看另一个例子:

package EXP;

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();
               
                System.out.println("=== ascent "+ascent);
                System.out.println("=== descent "+descent);
                System.out.println("=== xbase "+XBASE);
                System.out.println("=== YBASE "+YBASE);

                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在画完一个字符后放置另一个字符的位置。一个字符串的领先宽度没有必要计算它的字符的宽度和的绝对数值。因为一些字符的宽度是根据上下文变化的。

让我们在看最后一个例子,它说明了如何在一个字符串周围画边框:

package EXP;

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来获取边框,它是画在文字四周的。这在你希望同时布置文字和图像,并希望知道字符站多大空间时,是非常有用的。

原创粉丝点击