I'm very new to java.swing and I have looked at other answers but I'm struggling to understand how to properly double buffer in order to remove flickering.
Currently I have a JFrame class that has an action Listener
JButton northWest = new JButton("↖");
northWest.setPreferredSize(new Dimension(60, 60));
moveBorder.add(northWest);
northWest.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MainBoardJPanel mainBoardPanel = new MainBoardJPanel();
mainBoardPanel.movePlayer(painel.getGraphics(), -40, -40, playerInfo, currentPlayer.getUsername());
performMove();
}
});
When the button is pressed the movePlayer method (inside the MainBoardJPanel class) draws the background, the player icon at the new place and finally another layer which acts as fog of war.
public void movePlayer(Graphics g, int x, int y, PlayerInformation[] playerInfo, String username) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
try {
background = ImageIO.read(new File("Images\\BackgroundBoard.png"));
playerIcon1 = ImageIO.read(new File("Images\\PlayerIcon1.png"));
fogOfWar = ImageIO.read(new File("Images\\FogOfWar.png"));
} catch (Exception e) {
e.printStackTrace();
}
g.drawImage(background, 0, 0, this);
g.drawImage(playerIcon1, playerInfo[0].getPosX(), playerInfo[0].getPosY(), null);
int xFOW = x - 775;
int yFOW = y - 775;
g.drawImage(fogOfWar, xFOW, yFOW, this);
updateUserInfo(x, y, username);
setDoubleBuffered(true);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
(This is a very simplified version of it to cut down on irrelevant code)
Since each image is drawn consecutively the image keeps on flickering whenever the method is called, how would I go about double buffering this?
but I'm struggling to understand how to properly double buffer in order to remove flickering
I just want to make one thing very clear. When custom painting is done correctly, Swing components are automatically double buffered.
Calling super.paint
in movePlayer
is an inappropriate abuse of the painting system.
Don't use getGraphics
, this is not how custom painting works. Also, don't dispose of a Graphics
context you didn't create, this can actually prevent components which are schedule to painted after yours from been painted.
Swing uses a passive rendering algorithm, this means that it will schedule painting to occur when ever it decides it needs to be done. You don't have control over it, the best you can do is provide "hints" to the system that you would like a component or some part of the component repainted (ie repaint
). The painting subsystem will then decide when and what should be painted. Your components will be requested to perform a paint operation via their paint methods.
When done this way, Swing will double buffer the paint operation, so all components been painted are buffered and when the paint pass is complete, the image updated to the screen
I would, highly recommend, reading through:
for more details about how the painting system works in Swing and how you are expected to work with it
As a side note, I would also avoid loading resources (or performing any time consuming tasks) in any paint functionality. Painting should run as fast as possible