2016-01-02 3 views
0

Я пишу простую программу рисования, которая использует keyListeners. Он работает, но каждый раз, когда ему нужно рисовать другой круг, я должен использовать метод repaint(), иначе он не будет автоматически перерисовывать изображение после использования одной из клавиш со стрелками. Было бы хорошо, если бы он использовал слишком много CPU (около 50%) для такой простой программы. Любые идеи о том, как НЕ использовать метод repaint(), чтобы он мог делать все, что ему нужно, не съедая весь мой процессор? Вот исходный код:Перерисовать слишком много CPU

import java.awt.BorderLayout; 
import java.awt.Graphics; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 

import javax.swing.JComboBox; 
import javax.swing.JFrame; 

public class Game extends JFrame { 
int x, y; 

public class AL extends KeyAdapter { 

    @Override 
    public void keyPressed(KeyEvent e) { 
     int keyCode = e.getKeyCode(); 
     if (keyCode == e.VK_LEFT) { 
      x--; 
     } 
     if (keyCode == e.VK_RIGHT) { 
      x++; 
     } 
     if (keyCode == e.VK_UP) { 
      y--; 
     } 
     if (keyCode == e.VK_DOWN) { 
      y++; 
     } 

    } 

    @Override 
    public void keyReleased(KeyEvent e) { 

    } 
} 

public static void main(String[] args) { 
    Game game = new Game(); 
} 

public Game() { 
    addKeyListener(new AL()); 
    setTitle("Game"); 
    setSize(500, 500); 
    setResizable(false); 
    setVisible(true); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    x = 150; 
    y = 150; 

} 

@Override 
public void paint(Graphics g) { 
    g.fillOval(x, y, 15, 15); 
    repaint(); 
} 

} 
+0

все ответы отсутствуют две самые важные вещи 1. super.paint (очистка всех прошлых картин) в качестве первого. строка кода, перерисовка внутри краски создает цикл enless, 2. используйте JPanel с paintComponent – mKorbel

ответ

3

Вы делаете кое-что не так, когда речь идет о картине:

  • Не красьте на верхнем уровне компонента, как JFrame, вместо того, чтобы добавить JPanel к нему и рисовать на ней вместо этого.
  • Не переопределяйте paint, вместо этого замените paintComponent.
  • Не вызывайте repaint внутри методов, которые рисуют (например, paint и paintComponent), это вызовет рекурсию.

Также use key bindings instead of key listeners. Вот пример всего, что происходит вместе:

class Example extends JPanel { 

    int x = 0; 
    int y = 0; 

    Example() { 

     getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("RIGHT"), "right"); 
     getActionMap().put("right", new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 

       x++; 
       repaint(); 
      } 
     }); 
    } 

    @Override 
    public Dimension getPreferredSize() { 

     return new Dimension(200, 200); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 

     g.clearRect(0, 0, getWidth(), getHeight()); 
     g.drawRect(x, y, 30, 30); 
    } 

    public static void main(String args[]) { 

     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 

       JFrame frame = new JFrame(); 
       frame.add(new Example()); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
2

Не называйте repaint();paint() внутри. Перерисовывает графики paint(), поэтому неудивительно, что ваш процессор испытывает затруднения.

1

Как и в случае с Kayaman, вы никогда не должны переписывать() изнутри краски(). Вы можете вызвать метод Frames repaint() в keyPressed(), чтобы Frame был перекрашен каждый раз, когда вы нажимаете клавишу.

@Override 
public void keyPressed(KeyEvent e) { 
    int keyCode = e.getKeyCode(); 
    if (keyCode == e.VK_LEFT) { 
     x--; 
    } 
    if (keyCode == e.VK_RIGHT) { 
     x++; 
    } 
    if (keyCode == e.VK_UP) { 
     y--; 
    } 
    if (keyCode == e.VK_DOWN) { 
     y++; 
    } 
    Game.this.repaint(); 
} 
/*...*/ 
@Override 
public void paint(Graphics g) { 
    g.fillOval(x, y, 15, 15); 
} 
+0

Вы также должны рассмотреть использование API привязки ключей вместо KeyListener и вызов super.paint – MadProgrammer

0

Призыв к repaint() заставит RepaintManager вызвать paint() метод. Поэтому, если вы вызываете repaint() внутри paint(), он будет контур бесконечно. Вместо этого вы можете перекрасить ваш JFrame после выполнения действия key-pressed.

@Override 
public void keyPressed(KeyEvent e) { 
    int keyCode = e.getKeyCode(); 
    if (keyCode == KeyEvent.VK_LEFT) { 
     x--; 
    } 
    if (keyCode == KeyEvent.VK_RIGHT) { 
     x++; 
    } 
    if (keyCode == KeyEvent.VK_UP) { 
     y--; 
    } 
    if (keyCode == KeyEvent.VK_DOWN) { 
     y++; 
    } 
    repaint(); 
} 

Удалить repaint() вызов из paint() метода и добавить его, как указано выше.

Но если есть разные места, которые вы хотите перекрасить, и вы выберете вышеуказанный метод, он снова будет грязным. Итак, вы можете использовать Timer для звонка repaint().

private final javax.swing.Timer timer; 
private final int REFRESH_TIME = 100; 
public Game() { 
    addKeyListener(new AL()); 
    setTitle("Game"); 
    setSize(500, 500); 
    setResizable(false); 
    setVisible(true); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    x = 150; 
    y = 150; 

    timer = new javax.swing.Timer(REFRESH_TIME, new ActionListener() { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      repaint(); 
     } 
    }); 
    timer.start(); 
} 

Если вы хотите, вы можете использовать другой способ для вызова repaint() один раз в период. Вызов Thread не обязательно должен быть EDT.

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