在开发Swing程序的时候,很多情况下为了美观,我们需要将字体水平和垂直居中于某一个控件。


        让我们先来说说居中的算法。其实很简单,将外面控件的长度减去显示内容的长度,然后除以2,这样就得到了放置内容的X坐标。同理,将控件的高度减去内容的高度,然后除以2,就得到了Y坐标。通过X,Y坐标我们就可以在指定点上绘制内容了,这样的算法适用于任何需要居中显示的情况。但是如果需要垂直居中Swing的字体,我们需要小小的变通一下。



        在文章的最后可以下载到我写的例子,让我们结合例子来解释。让我们打开FontComponent类,这个类继承与JComponent,我们在paintComponent方法中来绘制我们的字体。



Rectangle clip = g2.getClipBounds() 这行代码我就可以获取到可以绘制的区域尺寸,即Container容器为FontComponent对象预留的区域。可以通过 clip.width 和 clip.height 属性来获取尺寸的长和高。



        接下来该获取需要绘制的字符串的长度了,请关注如下四行代码:


 

Font font = new Font("MS Song", Font.BOLD, 24); 

 
 
         g2.setFont(font); 

 
 
 FontMetrics fm = g2.getFontMetrics(font);  

 
 
 int textWidth = fm.stringWidth(text);


        我们先创建一个Font对象,这个对象决定了字体的类型,样式和大小。然后将font对象设置给Graphics2D对象,这样我们就能通过 getFontMetrics方法获取到一个 FontMetrics对象,通过它可以计算出在指定字体下,字符串被绘制出来的长度。有了外面控件的长度,有了显示内容的长度,我们可以通过上面提到的算法计算出 X 坐标:int x = (clip.width - textWidth) / 2;




        下面该计算 Y 坐标了,如果绘制的内容是一张图片,那么使用上面的算法就足够了,但是Swing绘制字体的机制比较特别,需要我们稍微调整一下。Swing(确切的说应该是Java2D)在绘制每一行字体的时候,以一条基线为标准来绘制。这样无论字体大小,样式,类型都可以确保在一条直线上。在基线上面的高度叫Ascent,在基线下面的部分叫Descent,如下图:









        所以我们要想获取内容的高度,只要将Ascent高度和Descent的高度相加即可。那么计算 Y 的坐标算法如下:


int ascent = fm.getAscent(); 

 
  int descent = fm.getDescent(); 

 
  int y = (clip.height - (ascent + descent)) / 2 + ascent;


        你可能对最后一行感到疑惑:为什么最后需要加上ascent?别忘了,Java2D绘制字体是从基线开始绘制,我们要做的是,首先是将内容放在垂直居中的位置,然后将 Y 坐标定位到基线的位置,好让Java2D从这里开始绘制。



        FontTest例子 下载