先看看对比图片
上面的是普通字体,下面的是抗锯齿字体,多少还是有点区别的
设置方法很简单:
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
很不幸的是,Graphics是一个短生命周期的类,因为下一次paint执行的时候,Graphics会被new,它并不是单例
当然你可以重写paintComponent方法,像这样 public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
super.paintComponent(g2);
}
这样可以很好的保证组件在画自己的时候,使用抗锯齿字体
但这样一来,你就要重写所有控件的paintComponent,也就意味着要新建所有的subclass
然后再想想别的办法,我们重新看看paint方法,所有控件都是paint方法画出来的,paint分为3个步骤paintComponent , paintBorder , paintChildren顺序执行
所以我们想重画组件是重写paintComponent方法而不是paint,当然除非你想试着重写下paint
paintChildren可能让你眼前一亮,因为调用子控件的绘制之前会调用容器的paintChildren,而且子控件的paint(g)参数是使用父控件的paintChildren(g)参数
那么把最顶层容器的paintChildren重写就可以了
是的,确实这样分析是没问题的,只是,这样只能起到一次效果
swing做过很多优化,当界面中有脏区域的时候,swing并不是刷新所有的控件,而是尽可能少的刷新控件。所以并不是每次,swing都从最顶层容器的paint方法开始执行刷新。
这样会有什么问题呢,假如你重写了顶层容器的paintChildren,那窗口显示之后,所有字体都是抗锯齿字体,这没有问题。
加入此时再动态往容器中某个位置新增一个控件,好吧,swing就刷新那一小部分需要刷新的区域,Graphics被new,而顶层容器的paint没有执行
当然有一个解决方法,不过并不是很合适,仅供学习参考吧
RepaintManager类有一个方法addDirtyRegion,用来设置屏幕的脏区域,然后那块区域会被刷新
我们可以重写addDirtyRegion方法,每当addDirtyRegion执行时,就把整个界面都加入到脏区域中,这样就会刷新整个界面,也就会执行到顶层容器的paint
当然为了这个字体做这么大的牺牲,从效率角度考虑还是不值得的,不过通过此例学习下RepaintManager也不错
上代码:
import javax.swing.RepaintManager;
import javax.swing.JComponent;
import java.awt.Container;
public class FullRepaintManager extends RepaintManager {
public void addDirtyRegion(JComponent comp, int x, int y, int w, int h) {
super.addDirtyRegion(comp,x,y,w,h);
JComponent root = getRootJComponent(comp);
// to avoid a recursive infinite loop
if(comp != root) {
super.addDirtyRegion(root,0,0,root.getWidth(),root.getHeight());
}
}
public JComponent getRootJComponent(JComponent comp) {
Container parent = comp.getParent();
if(parent instanceof JComponent) {
return getRootJComponent((JComponent)parent);
}
return comp;
}
}