javaswingjpanelpaintcomponentmouse-listeners

JPanel flickering with mouseMoved method


I have a simple JPanel that I'm using to display an image. I want some functionality where I'm able to pan the image by dragging it. I have something like this (note the code I have compiles and runs properly; the code below is heavily truncated to just get an idea of what I'm doing):

public class Data2DPanel extends JPanel { 
    public Data2DPanel(Data2D data) {
        // Set image
        this.image = Data2D.data2DToBufferedImage(data);

        // Set mouse listener
        Data2DMouseAdapter data2DMouseAdapter = new Data2DMouseAdapter();
        this.addMouseListener(data2DMouseAdapter);
        this.addMouseMotionListener(data2DMouseAdapter);
    }

    private class Data2DMouseAdapter extends MouseAdapter {
        @Override
        public void mouseDragged(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                switch (actionState) {
                    case PAN:
                        xOffset = xOffsetInit + e.getX()-xPosInit;
                        yOffset = yOffsetInit + e.getY()-yPosInit;
                        paintComponent(getGraphics());
                        break;                                
                }
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                            RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);

        // Paint image
        g2.drawImage(image,x,y,width,height,this);
        }
    }
}

The problem is that there is a lot of flickering. I've checked stackoverflow/google and it seems a lot of the flickering problems are because people override the paint method instead of the paintComponent method. I've also checked isDoubleBuffered and it returns true. Intuitively, I feel maybe the mouseDragged method is updating too much for paintComponent() to keep up, but I figured double buffering should still prevent flickering from occuring. My question is if there's something inherently wrong with this approach and if there's a standard or elegant solution to this.


Solution

  • paintComponent(getGraphics()); should be repaint(). Compounded problems.

    1. You never want to make a call to getGraphics() for custom painting. The only Graphics object used to paint should be the one provided in the paint method.
    2. You should never call paintXxx to try and "force" a repaint of the component. You should call repaint() and allow the RepaintManager to handle all the update and paint cycle