2011-01-10寫於iteye的一篇文章,今遷至此,之後這裏即是三哥的大本營!
AWTUtilities.setWindowOpaque的功能在Java7中能夠經過Window.setBackground來實現,但問題依舊!如下爲原文:
java
上個週末,將三號管家更新到了V1.0.4,其實主要是修改了SwingC,管家自己只改了版本號。更新說明裏我寫的是「優化菜單字體顯示」。請你們仔細觀察下面的截圖:
字體
這張圖片是在三號管家V1.0.3中抓取的,左邊是菜單有一部分超出了主界面的範圍(那部分是全透明的,因此不能說人家不存在),右邊是菜單所有顯示在主界面區域內。很明顯,左邊菜單中字體的質量要差不少,這仍是我在繪製的時候修改了某些參數優化過的,未經參數優化的比如今看到的效果還要差不少。爲何會這樣呢?TWaver的那位刀客在他的「Swing是一把刀」系列中曾經提到過,我在這裏再說一下。能夠認爲這是JDK的一個bug,具體問題是:java.awt.Window及其子類若是使用com.sun.awt.AWTUtilities.setWindowOpaque(window, false)設爲全透明,那麼這個窗體及其下的全部子組件所顯示的字體都會變得很粗糙。既然是窗體的問題,爲何會影響到菜單呢?緣由就在於JPopupMenu顯示的區域若是未超出其父窗體的範圍,那麼它是一個輕量級的JComponent,可是一旦超出了,那這個時候顯示出來的其實是一個重量級的Window。爲了實現彈出菜單邊框半透明的模糊效果,我重寫了setVisible,若是顯示的是重量級的Window,直接使用AWTUtilities.setWindowOpaque(window, false)將其置爲全透明,因此字體質量就嚴重降低了。優化
這是個很棘手的問題,我使勁的谷歌、百度一番事後,仍一無所得。TWaver的刀客採用的解決方案是在JFrame之上放一個JDialog,而後採起一些手段使它們保持同步,因此看起來仍然是一個窗體,但我這個僅僅只是彈出菜單,若是使用這個方案感受成本過高。通過幾番研究和嘗試以後,發如今繪製字體的時候改改某些參數的默認值能夠稍稍優化一下,不至於和正常字體的效果差太多,但終究仍是有差,這也就是上面圖片中你們看到的效果。心頭之痛哪,可是沒有更好的解決方案只能如此了。this
再而後就到了2011年的某一天,靈感忽然告訴我,有個辦法或許可行,因而試之,果真沒讓老三失望。我先把代碼帖上來吧,後面再慢慢說閒話。
spa
public void paint(Graphics g) { if(!UIUtil.isTranslucencySupported() || !buffered) { super.paint(g); } else { Insets insets = this.getInsets(); int x = insets.left; int y = insets.top; int width = this.getWidth(); int height = this.getHeight(); int contentWidth = width - insets.left - insets.right; int contentHeight = height - insets.top - insets.bottom; BufferedImage image = UIUtil.getGraphicsConfiguration(this).createCompatibleImage(width, height, Transparency.TRANSLUCENT); BufferedImage contentImage = UIUtil.getGraphicsConfiguration(this).createCompatibleImage(contentWidth, contentHeight, Transparency.OPAQUE); Graphics2D g2d = image.createGraphics(); Graphics2D contentG2d = contentImage.createGraphics(); contentG2d.translate(-x, -y); super.paint(g2d); super.paint(contentG2d); g2d.dispose(); contentG2d.dispose(); g.drawImage(image, 0, 0, this); g.drawImage(contentImage, x, y, this); } }
代碼很簡單,建立了兩個BufferedImage。注意createCompatibleImage中最後一個參數,第一張圖片使用Transparency.TRANSLUCENT,這種類型的圖片能夠設置透明度,用它來繪製邊框的半透明模糊效果,爲了不復雜的計算,直接將菜單的全部內容都繪製上去,但這種類型的圖片上面顯示的字體效果依然不好,因此在中間內容部分用另一張圖片來填充,前提是這張圖片不能覆蓋掉邊框的效果,因而它的長和寬都比第一張圖片小,起始位置也跳過了邊框,這就是第二個BufferedImage,類型爲Transparency.OPAQUE(即徹底不透明,默認背景爲黑色)。在這種類型的圖片上繪製字體,效果與JComponent組件正常的字體徹底一致,最後再將這兩張圖片繪製到組件上。問題就這麼解決了,這也就是三號管家V1.0.4中的菜單效果。上面這段代碼呢,只作講解使用,你們若是要用的話可能還須要實際狀況實際繪製,可是方法就是這麼個方法,萬變不離其蹤。code