简体   繁体   English

Java同时淡入和淡出两个JPanels

[英]Java Fade In and Out two JPanels at the same time

I have a list of JPanels that I want to display as a "slideshow" where one JPanel fades out and the next JPanel in the list fades in. This is the code I am fiddling with: 我有一个要显示为“幻灯片”的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 < 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());
  }

The problem is that it fades some times, and other times it does not, and other times the transition is very laggy. 问题在于,它有时会消失,而另一些时候则不会,并且有时过渡非常缓慢。 What I would prefer is that there is a fraction of a second where the screen goes white, between when one JPanel fades out and the next JPanel fades in. Does anyone know how I can solve this? 我希望在一个JPanel淡出和下一个JPanel淡入之间,屏幕变白只有几分之一秒。有人知道我能解决这个问题吗? Thanks in advance. 提前致谢。

So, when dealing with these types of problems, it's generally a better idea to reduce the number of Timer s you have, as each timer will be posting multiple events to the Event Dispatching Queue (there own tick updates as well as repaint events). 因此,在处理这些类型的问题时,通常最好是减少您拥有的Timer的数量,因为每个计时器将向事件调度队列中发布多个事件(具有自己的滴答更新以及重画事件)。 All this activity could reduce the performance of the system. 所有这些活动可能会降低系统的性能。

Animation is also the illusion of change over time, to this end, rather the trying to loop from a start point to an end point, you should decide how long you want the animation to run for and calculate the progress of time and update the values accordingly (this more of a "timeline" based animation cycle). 为此,动画也是随着时间变化的幻觉,而不是尝试从起点到终点循环,您应该确定动画要运行多长时间并计算时间进度并更新值因此(更多是基于“时间轴”的动画周期)。 This can help reduce the appearance of "lagging" 这可以帮助减少“滞后”的出现

Normally I'd use the Timing Framework to accomplish this, but you could also have a look at the Trident framework or the Universal Tween Engine which also provide complex animation support for Swing. 通常,我会使用Timing Framework来完成此任务,但您也可以看看Trident框架或Universal Tween Engine ,它们也为Swing提供了复杂的动画支持。

This example is very tightly coupled to it's goal. 这个例子与它的目标紧密相关。 Personally, I'd normally have a abstract concept of an "animatiable" object, which would probably just have the update(float) method, which would then be expanded to support other objects, but I'll leave that you to nut out. 就个人而言,我通常会有一个“可动画化”对象的抽象概念,该对象可能仅具有update(float)方法,然后可以对其进行扩展以支持其他对象,但我将不赘述。

Another issue is making sure that the component is fully transparent to begin with ( setOpaque(false) ), this allows us to fake the translucency of the component during the animation. 另一个问题是要确保组件从( setOpaque(false) )开始是完全透明的,这使我们可以在动画期间伪造组件的半透明性。

Normally, I'd always encourage you to override paintComponent , but there a few times when this is not adequate, this is one of them. 通常,我总是鼓励您重写paintComponent ,但是有时这还不够,这就是其中之一。 Basically, in order to facilitate the transition from one component to the other, we need to control the alpha level of ALL the child components within the component, this is when overriding paint will be a better choice. 基本上,为了便于从一个组件过渡到另一个组件,我们需要控制该组件内所有子组件的Alpha级别,这是覆盖paint将是一个更好的选择。

褪色

nb: The code is set to run at around 25fps, but the screen capture software captures at roughly 8fps 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;
        }

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM