Java同时淡入和淡出两个JPanels [英] Java Fade In and Out two JPanels at the same time

查看:123
本文介绍了Java同时淡入和淡出两个JPanels的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个要显示为幻灯片"的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());
  }

问题是它有时褪色,有时不褪色,有时过渡非常缓慢.我希望在一个JPanel淡出和下一个JPanel淡入之间,屏幕变白只有几分之一秒.有人知道我能解决这个问题吗?预先感谢.

解决方案

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

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

通常我会使用定时框架完成此操作,但是您也可以看看在 Trident 框架或update(float)方法,然后可以对其进行扩展以支持其他对象,但我将不为所动. /p>

另一个问题是要确保组件从(setOpaque(false))开始是完全透明的,这使我们可以在动画期间伪造组件的半透明性.

通常,我总是鼓励您覆盖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<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;
        }

    }

}

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:

  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? Thanks in advance.

解决方案

So, when dealing with these types of problems, it's generally a better idea to reduce the number of Timers you have, as each timer will be posting multiple events to the Event Dispatching Queue (there own tick updates as well as repaint events). 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.

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.

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.

Normally, I'd always encourage you to override paintComponent, but there a few times when this is not adequate, this is one of them. 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.

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

    }

}

这篇关于Java同时淡入和淡出两个JPanels的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆