自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

探秘JDK 7之三:JLayer裝飾Swing組件

開發(fā) 后端
探秘JDK 7:JLayer裝飾Swing組件。本文為探秘JDK 7系列的第三篇,前兩篇分別是“探秘JDK 7:將會(huì)出現(xiàn)新的語言特性”和“探秘JDK 7之二:半透明和任意形狀的窗口”。

51CTO在給各位介紹過“探秘JDK 7”和“再探JDK 7”之后,今天我們?cè)俅巫呱咸矫豃DK 7之旅。本文將為大家介紹JDK 7引入了一個(gè)新的Swing組件來裝飾其它Swing組件,這個(gè)新的組件是通過javax.swing.JLayer類,基于Swing實(shí)驗(yàn)室項(xiàng)目Swing Helper的JXLayer實(shí)現(xiàn)的。JLayer結(jié)合javax.swing.plaf.LayerUI使用可以實(shí)現(xiàn)高級(jí)的繪制效果,并可以在它的邊界范圍內(nèi)接收由java.awt.AWTEvents產(chǎn)生的所有通知。

JLayer和LayerUI概述

根據(jù)JDK的文檔描述,JLayer委托處理LayerUI對(duì)象的繪制和輸入事件,LayerUI負(fù)責(zé)裝飾,你可以使用這些類修改現(xiàn)有組件的外觀和行為使它們的裝飾效果更好。

實(shí)際上,你可以自己動(dòng)手?jǐn)U展LayerUI,廢除它們自帶的方法,自己定制繪制和事件處理方法,然后將這個(gè)類的實(shí)例和裝飾后的組件一道,傳遞給下面的JLayer構(gòu)造器:
public JLayer(V view,LayerUI<V> ui)

第一個(gè)參數(shù)可以是任何類的延伸java.awt.Component,表示你要裝飾的Swing組件,這個(gè)組件可以是一個(gè)JPanel或其它容器,這個(gè)容器和它里面所有的組件都將被裝飾,第二個(gè)參數(shù)代表裝飾器。使用這些構(gòu)造器創(chuàng)建JLayer時(shí),可以延遲指定LayerUI實(shí)例和/或視圖。

如果初始化時(shí)不指定視圖,之后你可以調(diào)用JLayer's public void setView(V view)方法來提供一個(gè)視圖,這個(gè)類也提供了一個(gè)public V getView()方法返回組件是否被裝飾,沒有裝飾就返回null。

如果初始化時(shí)不指定LayerUI實(shí)例,之后你可以調(diào)用JLayer's public void setUI(LayerUI ui方法提供一個(gè)實(shí)例,這個(gè)類也提供了一個(gè)public LayerUI getUI()方法返回當(dāng)前的裝飾器,沒有裝飾器就返回null。

JLayer自定義繪制

為了演示JLayer的自定義繪制特性,我創(chuàng)建了一個(gè)ReverseText程序,其代碼顯示在清單1中,當(dāng)按下按鈕時(shí),輸入到textfield中的文本將全部顛倒,這個(gè)程序使用JLayer在用戶界面后繪制了一個(gè)墻紙圖案。

清單1. ReverseText.java

  1. // ReverseText.java  
  2. import java.awt.Color;  
  3. import java.awt.EventQueue;  
  4. import java.awt.GradientPaint;  
  5. import java.awt.Graphics;  
  6. import java.awt.Graphics2D;  
  7. import java.awt.event.ActionEvent;  
  8. import java.awt.event.ActionListener;  
  9. import javax.swing.JButton;  
  10. import javax.swing.JComponent;  
  11. import javax.swing.JFrame;  
  12. import javax.swing.JLabel;  
  13. import javax.swing.JLayer;  
  14. import javax.swing.JPanel;  
  15. import javax.swing.JTextField;  
  16. import javax.swing.plaf.LayerUI;  
  17. public class ReverseText  
  18. {  
  19.    private static Color PALE_YELLOW = new Color (1.0f,1.0f,0.0f,0.2f);  
  20.    private static Color PALE_GREEN = new Color (0.0f,1.0f,0.0f,0.2f);  
  21.    private static JLayer<JPanel> createLayer ()  
  22.    {  
  23.       LayerUI<JPanel> layerUI;  
  24.       layerUI = new LayerUI<JPanel> ()  
  25.       {  
  26.          public void paint (Graphics g,JComponent c)  
  27.          {  
  28.             // Paint the wallpaper.  
  29.             Graphics2D g2 = (Graphics2D) g;  
  30.             g2.setPaint (new GradientPaint (0,0,PALE_YELLOW,  
  31.                                             5,0,PALE_GREEN,true));  
  32.             g2.fillRect (0,0,c.getWidth (),c.getHeight ());  
  33.             // Make sure that layer's panel view is not opaque.  
  34.             JLayer l = (JLayer) c;  
  35.             if (l.getView ().isOpaque ())  
  36.                 ((JPanel) l.getView ()).setOpaque (false);  
  37.             // Paint the view minus its background.  
  38.             super.paint (g,c);  
  39.          }  
  40.       };  
  41.       // Create a user interface to be decorated.  
  42.       JPanel pnl = new JPanel ();  
  43.       JLabel lblName = new JLabel ("Name:");  
  44.       pnl.add (lblName);  
  45.       final JTextField txtName = new JTextField (20);  
  46.       pnl.add (txtName);  
  47.       JButton btnReverse = new JButton ("Reverse");  
  48.       pnl.add (btnReverse);  
  49.       ActionListener al;  
  50.       al = new ActionListener ()  
  51.            {  
  52.                public void actionPerformed (ActionEvent ae)  
  53.                {  
  54.                   String txt = txtName.getText ();  
  55.                   txt = new StringBuffer (txt).reverse ().toString ();  
  56.                   txtName.setText (txt);  
  57.                }  
  58.            };  
  59.       btnReverse.addActionListener (al);  
  60.       // Create the layer for the panel using our custom layerUI.  
  61.       return new JLayer<JPanel> (pnl,layerUI);  
  62.    }  
  63.    private static void createAndShowUI ()  
  64.    {  
  65.       JFrame frame = new JFrame ("Reverse Text");  
  66.       frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);  
  67.       frame.add (createLayer ());  
  68.       frame.pack ();  
  69.       frame.setLocationRelativeTo (null);  
  70.       frame.setVisible (true);  
  71.    }  
  72.    public static void main (String [] args)  
  73.    {  
  74.       Runnable r = new Runnable ()  
  75.                    {  
  76.                        public void run ()  
  77.                        {  
  78.                           createAndShowUI ();  
  79.                        }  
  80.                    };  
  81.       EventQueue.invokeLater (r);  
  82.    }  

#p#

其中createLayer()方法是最重要的代碼,它創(chuàng)建了一個(gè)匿名LayerUI子類的實(shí)例,繪制了墻紙和JPanel視圖,創(chuàng)建了UI,在實(shí)例中包含了UI的面板容器。

繪制操作是由LayerUI's public void paint(Graphics g,JComponent c)方法實(shí)現(xiàn)的,第二個(gè)參數(shù)引用了視圖(被裝飾的組件)中的JLayer實(shí)例,不是引用的視圖。

在視圖后創(chuàng)建了漸變渲染墻紙后,調(diào)用paint()方法確保視圖(沒有嵌套面板的單一面板)是透明的,它將會(huì)隱藏墻紙,然后繪制視圖。

paint()對(duì)比paintLayer()

JDK文檔中除了提到paint()方法外,還提到了paintLayer()方法,我這里之所以選擇paint()方法,是因?yàn)長(zhǎng)ayerUI中不存在paintLayer(),此外,文檔還錯(cuò)誤地引用paintLayer() doesn't exist in LayerUI. Furthermore,the documentation incorrectly refers to addPropertyChange(),configureGraphics(),processComponentEvent(),processFocusEvent(),processHierarchyBoundsEvent(),processHierarchyEvent(),processKeyEvent(),processMouseEvent(),processMouseMotionEvent(),processMouseWheelEvent(),and repaintLayer()這些在LayerUI中根本不存在的方法,當(dāng)然這些方法也可能在JDK 7最終發(fā)布時(shí)會(huì)包含進(jìn)來。

圖1顯示了有墻紙背景的UI。

顯示了有墻紙背景的UI
圖1 在用戶界面后加了一層墻紙背景

ReverseText程序演示了自定義繪制,避開了事件觸發(fā),不需要檢測(cè)事件,因?yàn)槌绦蛑魂P(guān)心墻紙的繪制效果。相反,清單2顯示了一個(gè)需要響應(yīng)鼠標(biāo)移動(dòng)事件的程序代碼。

清單2. BrandedUI.java

  1. // BrandedUI.java  
  2. import java.awt.AWTEvent;  
  3. import java.awt.Color;  
  4. import java.awt.Component;  
  5. import java.awt.EventQueue;  
  6. import java.awt.Font;  
  7. import java.awt.GradientPaint;  
  8. import java.awt.Graphics;  
  9. import java.awt.Graphics2D;  
  10. import java.awt.GridLayout;  
  11. import java.awt.Point;  
  12. import java.awt.event.MouseEvent;  
  13. import javax.swing.JComponent;  
  14. import javax.swing.JFrame;  
  15. import javax.swing.JLabel;  
  16. import javax.swing.JLayer;  
  17. import javax.swing.JPanel;  
  18. import javax.swing.JTextField;  
  19. import javax.swing.SwingUtilities;  
  20. import javax.swing.plaf.LayerUI;  
  21. public class BrandedUI  
  22. {  
  23.    private static Color PALE_BLUE = new Color (0.0f, 0.0f, 1.0f, 0.3f);  
  24.    private static Color PALE_RED = new Color (1.0f, 0.0f, 0.0f, 0.3f);  
  25.    private static Font BRAND_FONT = new Font ("Arial", Font.BOLD, 18);  
  26.    private static String MSG = "My brand";  
  27.    private static JLayer<JPanel> createLayer ()  
  28.    {  
  29.       LayerUI<JPanel> layerUI;  
  30.       layerUI = new LayerUI<JPanel> ()  
  31.       {  
  32.          private Color color = PALE_BLUE;  
  33.          public void installUI (JComponent c)  
  34.          {  
  35.             super.installUI (c);  
  36.             ((JLayer) c).setLayerEventMask (AWTEvent.MOUSE_MOTION_EVENT_MASK);  
  37.          }  
  38.          public void eventDispatched (AWTEvent e,  
  39.                                       JLayer <? extends JPanel> l)  
  40.          {  
  41.             MouseEvent me = (MouseEvent) e;  
  42.             Point pt = SwingUtilities.convertPoint ((Component) me.getSource (),  
  43.                                                     me.getX (), me.getY (), l);  
  44.             int cx = l.getWidth ()/2;  
  45.             int cy = l.getHeight ()/2;  
  46.             if (pt.x > cx-45 && pt.x < cx+45 && pt.y > cy-10 && pt.y < cy+10)  
  47.                 color = PALE_RED;  
  48.             else  
  49.                 color = PALE_BLUE;  
  50.             l.repaint ();  
  51.          }  
  52.          public void paint (Graphics g, JComponent c)  
  53.          {  
  54.             // Paint the view.  
  55.             super.paint (g, c);  
  56.             // Paint the brand.  
  57.             g.setColor (color);  
  58.             g.setFont (BRAND_FONT);  
  59.             int width = g.getFontMetrics ().stringWidth (MSG);  
  60.             int height = g.getFontMetrics ().getHeight ();  
  61.             g.drawString (MSG, (c.getWidth ()-width)/2,  
  62.                           c.getHeight ()/2+height/4);  
  63.          }  
  64.          public void uninstallUI (JComponent c)  
  65.          {  
  66.             super.uninstallUI (c);  
  67.             ((JLayer) c).setLayerEventMask (0);  
  68.          }  
  69.       };  
  70.       // Create a user interface to be decorated.  
  71.       JPanel pnlMain = new JPanel ();  
  72.       pnlMain.setLayout (new GridLayout (2, 1));  
  73.       JPanel pnlTemp = new JPanel ();  
  74.       JLabel lblName = new JLabel ("Name:");  
  75.       pnlTemp.add (lblName);  
  76.       JTextField txtName = new JTextField (20);  
  77.       pnlTemp.add (txtName);  
  78.       pnlMain.add (pnlTemp);  
  79.       pnlTemp = new JPanel ();  
  80.       JLabel lblAddr = new JLabel ("Address:");  
  81.       pnlTemp.add (lblAddr);  
  82.       JTextField txtAddr = new JTextField (20);  
  83.       pnlTemp.add (txtAddr);  
  84.       pnlMain.add (pnlTemp);  
  85.       // Create the layer for the main panel using our custom layerUI.  
  86.       return new JLayer<JPanel> (pnlMain, layerUI);  
  87.    }  
  88.    private static void createAndShowUI ()  
  89.    {  
  90.       JFrame frame = new JFrame ("Branded UI");  
  91.       frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);  
  92.       frame.add (createLayer ());  
  93.       frame.pack ();  
  94.       frame.setLocationRelativeTo (null);  
  95.       frame.setVisible (true);  
  96.    }  
  97.    public static void main (String [] args)  
  98.    {  
  99.       Runnable r = new Runnable ()  
  100.                    {  
  101.                        public void run ()  
  102.                        {  
  103.                           createAndShowUI ();  
  104.                        }  
  105.                    };  
  106.       EventQueue.invokeLater (r);  
  107.    }  
  108. }  
  109.  

上面的代碼渲染UI上的文本印記,我們通常使用印記提醒用戶使用的是試用軟件,印記文本是半透明的,以便背景可以全部顯示,我們不希望這個(gè)印記給用戶造成太大的干擾。

另一方面,我們希望用戶能注意到這個(gè)印記,讓他們下定決心購(gòu)買這款軟件,清單2中的代碼通過改變印記的顏色(改成淡紅色)來達(dá)到這個(gè)目的,當(dāng)鼠標(biāo)移到初始值是綠色的印記面板上時(shí),顏色就變成淡紅色。

#p#

事件檢測(cè)

JLayer和LayerUI結(jié)合起來可以檢測(cè)視圖任意區(qū)域上發(fā)生的事件(包括嵌套的子組件),這些類共同提供了4個(gè)方法來檢測(cè)事件。

· public void setLayerEventMask(long layerEventMask)

調(diào)用這個(gè)JLayer方法時(shí)必須使用位掩碼AWTEvent常量選擇它檢測(cè)到的事件類型,如:setLayerEventMask (AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);可以檢測(cè)到按鍵和焦點(diǎn)改變事件。

◆public void installUI(JComponent c)

這個(gè)LayerUI方法通常放在setLayerEventMask()方法之前,這個(gè)方法類的代碼首先調(diào)用超類方法(super.installUI (c);),然后是引用JLayer的JComponent參數(shù),最后使用setLayerEventMask(): ((JLayer) c).setLayerEventMask(AWTEvent.KEY_EVENT_MASK);返回的結(jié)果。

◆public void uninstallUI(JComponent c)

這個(gè)LayerUI方法放在沒有參數(shù)的setLayerEventMask()方法后,這個(gè)方法內(nèi)的代碼首先調(diào)用超類方法(super.uninstallUI (c);),然后是引用JLayer的JComponent參數(shù),最后使用setLayerEventMask(): ((JLayer) c).setLayerEventMask(0);返回的結(jié)果。

◆public void eventDispatched(AWTEvent e, Jlayer l)

只要前面注冊(cè)的事件發(fā)生了,就會(huì)調(diào)用這個(gè)LayerUI方法,在這個(gè)方法中插入的代碼負(fù)責(zé)響應(yīng)事件,并恰當(dāng)?shù)馗聦?,更新了不同的繪制屬性(如顏色)后,通過傳遞給這個(gè)方法的JLayer參數(shù)調(diào)用repaint()方法重新繪制視圖。

在清單2中,LayerUI的installUI()方法調(diào)用setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK)檢測(cè)鼠標(biāo)移動(dòng)事件,它又調(diào)用eventDispatched()方法返回結(jié)果。

這個(gè)方法首先調(diào)用javax.swing.SwingUtilities類的convertPoint()方法確定鼠標(biāo)移動(dòng)事件相對(duì)于層的坐標(biāo)位置。

接下來這個(gè)方法通過檢查它的坐標(biāo)是否落在圍繞UI中心的一個(gè)矩形區(qū)域內(nèi),檢測(cè)鼠標(biāo)指針是否移到印記文本上方,如果坐標(biāo)剛好落在這個(gè)矩形區(qū)域內(nèi),印記文本的顏色就變?yōu)榈t色,除此以外,印記文本的顏色就恢復(fù)為藍(lán)色。

圖2顯示了鼠標(biāo)移到印記文本上方前后的顏色變化。

顯示了鼠標(biāo)移到印記文本上方前后的顏色變化
圖2 鼠標(biāo)指針移到文本上方時(shí),重新繪制文本顏色給用戶一個(gè)不刺眼的提示

小結(jié)

JLayer對(duì)自定義繪制和事件檢測(cè)的支持讓你可以改進(jìn)UI的各個(gè)組件,你可以將這個(gè)Swing組件和半透明及任意形狀窗口特性結(jié)合起來使用,讓你可以設(shè)計(jì)出更有趣的用戶界面。

【編輯推薦】

  1. 探秘JDK 7之二:半透明和任意形狀的窗口
  2. 探秘JDK 7:將會(huì)出現(xiàn)新的語言特性
  3. 我們真的能沒有Java嗎?
  4. 探秘Java 7:JVM動(dòng)態(tài)語言支持詳解
  5. 探秘Java 7新增垃圾回收器G1特性
責(zé)任編輯:佚名 來源: IT168
相關(guān)推薦

2012-03-14 11:08:32

JavaJLayer

2011-07-29 09:31:32

JDK 7

2011-05-20 09:43:23

JDK7

2011-05-20 09:35:22

JDK7

2011-05-20 10:28:29

JDK7

2010-06-22 11:07:42

JDK 7Java開發(fā)Java

2011-05-20 09:53:00

JDK7

2011-05-20 10:15:06

JDK7

2010-06-23 09:25:50

JDK 7Java開發(fā)Java

2011-05-20 10:20:11

JDK7

2009-07-10 18:06:59

JTree Swing

2009-07-17 12:54:13

2022-03-14 15:36:34

Row容器組件Column容器組件鴻蒙

2009-07-15 13:06:38

Swing組件

2009-07-10 17:03:17

AWT組件Swing組件

2009-07-10 16:29:32

Swing組件

2009-07-14 18:05:28

輕量級(jí)Swing組件

2009-07-17 14:38:51

輕量級(jí)Swing組件

2011-05-20 09:59:42

JDK7

2010-06-29 09:23:09

JDK 7I|ONIO.2
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)