title: Swing requires createBufferStrategy(2) to properly paint
body: <p>I have some grids that is painted to screen one by one. I use arrow keys to move grids around as a group. Swing is said to be doubleBuffered by default so I believe <code>frame.createBufferStrategy(2)</code> is a bad practice but the problem is when I don't use manual double buffering, the grids are misaligned and some holes are appearing between them. Using manual double buffering fixes it.</p>
  <p>I'm also experiencing some graphical problems(such as a dialog's buttons not displaying properly) in the actual program(not in SSCCE) so I thought it might be caused by the incorrect implementation of the double buffering.</p>
  <p>Here is the SSCCE of the program, that causes grids to misalign when not manually double buffered:</p>
  <pre><code>package SSCCE;
  
  import java.awt.Color;
  import java.awt.FlowLayout;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.LayoutManager;
  import java.awt.event.KeyEvent;
  import java.awt.event.KeyListener;
  import java.awt.image.BufferStrategy;
  
  import javax.swing.JButton;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  
  public class Main {
  boolean manuallyDoubleBuffered = false; //change this
  
  static Main main;
  
  public final JFrame frame = new JFrame();
  public final Keys keys = new Keys();
  private JPanel panel;
  private BufferStrategy bufferStrategy;
  
   
  
  public static void main(String[] args) {
      main = new Main();
      main.initiate();
      // --START LOOP--
      Thread loop = new Thread(main.new Looper());
      loop.start();
  }
  
  public void initiate() {
      frameInit();
      keys.start();
  }
  
  private void frameInit() {
      frame.setSize(1200, 750);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
      setUpGUI();
      if (manuallyDoubleBuffered)
          frame.createBufferStrategy(2); // manual double buffering
      bufferStrategy = frame.getBufferStrategy();
  }
  
  private void setUpGUI() {
      panel = new JPanel() {
          @Override
          protected void paintComponent(Graphics g) {
              Graphics2D g2d = (Graphics2D) g;
              Main.main.rendering(g2d);
              super.paintComponent(g);
          }
      };
  
      LayoutManager layout = new FlowLayout();
      frame.getContentPane().setBackground(Color.black);
      panel.setLayout(layout);
      panel.setOpaque(false);//
      JButton but1 = new JButton(&quot;but1&quot;);
      panel.add(but1);
      frame.add(panel);
  }
  
  class Looper implements Runnable {
      @Override
      public void run() {
          Main.main.gameLoop();
      }
  }
  
  private void gameLoop() {
      // variables are declared at start
      while (true) {
  
          if (manuallyDoubleBuffered)
              paint(); // MANUAL double buffering
          else
              frame.repaint();// no manual double buffering
  
          update();
  
          try {
              Thread.sleep(1000 / 60);
          } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
      }
  }// loop end
  
  private void update() {
      move();
  
  }
  
  private void rendering(Graphics2D g2d) {
      // // testing
      paintGrids(g2d);
  }
  
  private void move() {
      x += sx;
      y += sy;
  }
  
  int sx = 0; //speedX
  int sy = 0; //speedY
  
  //top left corner of the grid
  int x = 0; 
  int y = 0;
  
  private void paintGrids(Graphics2D g) {
      for (int i = 0; i &lt; 100; i++) {
          for (int t = 0; t &lt; 100; t++) {
              g.setColor(Color.GRAY);
              g.fillRect(i * 50 + x, t * 50 + y, 50, 50);
              g.setColor(Color.BLACK);
              g.drawString(i + &quot;,&quot; + t, i * 50 + x, t * 50 + y + 10);
          }
      }
  
  }
  
  public void paint() {
      // uses double buffering system.
      do {
          do {
              Graphics2D g2d = (Graphics2D) bufferStrategy.getDrawGraphics();
              g2d.fillRect(0, 0, frame.getWidth(), frame.getHeight());
  
              try {
                  frame.paint(g2d);
              } catch (NullPointerException e) {
                  e.printStackTrace();
              }
              g2d.dispose();
          } while (bufferStrategy.contentsRestored());
          bufferStrategy.show();
      } while (bufferStrategy.contentsLost());
  }
  }
  
  class Keys implements KeyListener {// Trimmed down to shorten SSCCE
  private final int leftKey = 37; // left b.
  private final int rightKey = 39; // Right b.
  private final int upKey = 38;// up k.
  private final int downKey = 40;// down k.
  
  public void start() {
  
      Main.main.frame.addKeyListener(this);
      Main.main.frame.setFocusable(true);
  }
  
  private void left() {
      Main.main.sx -= 10;
  }
  
  private void right() {
      Main.main.sx += 10;
  }
  
  private void up() {
      Main.main.sy -= 10;
  }
  
  private void down() {
      Main.main.sy += 10;
  }
  
  @Override
  public void keyPressed(KeyEvent e) {
      // TODO Auto-generated method stub
      System.out.println(e.getKeyCode());
      switch (e.getKeyCode()) {
      case leftKey:
          left();
          break;
      case rightKey:
          right();
          break;
      case downKey:
          down();
          break;
      case upKey:
          up();
          break;
      }
  }
  
  @Override
  public void keyReleased(KeyEvent arg0) {
      // TODO Auto-generated method stub
  
  }
  
  @Override
  public void keyTyped(KeyEvent arg0) {
      // TODO Auto-generated method stub
  
  }
  
  }// END OF THE KEYS CLASS
  </code></pre>
  <p>Oracle tutorials of swing does not explain the usage with a game loop. What is the best way to do it? Am I doing anything wrong?</p>
  <p>In case the visual error is not reproduced on other computers, I'm uploading a screenshot:
  <img src="https://i.stack.imgur.com/PISwA.png" alt="Those black lines are not supposed to happen." />
  Black lines are caused by the misalinging of the rectangles. They don't exist when manual double buffering is set to true.</p>
  <p>Thanks in advance.</p>
  <p>Edit: I've forgot to mention that the black lines occur when grids are moving.</p>
  <p>I' have also found out, manual double buffering drastically reduces performance.</p>
  <p>Edit 2 : I've fixed the problem and posted it as an answer but feel free to comment on my code. Main class(except the gameLoop) is similar to the actual main class I use in my program.</p>