Java7中的一个新的类,JLayer,也已被添加到提高的Java Swing的能力。 JLayer主要用于装饰的Swing组件。你可以用它改变如何绘制组件,以及它们如何响应事件。
下面是这个类的一个简单的例子:
先看运行结果:
1、鼠标进入登陆框时:聚光灯效果(Spotlight)
2、点击登录按钮:
- import java.awt.AWTEvent;
- import java.awt.AlphaComposite;
- import java.awt.BasicStroke;
- import java.awt.Color;
- import java.awt.Composite;
- import java.awt.Font;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.Image;
- import java.awt.Point;
- import java.awt.RadialGradientPaint;
- import java.awt.RenderingHints;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.awt.event.FocusAdapter;
- import java.awt.event.FocusEvent;
- import java.awt.event.ItemEvent;
- import java.awt.event.ItemListener;
- import java.awt.event.MouseEvent;
- import java.beans.PropertyChangeEvent;
- import javax.swing.ImageIcon;
- import javax.swing.JButton;
- import javax.swing.JCheckBox;
- import javax.swing.JComponent;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- import javax.swing.JLayer;
- import javax.swing.JPanel;
- import javax.swing.JPasswordField;
- import javax.swing.JTextField;
- import javax.swing.SwingUtilities;
- import javax.swing.Timer;
- import javax.swing.UIManager;
- import javax.swing.plaf.LayerUI;
- /**
- * @author http://blog.csdn.net/Cannel_2020
- *
- */
- public class TestJLayer {
- private static JFrame loginFrame;
- private LoginLayerUI layerUI;//LayerUI的一个子类
- public static void main(String[] args) {
- try {
- UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
- } catch (Exception e) {
- e.printStackTrace();
- }
- javax.swing.SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- new TestJLayer().createUI();
- }
- });
- }
- public void createUI() {
- loginFrame = new JFrame("From Cannel_2020's blog(CSDN)");
- loginFrame.setSize(340, 260);
- loginFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- loginFrame.setLocationRelativeTo(null);
- JPanel panel = createPanel();
- layerUI = new LoginLayerUI();
- /*
- * JLayer的构造函数:JLayer(V view, LayerUI<V> ui),
- * 第一个参数view为Component的一个子类,就是要要装饰的Swing组件
- * 第二个参数为LayerUI<V>的一个实例,指定
- */
- JLayer<JPanel> jlayer = new JLayer<JPanel>(panel, layerUI);
- //注意这个add的是JLayer<JPanel>的一个实例
- loginFrame.add(jlayer);
- loginFrame.setVisible(true);
- }
- private JPanel createPanel() {
- final Image background = new ImageIcon("image/background.jpg").getImage();//背景图片
- JPanel panel = new JPanel() {
- private static final long serialVersionUID = 6246862165441423926L;
- public void paintComponent(Graphics g) {
- super.paintComponent(g);
- Graphics2D g2d = (Graphics2D) g;
- g2d.drawImage(background, 0, 0, loginFrame.getWidth(),
- loginFrame.getHeight(), this);
- }
- };
- panel.setLayout(null);
- Font font = new Font("微软雅黑",Font.PLAIN,14);
- JLabel accountLabel = new JLabel("账号:");
- accountLabel.setFont(font);
- accountLabel.setBounds(40, 60, 40, 15);
- JLabel pswLabel = new JLabel("密码:");
- pswLabel.setFont(font);
- pswLabel.setBounds(40, 98, 40, 15);
- final JTextField userName = new JTextField();
- userName.setFont(font);
- userName.setBounds(88, 53, 155, 33);
- userName.addFocusListener(new FocusAdapter(){
- public void focusGained(FocusEvent e) {
- userName.selectAll();
- }
- });
- JPasswordField password = new JPasswordField();
- password.setBounds(88, 90, 155, 33);
- JLabel registerLabel = new JLabel("注册");
- registerLabel.setFont(font);
- registerLabel.setBounds(260, 60, 28, 19);
- JLabel findBackLabel = new JLabel("找回");
- findBackLabel.setFont(font);
- findBackLabel.setBounds(260, 98, 28, 19);
- JCheckBox rmbCBox = new JCheckBox("记住密码");
- rmbCBox.setSelected(true);
- rmbCBox.setBounds(90, 140, 77, 14);
- rmbCBox.addItemListener(new ItemListener(){
- public void itemStateChanged(ItemEvent e) {
- if(e.getStateChange() == ItemEvent.DESELECTED){
- System.out.println("rmbCBox(JCheckBox)被选中!");
- }
- }
- });
- JCheckBox autoCBox = new JCheckBox("自动登录");
- autoCBox.setBounds(175, 140, 77, 14);
- JButton setButton = new JButton("设置");
- setButton.setBounds(50, 170, 75, 27);
- JButton loginButton = new JButton("登录");
- loginButton.setFont(font);
- loginButton.setBounds(90, 170, 75, 27);
- //5秒钟后停止
- final Timer stopper = new Timer(5000, new ActionListener() {
- public void actionPerformed(ActionEvent ae) {
- layerUI.stop();
- }
- });
- stopper.setRepeats(false);//设置计时器只在第一次时触发然后停止
- loginButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent ae) {
- layerUI.start();
- //若stopper不是在运行,则启动stopper。
- if (!stopper.isRunning()) {
- stopper.start();
- }
- }
- });
- JButton exitButton = new JButton("退出");
- exitButton.setFont(font);
- exitButton.setBounds(170, 170, 75, 27);
- exitButton.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e) {
- System.exit(0);
- }
- });
- panel.add(userName);
- panel.add(password);
- panel.add(accountLabel);
- panel.add(pswLabel);
- panel.add(registerLabel);
- panel.add(findBackLabel);
- panel.add(rmbCBox);
- panel.add(autoCBox);
- panel.add(loginButton);
- panel.add(exitButton);
- return panel;
- }
- }
- class LoginLayerUI extends LayerUI<JPanel> implements ActionListener {
- private static final long serialVersionUID = 1L;
- private boolean mIsRunning = false;// 点击按钮之后所触发的线程是否在运行
- private boolean mIsFadingOut = false;//控制线程的停止,和处理
- private Timer mTimer;// 在指定时间间隔触发一个或多个 ActionEvent。
- private int mAngle = 0;//用于旋转时计算角度
- private int mFadeCount = 0;//结合mFadeLimit用于设置针形旋转图案整体的渐变的效果
- private int mFadeLimit = 30;
- private boolean mActive;// 是否进入窗口内
- private int mX, mY;// 记录鼠标的坐标
- /*
- * 渲染效果的过程中会不断调用paint
- */
- public void paint(Graphics g, JComponent c) {
- int w = c.getWidth();//获取组件c的宽度
- int h = c.getHeight();
- super.paint(g, c);//调用父类的paint方法,绘画组件c
- Graphics2D g2 = (Graphics2D) g.create();
- // 设置聚光灯(Spotlight)效果
- if (mActive) {
- // 创建径向渐变,中间透明。
- java.awt.geom.Point2D center = new java.awt.geom.Point2D.Float(mX,
- mY);
- float radius = 72;
- float[] dist = { 0.0f, 1.0f };
- Color[] colors = { new Color(0.0f, 0.0f, 0.0f, 0.0f), Color.black };
- //RadialGradientPaint 类提供使用圆形辐射颜色渐变模式填充某一形状的方式
- RadialGradientPaint p = new RadialGradientPaint(center, radius,
- dist, colors);
- //setPaint:为 Graphics2D 上下文设置 Paint 属性
- g2.setPaint(p);
- /*为 Graphics2D 上下文设置 Composite。
- *Composite 用于所有绘制方法中,如 drawImage、drawString、draw 和 fill
- *这里使用AlphaComposite 类实现一些基本的 alpha 合成规则
- *将源色与目标色组合,在图形和图像中实现混合和透明效果
- */
- g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- .6f));
- //填充是绘画
- g2.fillRect(0, 0, c.getWidth(), c.getHeight());
- }
- if (!mIsRunning) {
- return;
- }
- float fade = (float) mFadeCount / (float) mFadeLimit;
- //fade的不同形成:12根针整体刚才出现的渐变效果,和登录成功后的针消失过程的渐变效果
- g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- .5f * fade));
- g2.fillRect(0, 0, w, h);
- int s = Math.min(w, h) / 5;
- int cx = w / 2;
- int cy = h / 2;
- /* 为呈现算法设置单个首选项的值。
- * RenderingHints.KEY_ANTIALIASING:抗锯齿提示键。
- * RenderingHints.VALUE_ANTIALIAS_ON:抗锯齿提示值——使用抗锯齿模式完成呈现
- */
- g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
- /*
- * setStroke:设置呈现过程中要画的图形
- * BasicStroke 类定义针对图形图元轮廓呈现属性的一个基本集合
- */
- g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND,
- BasicStroke.JOIN_ROUND));
- //设置绘画颜色
- g2.setPaint(Color.white);
- /* rotate:旋转转换连接
- * 第一个参数 Math.PI * mAngle / 180:旋转的角度,以弧度为单位
- * 第二个参数 cx:x - 旋转原点的 x 坐标
- * 第二个参数 cy:y - 旋转原点的 y 坐标
- */
- g2.rotate(Math.PI * mAngle / 180, cx, cy);
- //12跟针,各个针的颜色是不同的,针与针之间形成渐变的效果
- for (int i = 0; i < 12; i++) {
- float scale = (11.0f - (float) i) / 11.0f;
- g2.drawLine(cx + s, cy, cx + s * 2, cy);
- g2.rotate(-Math.PI / 6, cx, cy);
- //通过设置AlphaComposite.getInstance()第二个参数的不同来实现12“针”颜色的不同
- g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- scale * fade));
- }
- //释放此图形的上下文以及它使用的所有系统资源。
- g2.dispose();
- }
- public void installUI(JComponent c) {
- super.installUI(c);
- JLayer jlayer = (JLayer) c;
- // 启动鼠标事件和鼠标移动事件
- jlayer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK
- | AWTEvent.MOUSE_MOTION_EVENT_MASK);
- }
- public void uninstallUI(JComponent c) {
- JLayer jlayer = (JLayer) c;
- jlayer.setLayerEventMask(0);
- super.uninstallUI(c);
- }
- // JLayer对象专用的鼠标事件,在installUI中启动事件,在uninstallUI中禁用事件
- protected void processMouseEvent(MouseEvent e, JLayer l) {
- if (e.getID() == MouseEvent.MOUSE_ENTERED)
- mActive = true;
- if (e.getID() == MouseEvent.MOUSE_EXITED)
- mActive = false;
- l.repaint();
- }
- // JLayer对象专用的鼠标移动事件,在installUI中启动事件,在uninstallUI中禁用事件
- // 这里把鼠标坐标记录在mX和mY中
- protected void processMouseMotionEvent(MouseEvent e, JLayer l) {
- // 确定鼠标移动事件相对于层的坐标位置。
- Point p = SwingUtilities
- .convertPoint(e.getComponent(), e.getPoint(), l);
- mX = p.x;
- mY = p.y;
- l.repaint();
- }
- public void actionPerformed(ActionEvent e) {
- if (mIsRunning) {
- //firePropertyChange():通知的内部状态的更新
- firePropertyChange("tick", 0, 1);
- mAngle += 3;
- if (mAngle >= 360) {
- mAngle = 0;
- }
- if (mIsFadingOut) {
- if (--mFadeCount == 0) {
- mIsRunning = false;
- mTimer.stop();
- }
- //防止AlphaComposite.getInstance()的第二个参数的值超出范围
- } else if (mFadeCount < mFadeLimit) {
- mFadeCount++;
- }
- }
- }
- public void start() {
- if (mIsRunning) {
- return;
- }
- mIsRunning = true;
- mIsFadingOut = false;
- mFadeCount = 0;
- int fps = 24;
- int tick = 1000 / fps;
- //每tick毫秒调用一次本类中的actionPerformed方法
- mTimer = new Timer(tick, this);
- mTimer.start();
- }
- public void stop() {
- mIsFadingOut = true;
- }
- //不断repaint()窗口
- public void applyPropertyChange(PropertyChangeEvent pce, JLayer l) {
- if ("tick".equals(pce.getPropertyName())) {
- l.repaint();
- }
- }
- }
原文链接:http://blog.csdn.net/cannel_2020/article/details/7350516
【编辑推荐】