Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 499|回复: 0

[Swing学习]JDK7探秘(三):JLayerg组件

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-7 23:56:50 | 显示全部楼层 |阅读模式
    JDK 7引入了一个新的Swing组件来装饰其它Swing组件,这个新的组件是通过javax.swing.JLayer类,基于Swing实验室项目 Swing Helper的JXLayer实现的。JLayer结合javax.swing.plaf.LayerUI使用可以实现高级的绘制效果,并可以在它的边界 范围内接收由java.awt.AWTEvents产生的所有通知。本文将为大家一一介绍这些类。   JLayer和LayerUI概述  根据JDK的文档描述,JLayer委托处理LayerUI对象的绘制和输入事件,LayerUI负责装饰,你可以使用这些类修改现有组件的外观和行为使它们的装饰效果更好。  实际上,你可以自己动手扩展LayerUI,废除它们自带的方法,自己定制绘制和事件处理方法,然后将这个类的实例和装饰后的组件一道,传递给下面的JLayer构造器:
      
       
       
         
       

         
       
      


       
      
       
       
       public
        JLayer(V view,LayerUI
       <
       V
       >
        ui)
       
      
      第一个参数可以是任何类的延伸java.awt.Component,表示你要装饰的Swing组件,这个组件可以是一个JPanel或其它容器,这个 容器和它里面所有的组件都将被装饰,第二个参数代表装饰器。使用这些构造器创建JLayer时,可以延迟指定LayerUI实例和/或视图。
      如果初始化时不指定视图,之后你可以调用JLayer"s public void setView(V view)方法来提供一个视图,这个类也提供了一个public V getView()方法返回组件是否被装饰,没有装饰就返回null。
      如果初始化时不指定LayerUI实例,之后你可以调用JLayer"s public void setUI(LayerUI
       ui方法提供一个实例,这个类也提供了一个public LayerUI
       getUI()方法返回当前的装饰器,没有装饰器就返回null。
       JLayer自定义绘制
      为了演示JLayer的自定义绘制特性,我创建了一个ReverseText程序,其代码显示在清单1中,当按下按钮时,输入到textfield中的文本将全部颠倒,这个程序使用JLayer在用户界面后绘制了一个墙纸图案。
      清单1. ReverseText.java
      
       
       
       //
        ReverseText.java
       

       import
        java.awt.Color;

       import
        java.awt.EventQueue;

       import
        java.awt.GradientPaint;

       import
        java.awt.Graphics;

       import
        java.awt.Graphics2D;

       import
        java.awt.event.ActionEvent;

       import
        java.awt.event.ActionListener;

       import
        javax.swing.JButton;

       import
        javax.swing.JComponent;

       import
        javax.swing.JFrame;

       import
        javax.swing.JLabel;

       import
        javax.swing.JLayer;

       import
        javax.swing.JPanel;

       import
        javax.swing.JTextField;

       import
        javax.swing.plaf.LayerUI;

       public
       
       class
        ReverseText
    {
       
       private
       
       static
        Color PALE_YELLOW
       =
       
       new
        Color (
       1.0f
       ,
       1.0f
       ,
       0.0f
       ,
       0.2f
       );
       
       private
       
       static
        Color PALE_GREEN
       =
       
       new
        Color (
       0.0f
       ,
       1.0f
       ,
       0.0f
       ,
       0.2f
       );
       
       private
       
       static
        JLayer
       <
       JPanel
       >
        createLayer ()
        {
           LayerUI
       <
       JPanel
       >
        layerUI;
           layerUI
       =
       
       new
        LayerUI
       <
       JPanel
       >
        ()
           {
             
       public
       
       void
        paint (Graphics g,JComponent c)
              {
                
       //
        Paint the wallpaper.
       

                   Graphics2D g2
       =
        (Graphics2D) g;
                 g2.setPaint (
       new
        GradientPaint (
       0
       ,
       0
       ,PALE_YELLOW,
                                                 
       5
       ,
       0
       ,PALE_GREEN,
       true
       ));
                 g2.fillRect (
       0
       ,
       0
       ,c.getWidth (),c.getHeight ());
                
       //
        Make sure that layer"s panel view is not opaque.
       

                   JLayer l
       =
        (JLayer) c;
                
       if
        (l.getView ().isOpaque ())
                     ((JPanel) l.getView ()).setOpaque (
       false
       );
                
       //
        Paint the view minus its background.
       

                   
       super
       .paint (g,c);
              }
           };
          
       //
        Create a user interface to be decorated.
       

             JPanel pnl
       =
       
       new
        JPanel ();
           JLabel lblName
       =
       
       new
        JLabel (
       "
       Name:
       "
       );
           pnl.add (lblName);
          
       final
        JTextField txtName
       =
       
       new
        JTextField (
       20
       );
           pnl.add (txtName);
           JButton btnReverse
       =
       
       new
        JButton (
       "
       Reverse
       "
       );
           pnl.add (btnReverse);
           ActionListener al;
           al
       =
       
       new
        ActionListener ()
                {
                   
       public
       
       void
        actionPerformed (ActionEvent ae)
                    {
                       String txt
       =
        txtName.getText ();
                       txt
       =
       
       new
        StringBuffer (txt).reverse ().toString ();
                       txtName.setText (txt);
                    }
                };
           btnReverse.addActionListener (al);
          
       //
        Create the layer for the panel using our custom layerUI.
       

             
       return
       
       new
        JLayer
       <
       JPanel
       >
        (pnl,layerUI);
        }
       
       private
       
       static
       
       void
        createAndShowUI ()
        {
           JFrame frame
       =
       
       new
        JFrame (
       "
       Reverse Text
       "
       );
           frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
           frame.add (createLayer ());
           frame.pack ();
           frame.setLocationRelativeTo (
       null
       );
           frame.setVisible (
       true
       );
        }
       
       public
       
       static
       
       void
        main (String [] args)
        {
           Runnable r
       =
       
       new
        Runnable ()
                        {
                            
       public
       
       void
        run ()
                            {
                               createAndShowUI ();
                            }
                        };
           EventQueue.invokeLater (r);
        }
    }
       
      


      其中createLayer()方法是最重要的代码,它创建了一个匿名LayerUI子类的实例,绘制了墙纸和JPanel视图,创建了UI,在实例中包含了UI的面板容器。
      绘制操作是由LayerUI"s public void paint(Graphics g,JComponent c)方法实现的,第二个参数引用了视图(被装饰的组件)中的JLayer实例,不是引用的视图。
      在视图后创建了渐变渲染墙纸后,调用paint()方法确保视图(没有嵌套面板的单一面板)是透明的,它将会隐藏墙纸,然后绘制视图。
      paint()对比paintLayer()
      JDK文档中除了提到paint()方法外,还提到了paintLayer()方法,我这里之所以选择paint()方法,是因为LayerUI中不存 在paintLayer(),此外,文档还错误地引用了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中根本不存在的方法,当然这些方法也可能在JDK 7最终发布时会包含进来。
      图1显示了有墙纸背景的UI。
      
    图 1 在用户界面后加了一层墙纸背景
      ReverseText程序演示了自定义绘制,避开了事件触发,不需要检测事件,因为程序只关心墙纸的绘制效果。相反,清单2显示了一个需要响应鼠标移动事件的程序代码。
      清单2. BrandedUI.java
      
       
       
       //
        BrandedUI.java
       

       import
        java.awt.AWTEvent;

       import
        java.awt.Color;

       import
        java.awt.Component;

       import
        java.awt.EventQueue;

       import
        java.awt.Font;

       import
        java.awt.GradientPaint;

       import
        java.awt.Graphics;

       import
        java.awt.Graphics2D;

       import
        java.awt.GridLayout;

       import
        java.awt.Point;

       import
        java.awt.event.MouseEvent;

       import
        javax.swing.JComponent;

       import
        javax.swing.JFrame;

       import
        javax.swing.JLabel;

       import
        javax.swing.JLayer;

       import
        javax.swing.JPanel;

       import
        javax.swing.JTextField;

       import
        javax.swing.SwingUtilities;

       import
        javax.swing.plaf.LayerUI;

       public
       
       class
        BrandedUI
    {
       
       private
       
       static
        Color PALE_BLUE
       =
       
       new
        Color (
       0.0f
       ,
       0.0f
       ,
       1.0f
       ,
       0.3f
       );
       
       private
       
       static
        Color PALE_RED
       =
       
       new
        Color (
       1.0f
       ,
       0.0f
       ,
       0.0f
       ,
       0.3f
       );
       
       private
       
       static
        Font BRAND_FONT
       =
       
       new
        Font (
       "
       Arial
       "
       , Font.BOLD,
       18
       );
       
       private
       
       static
        String MSG
       =
       
       "
       My brand
       "
       ;
       
       private
       
       static
        JLayer
       <
       JPanel
       >
        createLayer ()
        {
           LayerUI
       <
       JPanel
       >
        layerUI;
           layerUI
       =
       
       new
        LayerUI
       <
       JPanel
       >
        ()
           {
             
       private
        Color color
       =
        PALE_BLUE;
             
       public
       
       void
        installUI (JComponent c)
              {
                
       super
       .installUI (c);
                 ((JLayer) c).setLayerEventMask (AWTEvent.MOUSE_MOTION_EVENT_MASK);
              }
             
       public
       
       void
        eventDispatched (AWTEvent e,
                                           JLayer
       <?
       
       extends
        JPanel
       >
        l)
              {
                 MouseEvent me
       =
        (MouseEvent) e;
                 Point pt
       =
        SwingUtilities.convertPoint ((Component) me.getSource (),
                                                         me.getX (), me.getY (), l);
                
       int
        cx
       =
        l.getWidth ()
       /
       2
       ;
                
       int
        cy
       =
        l.getHeight ()
       /
       2
       ;
                
       if
        (pt.x
       >
        cx
       -
       45
       
       &&
        pt.x
       <
        cx
       +
       45
       
       &&
        pt.y
       >
        cy
       -
       10
       
       &&
        pt.y
       <
        cy
       +
       10
       )
                     color
       =
        PALE_RED;
                
       else
       
                     color
       =
        PALE_BLUE;
                 l.repaint ();
              }
             
       public
       
       void
        paint (Graphics g, JComponent c)
              {
                
       //
        Paint the view.
       

                   
       super
       .paint (g, c);
                
       //
        Paint the brand.
       

                   g.setColor (color);
                 g.setFont (BRAND_FONT);
                
       int
        width
       =
        g.getFontMetrics ().stringWidth (MSG);
                
       int
        height
       =
        g.getFontMetrics ().getHeight ();
                 g.drawString (MSG, (c.getWidth ()
       -
       width)
       /
       2
       ,
                               c.getHeight ()
       /
       2
       +
       height
       /
       4
       );
              }
             
       public
       
       void
        uninstallUI (JComponent c)
              {
                
       super
       .uninstallUI (c);
                 ((JLayer) c).setLayerEventMask (
       0
       );
              }
           };
          
       //
        Create a user interface to be decorated.
       

             JPanel pnlMain
       =
       
       new
        JPanel ();
           pnlMain.setLayout (
       new
        GridLayout (
       2
       ,
       1
       ));
           JPanel pnlTemp
       =
       
       new
        JPanel ();
           JLabel lblName
       =
       
       new
        JLabel (
       "
       Name:
       "
       );
           pnlTemp.add (lblName);
           JTextField txtName
       =
       
       new
        JTextField (
       20
       );
           pnlTemp.add (txtName);
           pnlMain.add (pnlTemp);
           pnlTemp
       =
       
       new
        JPanel ();
           JLabel lblAddr
       =
       
       new
        JLabel (
       "
       Address:
       "
       );
           pnlTemp.add (lblAddr);
           JTextField txtAddr
       =
       
       new
        JTextField (
       20
       );
           pnlTemp.add (txtAddr);
           pnlMain.add (pnlTemp);
          
       //
        Create the layer for the main panel using our custom layerUI.
       

             
       return
       
       new
        JLayer
       <
       JPanel
       >
        (pnlMain, layerUI);
        }
       
       private
       
       static
       
       void
        createAndShowUI ()
        {
           JFrame frame
       =
       
       new
        JFrame (
       "
       Branded UI
       "
       );
           frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
           frame.add (createLayer ());
           frame.pack ();
           frame.setLocationRelativeTo (
       null
       );
           frame.setVisible (
       true
       );
        }
       
       public
       
       static
       
       void
        main (String [] args)
        {
           Runnable r
       =
       
       new
        Runnable ()
                        {
                            
       public
       
       void
        run ()
                            {
                               createAndShowUI ();
                            }
                        };
           EventQueue.invokeLater (r);
        }
    }
       
      
      上面的代码渲染UI上的文本印记,我们通常使用印记提醒用户使用的是试用软件,印记文本是半透明的,以便背景可以全部显示,我们不希望这个印记给用户造成太大的干扰。
      另一方面,我们希望用户能注意到这个印记,让他们下定决心购买这款软件,清单2中的代码通过改变印记的颜色(改成淡红色)来达到这个目的,当鼠标移到初始值是绿色的印记面板上时,颜色就变成淡红色。  


    事件检测
      JLayer和LayerUI结合起来可以检测视图任意区域上发生的事件(包括嵌套的子组件),这些类共同提供了4个方法来检测事件。
      ・ public void setLayerEventMask(long layerEventMask)
      调用这个JLayer方法时必须使用位掩码AWTEvent常量选择它检测到的事件类型,如:setLayerEventMask (AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);可以检测到按键和焦点改变事件。
      ・ public void installUI(JComponent c)
      这个LayerUI方法通常放在setLayerEventMask()方法之前,这个方法类的代码首先调用超类方法(super.installUI (c);),然后是引用JLayer的JComponent参数,最后使用setLayerEventMask(): ((JLayer) c).setLayerEventMask(AWTEvent.KEY_EVENT_MASK);返回的结果。
      ・ public void uninstallUI(JComponent c)
      这个LayerUI方法放在没有参数的setLayerEventMask()方法后,这个方法内的代码首先调用超类方法 (super.uninstallUI (c);),然后是引用JLayer的JComponent参数,最后使用setLayerEventMask(): ((JLayer) c).setLayerEventMask(0);返回的结果。
      ・ public void eventDispatched(AWTEvent e, Jlayer
       l)
      只要前面注册的事件发生了,就会调用这个LayerUI方法,在这个方法中插入的代码负责响应事件,并恰当地更新层,更新了不同的绘制属性(如颜色)后,通过传递给这个方法的JLayer参数调用repaint()方法重新绘制视图。
      在清单2中,LayerUI的installUI()方法调用setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK)检测鼠标移动事件,它又调用eventDispatched()方法返回结果。
      这个方法首先调用javax.swing.SwingUtilities类的convertPoint()方法确定鼠标移动事件相对于层的坐标位置。
      接下来这个方法通过检查它的坐标是否落在围绕UI中心的一个矩形区域内,检测鼠标指针是否移到印记文本上方,如果坐标刚好落在这个矩形区域内,印记文本的颜色就变为淡红色,除此以外,印记文本的颜色就恢复为蓝色。
      图2显示了鼠标移到印记文本上方前后的颜色变化。
      
    图 2 鼠标指针移到文本上方时,重新绘制文本颜色给用户一个不刺眼的提示
    小结
      JLayer对自定义绘制和事件检测的支持让你可以改进UI的各个组件,你可以将这个Swing组件和半透明及任意形状窗口特性结合起来使用,让你可以设计出更有趣的用户界面。下一篇文章将带来NIO.2的介绍,敬请期待!




      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/11/7/235649968.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 10:40 , Processed in 0.349706 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表