Java 同时淡入和淡出两个 JPanel

标签 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 淡入之间,屏幕变白的那一瞬间。有谁知道我该如何解决这个问题?提前致谢。

最佳答案

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

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

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

这个示例与其目标紧密结合。就我个人而言,我通常有一个“可动画”对象的抽象概念,它可能只有 update(float) 方法,然后将其扩展以支持其他对象,但我会让你发疯吧。

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

通常,我总是鼓励您重写 paintComponent,但有时这还不够,这就是其中之一。基本上,为了促进从一个组件到另一个组件的转换,我们需要控制组件内所有子组件的 alpha 级别,此时重写 paint 将是更好的选择。

Fade

注意:代码设置为以 25 fps 左右运行,但屏幕捕获软件以大约 8 fps 捕获

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

    }

}

关于Java 同时淡入和淡出两个 JPanel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34119221/

相关文章:

Java Swing : Resizing component in JFrame without affecting other components

javascript - JQuery 动画中的 setTimeout

ruby-on-rails - Ruby on Rails 时间助手

java - spring mvc hibernate 锁定表的行

java - 将字符串转换为整数十六进制值 "Strange"行为

java - 如何处置jframe

java - setVisible() 方法在静态方法中不起作用

c - 如果回调函数的处理时间是动态的,如何使用hrtimer?

java - 如何在 android studio 中使用弹出窗口按钮打开新 Activity ?

java - 以编程方式关闭 Java 托盘气球