2015-03-03 3 views
0

Я рисую объекты транспортных средств, которые я определил с помощью paintComponent(). Поскольку транспортные средства могут перемещаться, я реализую ActionListener и устанавливаю таймер() для запуска.repaint() краски медленнее, чем paintComponent()?

В результате мои транспортные средства могут двигаться. Но это своего рода «тряска». Когда я изменяю размер окна, чтобы вызвать paintComponent(), движение становится плавным. Когда я не изменяю размер окна (не называя paintComponent), он снова скачет. Зачем? Как это исправить?

public class VehiclesComponent extends JComponent implements ActionListener{ 
    private Vehicle[] vehicles; 
    private Timer timer; 

    public VehiclesComponent(int n){ 
     vehicles = Vehicle.generateVehicle(n); 
     timer = new Timer(5,this); 
    } 

    public void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D)g; 

     for (int i=0; i<vehicles.length; i++) { 
      vehicles[i].draw(g2); 
     } 

     // may change later 
     timer.start(); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e){ 

     //check collision in here 
     for (Vehicle v : vehicles) { 
      if (Vehicle.intersectsOther(v, vehicles)) { 
       v.collisionSideEffect(); 
      } 
     } 

     //move all in here 

     for (Vehicle v : vehicles) { 
      v.move(); 
     } 

     repaint(); 
     //?? repaint slower than paintComponent 
    } 


} 
+0

'общественного недействительными paintComponent (Graphics г) {..' как уже упоминалось здесь ** на ежедневной основе **, который должен быть «public void paintComponent (Graphics g) {super.paintComponent (g); ..' И 1) move '// может позже измениться timer.start();' вне метода, который мы не контролируем, когда и сколько раз он вызывается. 2) Используйте логическую и согласованную форму отступающих кодовых строк и блоков. Отступы предназначены для того, чтобы поток кода стал проще следовать! –

+0

И он должен оставаться 'protected' – MadProgrammer

+0

Начнем с [Живопись в AWT и Swing] (http://www.oracle.com/technetwork/java/painting-140037.html)'. 'repaint' делает запрос к' RepaintManager', который отвечает за планирование событий рисования в очереди событий. Чтобы повысить производительность, запрос 'repaint' может быть объединен в одно (или меньшее количество) событий рисования. – MadProgrammer

ответ

1

Начните с обзора Painting in AWT and Swing. Помните, repaint - это только предложение, сделанное для RepaintManager, RepaintManager может выбрать объединение нескольких repaint звонков в меньшее количество актуальных событий.

Удостоверяются, что вы звоните super.paintComponent, иначе вы в конце концов не закончите странные артефакты.

Не допускайте, прямо или косвенно, изменения состояния компонента или других компонентов из любого метода краски, это приведет к созданию нового запроса repaint, что может привести к циклу событий красок, которые могли бы потребляйте ваши циклы процессора. Это означает, что не звоните timer.start()!

Без плавного примера, который я прошел, я соскочил вместе. Теперь это оживляющий 10 000 индивидуальных Vehicle S (прямоугольники), так что это массово над убить, но она должна обеспечивать точку ...

Noise

(МФП работает только на 7 кадров в секунду, а не ваш 200fps)

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.Shape; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new VehiclesComponent(10000)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class VehiclesComponent extends JComponent implements ActionListener { 

     private Vehicle[] vehicles; 
     private Timer timer; 

     public VehiclesComponent(int n) { 
      vehicles = Vehicle.generateVehicle(n, getPreferredSize()); 
      timer = new Timer(5, this); 

      timer.start(); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(400, 400); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2 = (Graphics2D) g; 

      for (int i = 0; i < vehicles.length; i++) { 
       vehicles[i].draw(g2); 
      } 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 

      //check collision in here 
//   for (Vehicle v : vehicles) { 
//    if (Vehicle.intersectsOther(v, vehicles)) { 
//     v.collisionSideEffect(); 
//    } 
//   } 

     //move all in here 
      for (Vehicle v : vehicles) { 
       v.move(this.getSize()); 
      } 

      repaint(); 
      //?? repaint slower than paintComponent 
     } 

    } 

    public static class Vehicle { 

     protected static final int SIZE = 5; 
     protected static final Color[] COLORS = new Color[]{ 
      Color.BLACK, 
      Color.BLUE, 
      Color.CYAN, 
      Color.DARK_GRAY, 
      Color.GREEN, 
      Color.MAGENTA, 
      Color.ORANGE, 
      Color.PINK, 
      Color.RED, 
      Color.WHITE, 
      Color.YELLOW 
     }; 

     private int x = 0; 
     private int y = 0; 

     private int xDelta; 
     private int yDelta; 

     private Shape car; 
     private Color color; 

     public static Vehicle[] generateVehicle(int count, Dimension bounds) { 

      Vehicle[] vehicles = new Vehicle[count]; 
      for (int index = 0; index < vehicles.length; index++) { 
       vehicles[index] = new Vehicle(bounds); 
      } 

      return vehicles; 

     } 

     public Vehicle(Dimension size) { 

      x = (int)(Math.random() * (size.width - SIZE)); 
      y = (int)(Math.random() * (size.height - SIZE)); 

      xDelta = (int)(Math.random() * 3) + 1; 
      yDelta = (int)(Math.random() * 3) + 1; 
      car = new Rectangle(SIZE, SIZE); 

      color = COLORS[(int)(Math.random() * COLORS.length)]; 

     } 

     public void move(Dimension size) { 
      x += xDelta; 
      y += yDelta; 

      if (x < 0) { 
       x = 0; 
       xDelta *= -1; 
      } else if (x + SIZE > size.width) { 
       x = size.width - SIZE; 
       xDelta *= -1; 
      } 
      if (y < 0) { 
       y = 0; 
       yDelta *= -1; 
      } else if (y + SIZE > size.height) { 
       y = size.height - SIZE; 
       yDelta *= -1; 
      } 

     } 

     public void draw(Graphics2D g2) { 
      g2.translate(x, y); 
      g2.setColor(color); 
      g2.fill(car); 
      g2.translate(-x, -y); 
     } 

    } 

} 

Вы также мог бы взглянуть на this example, которая делает вверх 4500 изображений в произвольных направлениях и демонстрируют некоторые методы оптимизации.

Вы также можете посмотреть на this example, который способен анимировать как в направлении вращения и, свыше 10 000 изображений

+0

* «так что это массовое убийство» * Нет такого убийства, как перебор. :) –

+0

Хотя я вижу смысл делать лишь «несколько» модификаций существующего кода (для того, чтобы предоставить * ответ *, а не просто рассказать, что он использует неправильный подход), следует, вероятно, подчеркнуть, что * * не следует злоупотреблять «Компонента» как спрайты **. Компонент - это компонент, а спрайт - спрайт. Живопись 10000 простых прямоугольников (в собственном компоненте, в методе 'paintComponent') была бы возможна с гораздо большим, чем 7 fps ... – Marco13

+0

@ Marco13 Первые два момента: call' super.paintComponent' и не вызывайте 'timer.start' в методе' paintComponent'. GIF-анимация имеет 7 кадров в секунду, поэтому причина выглядит немного «пошатнутой», пример может максимизироваться со скоростью 200 кадров в секунду. Первые два момента будут иметь разницу, основанную на том, что предоставил ОП. ОП не предоставил никакой информации о том, что они рисуют или как, поэтому невозможно предоставить более подробную информацию. Если вам нравится, я могу опубликовать ссылку на пример, который анимирует 4000-5000 случайных изображений ... – MadProgrammer

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