8

我正在用 Java 创建一个动画幻灯片过渡,它在我当前的型号 MacBook Pro 和我一岁的 iMac 上,在 Java 6、7 和 8 上时断断续续。

在 Mac OS X 上,我可以做些什么来使这个动画在用户看来更流畅?

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ScratchSpace {

    public static void main(String[] args) {
        AnimatedPanel panel = new AnimatedPanel();

        JFrame frame = new JFrame();
        frame.setContentPane(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        panel.animate();
    }


    public static class AnimatedPanel extends JPanel {

        private float progress = 0.0f; // a number between 0.0 and 1.0

        public AnimatedPanel() {
            setPreferredSize(new Dimension(800, 600));
            setOpaque(true);
        }

        public void animate() {
            final int animationTime = 1000;
            int framesPerSecond = 30;
            int delay = 1000 / framesPerSecond;
            final long start = System.currentTimeMillis();
            final Timer timer = new Timer(delay, null);
            timer.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    final long now = System.currentTimeMillis();
                    final long elapsed = now - start;
                    progress = (float) elapsed / animationTime;
                    repaint();
                    if (elapsed >= animationTime) {
                        timer.stop();
                    }
                }
            });
            timer.start();
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            int width = getWidth();
            int progressWidth = (int) (width * progress);
            g2d.setColor(Color.BLUE);
            g2d.fillRect(0, 0, progressWidth, getHeight());
            g2d.setColor(Color.RED);
            g2d.fillRect(progressWidth, 0, width-progressWidth, getHeight());
        }
    }
}
4

1 回答 1

15

很大程度上取决于您最终想要实现的目标。

请记住,动画是运动的幻觉......

我变了

  • framesPerSecond似乎有60帮助。
  • 降低了可打印区域的总高度
  • 计算变化的区域,简单地称为repaint(Rectangle)只传入发生变化的区域。

另一个问题是您的动画在很短的时间内需要覆盖很大的区域。增加时间也会使其更平滑(或减少宽度和/或高度)

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ScratchSpace {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                AnimatedPanel panel = new AnimatedPanel();

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                panel.animate();
            }
        });
    }

    public static class AnimatedPanel extends JPanel {

        private float progress = 0.0f; // a number between 0.0 and 1.0

        public AnimatedPanel() {
            setPreferredSize(new Dimension(800, 100));
        }

        public void animate() {
            final int animationTime = 1000;
            int framesPerSecond = 60;
            int delay = 1000 / framesPerSecond;
            final long start = System.currentTimeMillis();
            final Timer timer = new Timer(delay, null);
            timer.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    final long now = System.currentTimeMillis();
                    final long elapsed = now - start;

                    int width = getWidth();
                    int height = getHeight();
                    int oldWidth = (int) (width * progress);

                    progress = (float) elapsed / animationTime;
                    int newWidth = (int) (width * progress);

                    repaint(new Rectangle(oldWidth, 0, newWidth - oldWidth, height));
                    if (elapsed >= animationTime) {
                        timer.stop();
                    }
                }
            });
            timer.start();
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            int width = getWidth();
            int progressWidth = (int) (width * progress);
            g2d.setColor(Color.BLUE);
            g2d.fillRect(0, 0, progressWidth, getHeight());
            g2d.setColor(Color.RED);
            g2d.fillRect(progressWidth, 0, width - progressWidth, getHeight());
        }
    }
}

或者,您可以生成自己的后备缓冲区并更新它......

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ScratchSpace {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                AnimatedPanel panel = new AnimatedPanel();

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                panel.animate();
            }
        });
    }

    public static class AnimatedPanel extends JPanel {

        private float progress = 0.0f; // a number between 0.0 and 1.0
        private BufferedImage buffer;

        public AnimatedPanel() {
            setPreferredSize(new Dimension(800, 600));
//            setOpaque(true);
        }

        public void animate() {
            final int animationTime = 1000;
            int framesPerSecond = 60;
            int delay = 1000 / framesPerSecond;
            final long start = System.currentTimeMillis();
            final Timer timer = new Timer(delay, null);
            timer.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    final long now = System.currentTimeMillis();
                    final long elapsed = now - start;

                    int width = getWidth();

                    progress = (float) elapsed / animationTime;

                    updateBuffer();
                    repaint();

                    if (elapsed >= animationTime) {
                        timer.stop();
                    }

                }
            });
            timer.start();
        }

        @Override
        public void invalidate() {
            buffer = null;
            updateBuffer();
            super.invalidate();
        }

        protected void updateBuffer() {

            if (getWidth() > 0 && getHeight() > 0) {

                if (buffer == null) {

                    buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);

                }

                Graphics2D g2d = buffer.createGraphics();
                g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
                g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
                int width = getWidth();
                int height = getHeight();
                float progressWidth = width * progress;
                g2d.setColor(Color.BLUE);
                g2d.fill(new Rectangle2D.Float(0, 0, progressWidth, height));
                g2d.setColor(Color.RED);
                g2d.fill(new Rectangle2D.Float(progressWidth, 0, width - progressWidth, height));
                g2d.dispose();

            }

        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            if (buffer != null) {
                g2d.drawImage(buffer, 0, 0, this);
            }
//            int width = getWidth();
//            int progressWidth = (int) (width * progress);
//            g2d.setColor(Color.BLUE);
//            g2d.fillRect(0, 0, progressWidth, getHeight());
//            g2d.setColor(Color.RED);
//            g2d.fillRect(progressWidth, 0, width - progressWidth, getHeight());
        }
    }
}

您遇到的主要问题基本上是您尝试绘制的区域对于您想要绘制它的时间来说太大了。

另一种选择

您可以创建一个BufferedImage代表进度条并随着进度更新而移动。此更新创建了一个兼容的缓冲图像,这将使渲染器更快

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ScratchSpace {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                AnimatedPanel panel = new AnimatedPanel();

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                panel.animate();
            }
        });
    }

    public static class AnimatedPanel extends JPanel {

        private float progress = 0.0f; // a number between 0.0 and 1.0
        private BufferedImage buffer;

        public AnimatedPanel() {
            setPreferredSize(new Dimension(800, 600));
//            setOpaque(true);
        }

        public void animate() {
            final int animationTime = 1000;
            int framesPerSecond = 60;
            int delay = 1000 / framesPerSecond;
            final long start = System.currentTimeMillis();
            final Timer timer = new Timer(delay, null);
            timer.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    final long now = System.currentTimeMillis();
                    final long elapsed = now - start;

                    progress = (float) elapsed / animationTime;

                    repaint();

                    if (elapsed >= animationTime) {
                        timer.stop();
                    }

                }
            });
            timer.start();
        }

        @Override
        public void invalidate() {
            buffer = null;
            updateBuffer();
            super.invalidate();
        }

        protected void updateBuffer() {

            if (getWidth() > 0 && getHeight() > 0) {

                if (buffer == null) {

                    GraphicsConfiguration config = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
                    buffer = config.createCompatibleImage(getWidth(), getHeight(), Transparency.TRANSLUCENT);
                    buffer.coerceData(true);

                    Graphics2D g2d = buffer.createGraphics();
                    g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
                    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
                    g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
                    g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                    g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                    g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
                    int width = getWidth();
                    int height = getHeight();
                    g2d.setColor(Color.BLUE);
                    g2d.fill(new Rectangle2D.Float(0, 0, width, height));
                    g2d.dispose();

                }

            }

        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            int width = getWidth();
            int progressWidth = (int) (width * progress);
            int x = (progressWidth - width);
            System.out.println(progressWidth + "; " + x);
//            g2d.setColor(Color.BLUE);
//            g2d.fillRect(0, 0, progressWidth, getHeight());
            g2d.setColor(Color.RED);
            g2d.fillRect(progressWidth, 0, width - progressWidth, getHeight());
            g2d.drawImage(buffer, x, 0, this);
        }
    }
}
于 2013-03-19T22:39:01.550 回答