2013-03-19 4 views
6

Я создаю анимированный переход слайдов в Java, и он изменчив в моей текущей модели MacBook Pro и моем годовом iMac на Java 6, 7 и 8.Как я могу сделать анимацию Java Swing более гладкой?

Что я могу сделать, чтобы сделать эту анимацию более гладкой для пользователя на 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()); 
     } 
    } 
} 
+0

Значение isDoubleBuffered() в JPanel истинно –

+0

1) Используйте BufferedImage для фонового изображения. 2) Ограничьте, сколько вы будете перерисовывать, используя пересылку (...) 'перегрузки, которая только перерисовывает ограниченную область графического интерфейса, достаточно для ваших целей. 3) Играйте с частотой кадров, чтобы увидеть, что лучше всего работает. 4) Эксперимент с не-Swing анимацией/графической библиотекой, такой как Slick, которая может быть оптимизирована для анимации. –

+1

Уменьшите размер области, которую вы рисуете. – MadProgrammer

ответ

11

Многое зависит от того, чего именно вы в конечном итоге хотите достичь.

Помните, что анимация иллюзия движения ...

Я изменил

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

Alternativly, вы можете создать свой собственный сервис резервного буфера и обновлять его ...

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

Спасибо, это был полезный материал. Я замечаю, что когда я переключаюсь между настольными компьютерами Mac OS X, переход на скольжение намного более плавный, и я использую это как ориентир того, что возможно. К сожалению, Java на Mac, похоже, не имеет доступа к низкоуровневым возможностям компьютера. –

+0

Не так много имеет доступ к ускорению низкого уровня на Mac, это основная жалоба Adobe с Flash. – MadProgrammer

Смежные вопросы