Java JButton悬停效果动画。通过鼠标侦听器更改不透明度

Java JButton悬停效果动画。通过鼠标侦听器更改不透明度,java,swing,animation,jbutton,rollover,Java,Swing,Animation,Jbutton,Rollover,我想做一个过渡效果很好的JButton。我编写了一个类,该类通过JButton进行扩展,并向其中添加自定义MouseAdapter。它几乎可以工作,但如果不透明度为0,我的单缓冲图像不会消失 这里是我所有的源代码: public class ImageHoverButton extends JButton { public class MouseListener extends MouseAdapter { public void mouseExited(M

我想做一个过渡效果很好的JButton。我编写了一个类,该类通过JButton进行扩展,并向其中添加自定义MouseAdapter。它几乎可以工作,但如果不透明度为0,我的单缓冲图像不会消失

这里是我所有的源代码:

public class ImageHoverButton extends JButton {

    public class MouseListener extends MouseAdapter
      {
        public void mouseExited(MouseEvent me)
        {
          new Thread(new Runnable()
          {
            public void run()
            {
              for (float i = 1f; i >= 0f; i -= .03f)
              {
                setOpacity(i);
                try
                {
                  Thread.sleep(10);
                }
                catch (Exception e)
                {
                }
              }
            }
          }).start();
        }

        public void mouseEntered(MouseEvent me)
        {
          new Thread(new Runnable()
          {
            public void run()
            {
              for (float i = 0f; i <= 1f; i += .03f)
              {
                  setOpacity(i);
                try
                {
                  Thread.sleep(10);
                }
                catch (Exception e)
                {
                }
              }
            }
          }).start();
        }

        public void mousePressed(MouseEvent me)
        {
          new Thread(new Runnable()
          {
            public void run()
            {
              for (float i = 1f; i >= 0.6f; i -= .1f)
              {
                  setOpacity(i);
                try
                {
                  Thread.sleep(1);
                }
                catch (Exception e)
                {
                }
              }
            }
          }).start();
        }
      }


    private static final long serialVersionUID = 1L;

    private BufferedImage imgBottom;
    private BufferedImage imgHover;
    private BufferedImage imgHoverRGB;

    // filter to imgInActive
    float[] scales = { 1f, 1f, 1f, 0f};
    float[] offsets = new float[4];
    RescaleOp rop = new RescaleOp(scales, offsets, null);

    /**
     * Constructor for image path 
     * @param img
     * @param x
     * @param y
     */

    public ImageHoverButton(String imgBottomPath, String imgHoverPath, int x, int y) {

        try {
            this.imgBottom = ImageIO.read(new File(imgBottomPath));
            this.imgHover = ImageIO.read(new File(imgHoverPath));


            imgHoverRGB = new BufferedImage(imgHover.getWidth(null), 
                                            imgHover.getHeight(null), 
                                            BufferedImage.TYPE_INT_ARGB);
            Graphics g = imgHoverRGB.getGraphics();
            g.drawImage(imgHover, 0, 0, null);

        } catch (IOException e) {
        } 
        this.setBounds(x, y, imgBottom.getWidth() + 40 , imgBottom.getHeight() + 50);
        addMouseListener(new MouseListener());
        setOpacity(0f);
        setOpaque(false);
        setBorderPainted(false);
        setRolloverEnabled(false);
        setCursor(new Cursor(Cursor.HAND_CURSOR));
        setLayout(null);



    }

    public void setOpacity(float opacity) {
        scales[3] = opacity;
        rop = new RescaleOp(scales, offsets, null);
        repaint();
    }

     public void paint(Graphics g) {
            Graphics2D g2d = (Graphics2D)g;
            g2d.drawImage(imgBottom, 50, 50, null);
            g2d.drawImage(imgHoverRGB, rop, 0, 0);
     }

}
public类ImageHoverButton扩展了JButton{
公共类MouseListener扩展了MouseAdapter
{
public void mouseexitted(MouseEvent me)
{
新线程(newrunnable())
{
公开募捐
{
对于(浮点i=1f;i>=0f;i-=0.03f)
{
不透明度(i);
尝试
{
睡眠(10);
}
捕获(例外e)
{
}
}
}
}).start();
}
公共无效mouseenterned(MouseEvent me)
{
新线程(newrunnable())
{
公开募捐
{
用于(浮动i=0f;i=0.6f;i-=0.1f)
{
不透明度(i);
尝试
{
睡眠(1);
}
捕获(例外e)
{
}
}
}
}).start();
}
}
私有静态最终长serialVersionUID=1L;
私有缓存映像imgBottom;
专用缓冲区映像imgHover;
专用缓冲区映像IMGHGB;
//滤波器至imgInActive
浮动[]刻度={1f,1f,1f,0f};
浮动[]偏移=新浮动[4];
重新缩放rop=新的重新缩放(缩放、偏移、空);
/**
*映像路径的构造函数
*@param img
*@param x
*@param y
*/
公共图像悬停按钮(字符串imgBottomPath、字符串imgOverPath、整数x、整数y){
试一试{
this.imgBottom=ImageIO.read(新文件(imgBottomPath));
this.imgHover=ImageIO.read(新文件(imgHoverPath));
IMGHOVERGB=新缓冲区映像(imgHover.getWidth(null),
imgHover.getHeight(null),
BuffereImage.TYPE_INT_ARGB);
Graphics g=imghgb.getGraphics();
g、 drawImage(imgHover,0,0,null);
}捕获(IOE异常){
} 
这个.setBounds(x,y,imgBottom.getWidth()+40,imgBottom.getHeight()+50);
addMouseListener(新的MouseListener());
不透明度(0f);
设置不透明(假);
(二)虚假;
setRolloverEnabled(假);
setCursor(新光标(Cursor.HAND_光标));
setLayout(空);
}
公共无效设置不透明度(浮动不透明度){
比例[3]=不透明度;
rop=新的重新缩放(缩放、偏移、空);
重新油漆();
}
公共空间涂料(图g){
Graphics2D g2d=(Graphics2D)g;
g2d.drawImage(imgBottom,50,50,null);
g2d.drawImage(imghgb,rop,0,0);
}
}

你知道如何改进吗

不要从其他线程访问Swing组件。改用摆动计时器。
请参见

我对重新缩放不太熟悉,不记得以前用过这个。但在这种情况下应用它的结果似乎有些出乎意料

作为替代,您可以考虑<代码>字母表> <代码>。为达到预期效果所需的最小修改是改变线路

g2d.drawImage(imgHoverRGB, rop, 0, 0);

但是,该代码还有几个其他问题:

  • 不要覆盖
    绘制
    。相反,请覆盖
    paintComponent
  • 不要在组件上调用
    setBounds
    (尤其不是在构造函数中)。布局应由布局管理器完成
  • 不要默默地吞下例外
  • 不要在按钮的构造函数中加载图像
  • 正确执行
    getPreferredSize
  • 不要因为鼠标移动而产生数百个线程。(快速移入移出鼠标时,将运行多个线程-其中一些线程增加不透明度,另一些线程降低不透明度)
我创建了一个示例,展示了一种可能的方法:它包含一个
OpacityAnimator
,允许在两个opacity之间进行转换,以毫秒为单位预定义延迟。当鼠标悬停该按钮时,该动画用于增加前景图像的不透明度,当鼠标离开该按钮时,该动画用于降低前景图像的不透明度

(注意,这可以进一步推广,有许多可能的“配置设置”(如转换延迟)可以公开,但这只是一个示例)

导入java.awt.AlphaComposite;
导入java.awt.Cursor;
导入java.awt.Dimension;
导入java.awt.FlowLayout;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入java.awt.image.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入javax.imageio.imageio;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.SwingUtilities;
导入javax.swing.Timer;
公共类悬停按钮测试
{
公共静态void main(字符串[]args)
{
SwingUtilities.invokeLater(新的Runnable()
{
@凌驾
公开募捐
{
尝试
{
createAndShowGUI();
}
捕获(IOE异常)
{
e、 printStackTrace();
}
}
});
}
私有静态void createAndShowGUI()引发IOException
{
JFrame f=新的JFrame();
f、 setDefaultCloseOperation(JFrame.EXIT
g2d.setComposite(AlphaComposite.getInstance(
    AlphaComposite.SRC_OVER, scales[3]));
g2d.drawImage(imgHoverRGB, 0, 0, null);
import java.awt.AlphaComposite;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class HoverButtonTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    createAndShowGUI();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        });
    }

    private static void createAndShowGUI() throws IOException
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        BufferedImage backgroundImage = loadImage("background.png");
        BufferedImage foregroundImage = loadImage("foreground.png");
        f.getContentPane().setLayout(new FlowLayout());
        f.getContentPane().add(
            new ImageHoverButton(backgroundImage, foregroundImage));

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static BufferedImage loadImage(String path) throws IOException
    {
        return convertToARGB(ImageIO.read(new File(path)));
    }

    public static BufferedImage convertToARGB(BufferedImage image)
    {
        BufferedImage newImage = new BufferedImage(image.getWidth(),
            image.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return newImage;
    }

}

class ImageHoverButton extends JButton
{
    private class MouseHoverListener extends MouseAdapter
    {
        @Override
        public void mouseExited(MouseEvent me)
        {
            opacityAnimator.changeOpacity(0.0f, 250);
        }

        @Override
        public void mouseEntered(MouseEvent me)
        {
            opacityAnimator.changeOpacity(1.0f, 1000);
        }

        @Override
        public void mousePressed(MouseEvent me)
        {
            opacityAnimator.changeOpacity(0.5f, 50);
        }
    }

    private class OpacityAnimator
    {
        private final int DELAY_MS = 10;
        private final Timer timer;

        private float targetOpacity;
        private float currentOpacity;
        private float opacityStep;

        OpacityAnimator()
        {
            timer = new Timer(DELAY_MS, new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    if (currentOpacity > targetOpacity)
                    {
                        currentOpacity += opacityStep;
                        currentOpacity = Math.max(
                            currentOpacity, targetOpacity);
                    }
                    else if (currentOpacity < targetOpacity)
                    {
                        currentOpacity += opacityStep;
                        currentOpacity = Math.min(
                            currentOpacity, targetOpacity);
                    }
                    if (currentOpacity == targetOpacity)
                    {
                        timer.stop();
                    }
                    setOpacity(currentOpacity);
                }
            });
        }

        void changeOpacity(float targetOpacity, int durationMs)
        {
            timer.stop();
            this.targetOpacity = targetOpacity;

            float delta = targetOpacity - currentOpacity;
            if (durationMs > 0)
            {
                opacityStep = (delta / durationMs) * DELAY_MS;
            }
            else
            {
                opacityStep = delta;
            }
            timer.start();
        }
    }

    private final OpacityAnimator opacityAnimator;
    private final BufferedImage backgroundImage;
    private final BufferedImage foregroundImage;
    private float opacity = 0.0f;

    public ImageHoverButton(BufferedImage backgroundImage,
        BufferedImage foregroundImage)
    {
        this.backgroundImage = backgroundImage;
        this.foregroundImage = foregroundImage;
        this.opacityAnimator = new OpacityAnimator();
        addMouseListener(new MouseHoverListener());
        setOpaque(false);
        setBorderPainted(false);
        setRolloverEnabled(false);
        setCursor(new Cursor(Cursor.HAND_CURSOR));
    }

    @Override
    public Dimension getPreferredSize()
    {
        if (super.isPreferredSizeSet())
        {
            return super.getPreferredSize();
        }
        int w = Math
            .max(backgroundImage.getWidth(), foregroundImage.getWidth());
        int h = Math.max(backgroundImage.getHeight(),
            foregroundImage.getHeight());
        return new Dimension(w, h);
    }

    public void setOpacity(float opacity)
    {
        this.opacity = opacity;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D) gr;
        g.drawImage(backgroundImage, 0, 0, null);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
            opacity));
        g.drawImage(foregroundImage, 0, 0, null);
    }
}