先看看對比圖片
上面的是普通字型,下面的是消除鋸齒字型,多少還是有點區別的
設定方法很簡單:
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; }}