How can I make Java Swing animation smoother

I am creating an animated slide transition in Java and it is volatile in my current MacBook Pro model and on my annual iMac, in Java 6, 7, and 8.

What can I do to make this animation smoother for the user on 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()); } } } 
+6
source share
1 answer

Much depends on what you ultimately want to achieve.

Remember, animation is an illusion of movement ...

I changed

  • framesPerSecond to 60 , which seems to have helped.
  • Reducing the overall height of the print area
  • It calculates the area of ​​change and is simply called repaint(Rectangle) , passing only in the area that has changed.

Another problem is that your animation has a large area to cover for a very short period of time. Increasing the amount of time will also make it smoother (or reduce the width and / or height).

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

Alternatively, you can create your own support buffer and update it ...

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

The main problem you are facing is basically the area you are trying to draw is large for the time you want to draw it.

Another variant

You can create a BufferedImage that displays a progress bar and navigate as it updates. This update creates a compatible buffered image that should make it faster for renderer.

 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); } } } 
+11
source

All Articles