Java同时淡入和淡出两个JPanel

我有一个JPanels列表,我希望将其显示为“幻灯片放映”,其中一个JPanel淡出,列表中的下一个JPanel淡入。这是我正在摆弄的代码:

public float opacity = 0f; private Timer fadeTimer; private boolean out; public void fadeIn() { out = false; beginFade(); } public void fadeOut () { out = true; beginFade(); } private void beginFade() { fadeTimer = new javax.swing.Timer(75,this); fadeTimer.setInitialDelay(0); fadeTimer.start(); } public void actionPerformed(ActionEvent e) { if (out) { opacity -= .03; if(opacity  1) { opacity = 1; fadeTimer.stop(); fadeTimer = null; } } repaint(); } public void paintComponent(Graphics g) { ((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity)); g.setColor(getBackground()); g.fillRect(0,0,getWidth(),getHeight()); } 

问题是它有时会消失,有时则会消失,有时候转换会非常迟缓。 我更喜欢的是,在一个JPanel消失并且下一个JPanel消失之间,屏幕变白的时间只有一小部分。有人知道如何解决这个问题吗? 提前致谢。

因此,在处理这些类型的问题时,通常最好减少Timer的数量,因为每个计时器都会将多个事件发布到事件调度队列(有自己的tick更新以及重绘事件)。 所有这些活动都可能降低系统的性能。

动画也是随时间变化的错觉,为此,而不是试图从起点到终点循环,你应该决定你想要动画的运行时间并计算时间的进度并更新值因此(这更像是基于“时间轴”的动画周期)。 这有助于减少“滞后”的出现

通常我会使用Timing Framework来完成此任务,但您也可以查看Trident框架或Universal Tween Engine ,它还为Swing提供复杂的动画支持。

这个例子与它的目标紧密相关。 就个人而言,我通常会有一个“动画”对象的抽象概念,它可能只有update(float)方法,然后将其扩展为支持其他对象,但我会让你坚持下去。

另一个问题是确保组件完全透明( setOpaque(false) ),这允许我们在动画期间伪造组件的半透明度。

通常情况下,我总是鼓励你覆盖paintComponent ,但有几次这paintComponent时,这就是其中之一。 基本上,为了便于从一个组件转换到另一个组件,我们需要控制组件中所有子组件的alpha级别,这是当覆盖paint将是更好的选择。

褪色

nb:代码设置为大约25fps,但屏幕捕获软件大约以8fps的速度捕获

 import java.awt.AlphaComposite; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; 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 java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class FadeTest { public static void main(String[] args) { new FadeTest(); } public FadeTest() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } BufferedImage img1 = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\Ponies\\sillydash-small.png")); BufferedImage img2 = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\Ponies\\SmallPony.png")); AlphaPane pane1 = new AlphaPane(); pane1.add(new JLabel(new ImageIcon(img1))); pane1.setAlpha(1f); AlphaPane pane2 = new AlphaPane(); pane2.add(new JLabel(new ImageIcon(img2))); pane2.setAlpha(0f); JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 1; gbc.weightx = 1; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; frame.add(pane1, gbc); frame.add(pane2, gbc); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); MouseAdapter ma = new MouseAdapter() { private AnimationController controller; @Override public void mouseClicked(MouseEvent e) { try { if (controller != null) { controller.stop(); } controller = new AnimationController(4000); boolean fadeIn = pane1.getAlpha() < pane2.getAlpha(); controller.add(controller.new AlphaRange(pane1, fadeIn)); controller.add(controller.new AlphaRange(pane2, !fadeIn)); controller.start(); } catch (InvalidStateException ex) { ex.printStackTrace(); } } }; pane1.addMouseListener(ma); pane2.addMouseListener(ma); } catch (IOException ex) { ex.printStackTrace(); } } }); } public class AnimationController { private List animationRanges; private Timer timer; private Long startTime; private long runTime; public AnimationController(int runTime) { this.runTime = runTime; animationRanges = new ArrayList<>(25); } public void add(AlphaRange range) { animationRanges.add(range); } public void start() throws InvalidStateException { if (timer == null || !timer.isRunning()) { timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (startTime == null) { startTime = System.currentTimeMillis(); } long duration = System.currentTimeMillis() - startTime; float progress = (float) duration / (float) runTime; if (progress > 1f) { progress = 1f; stop(); } System.out.println(NumberFormat.getPercentInstance().format(progress)); for (AlphaRange range : animationRanges) { range.update(progress); } } }); timer.start(); } else { throw new InvalidStateException("Animation is running"); } } public void stop() { if (timer != null) { timer.stop(); } } public class AlphaRange { private float from; private float to; private AlphaPane alphaPane; public AlphaRange(AlphaPane alphaPane, boolean fadeIn) { this.from = alphaPane.getAlpha(); this.to = fadeIn ? 1f : 0f; this.alphaPane = alphaPane; } public float getFrom() { return from; } public float getTo() { return to; } public float getValueBasedOnProgress(float progress) { float value = 0; float distance = to - from; value = (distance * progress); value += from; return value; } public void update(float progress) { float alpha = getValueBasedOnProgress(progress); alphaPane.setAlpha(alpha); } } } public class InvalidStateException extends Exception { public InvalidStateException(String message) { super(message); } public InvalidStateException(String message, Throwable cause) { super(message, cause); } } public class AlphaPane extends JPanel { private float alpha; public AlphaPane() { setOpaque(false); } @Override public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); g2d.setComposite(AlphaComposite.SrcOver.derive(alpha)); super.paint(g2d); g2d.dispose(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Fake the background g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); } public void setAlpha(float value) { if (alpha != value) { this.alpha = Math.min(1f, Math.max(0, value)); repaint(); } } public float getAlpha() { return alpha; } } }