Stop flickering in swing when i repaint too much
concurrency, event-dispatch-thread, java, repaint, swing
Solution
A number of small things jump out at me.
Firstly. You might be better using `javax.swing.Timer` instead of `java.util.Timer`, this will at least allow the events to flow a little better.
Secondly, 10 milliseconds is to short a time period, seriously, you don't need 100fps, 60fps is about 17 milliseconds, I normally use 40 milliseconds for 25fps. This might give the EDT some breathing room to actually respond to the repaint requests.
Thirdly, you should be using `paintComponent` instead of `paint`. It's low enough in the call chain to guaranteed to be double buffered
Fourthly, you should avoid calling any method that might reschedule a `repaint` (like `setDoubleBuffered` for example, to this in the constructor if you must, but, Swing components are double buffered by default)
Fifthly, where possible, paint all "static" or slow changing content to a backing buffer and paint that instead. This will increase the speed at which `paint` can work as it doesn't get stuck in a lot of small loops.
You may want to take a look at Painting in AWT and Swing for more details about the paint process
Some additional examples...
- Swing animation running extremely slow - was able to go from 500 elements up to 4500 elements moving on the screen at one time - talks about resource management as well
- Java Bouncing Ball
- How to make line animation smoother?
- the images are not loading
And because kleo scares me (and it's also a good idea), you should also take a look at How to use Key Bindings, which will solve your focus issues with the `KeyListener`
Problem
I am making an RPG with a tilemap. To generate the tilemap i loop through a 2 dimensional array but that means that when I repaint I have to do that each time. If I repaint too much the screen flickers how could I stop this. ``` package sexyCyborgFromAnOtherDimension; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Timer; import java.util.TimerTask; import javax.swing.JPanel; @SuppressWarnings("serial") public class Game extends JPanel { KeyLis listener; int mapX = 20; int mapY = 20; boolean up = false; boolean down = false; boolean right = false; boolean left = false; String[][] map; public Game() { super(); try { map = load("/maps/map1.txt"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } listener = new KeyLis(); this.setFocusable(true); this.requestFocus(); this.addKeyListener(listener); Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { if(up) { mapY++; repaint(); } if(down) { mapY--; repaint(); } if(right) { mapX--; repaint(); } if(left) { mapX++; repaint(); } } }; timer.scheduleAtFixedRate(task, 0, 10); } public void paint(Graphics g) { super.paintComponent(g); setDoubleBuffered(true); Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (int x = 0; x < map.length; x++) { for (int y = 0; y < map[x].length; y++) { switch(map[x][y]) { case "0": g.setColor(Color.GREEN); break; case "1": g.setColor(Color.GRAY); break; } g.fillRect(y*20+mapX, x*20+mapY, 20, 20); } } g.setColor(Color.BLACK); g.fillRect(400, 400, 20, 20); } String[][] load(String file) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(file))); int lines = 1; int length = br.readLine().split(" ").length; while (br.readLine() != null) lines++; br.close(); BufferedReader br1 = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(file))); String[][] map = new String[lines][length]; for (int i = 0; i < lines; i++) { String line = br1.readLine(); String[] parts = line.split(" "); for (int y = 0; y < length; y++) { map[i][y] = parts[y]; } } br1.close(); return map; } private class KeyLis extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: up = true; break; case KeyEvent.VK_DOWN: down = true; break; case KeyEvent.VK_LEFT: left = true; break; case KeyEvent.VK_RIGHT: right = true; break; } } @Override public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: up = false; break; case KeyEvent.VK_DOWN: down = false; break; case KeyEvent.VK_LEFT: left = false; break; case KeyEvent.VK_RIGHT: right = false; break; } } } } ``` Thank you for your help Edit Using `javax.swing.Timer` removes all flickering even with a 10 ms delay.