Java JButton悬停效果动画。通过鼠标侦听器更改不透明度
我想做一个过渡效果很好的JButton。我编写了一个类,该类通过JButton进行扩展,并向其中添加自定义MouseAdapter。它几乎可以工作,但如果不透明度为0,我的单缓冲图像不会消失 这里是我所有的源代码: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
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);
}
}