Java同时淡入和淡出两个JPanel

时间:2015-12-06 15:39:29

标签: java swing timer jpanel fading

我有一个JPanel列表,我希望将其显示为"幻灯片"其中一个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 < 0)
      {
        opacity = 0;
        fadeTimer.stop();
        fadeTimer = null;
      }
    }
    else
    {
      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淡入之间。有人知道我怎么能解决这个问题吗?提前谢谢。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

另一个问题是确保组件完全透明(setOpaque(false)),这样我们就可以在动画过程中伪造组件的半透明效果。

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

Fade

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<AlphaRange> 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;
        }

    }

}