Search code examples
javaswingmouseeventpaintcomponentrepaint

Jave Swing - Drawing lines by dragging mouse: Why does my code work?


I'm learning the basics of Swing, and I managed to make this program to draw a line by dragging the mouse.

    public class SwingPaintDemo2 {

    public static void main(String[] args) {
        JFrame f = new JFrame("Swing Paint Demo");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(300,300);
        f.add(new MyPanel());
        f.setVisible(true);
    }
}

class MyPanel extends JPanel {

    private int x, y, x2, y2;

    public MyPanel() {

        setBorder(BorderFactory.createLineBorder(Color.black));
        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                x2 = e.getX();
                y2 = e.getY();
                repaint();
            }
        });

        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                x = e.getX();
                y = e.getY();
            }
        });
    }

    public void paintComponent(Graphics g){
//        super.paintComponent(g);
        g.setColor(Color.BLACK);
        g.drawLine(x, y, x2, y2);
        x = x2;
        y = y2;
    }
}

I have two questions:

1) If I call super.paintComponent(g) nothing is drawn, why is that?

2) In the code above, I reset x, y to be equal to x2, y2 in paintComponenet(), but I originally tried to reset them within mouseDragged like so:

  public void mouseDragged(MouseEvent e) {
            x2 = e.getX();
            y2 = e.getY();
            repaint();
            x = x2;
            y = y2;
        }

However, this did not create lines, only a series of points. To my understanding, these two approaches should have been equivalent. How are they different?


Solution

  • When you invoke the repaint() method a request is made to the RepaintManager. Then RepaintManager will then (potentially) combine multiple repaint() requests into once call to the paint() method of the component, which in turn will invoke the paintComponent() method.

    So, by the time the paintComponent() method is invoked the statements after the repaint() statement will already have been executed so the x/y values will already have been updated.

    You should always invoke super.paintComponent() at the start of your method to make sure the background is cleared. If you want to do incremental painting the check out Custom Painting Approaches which explains the two common ways to do this.