David Lewine
David Lewine

Reputation: 141

What is causing this code to repaint itself?

In the code below, the arrow keys are used to draw a line as in etch-a-sketch (but you have to resize the window first to trigger the panel's focus request at the right time -- that's a question for a different time, perhaps). The graphics command g.drawLine() occurs in the keyPressed() function, repaint() is not called explicitly, but the image updates itself as the arrow keys are pressed. Why is that? All the documentation I have looked at only talks about the JPanel automatically repainting itself when it is resized or uncovered.

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class Etch extends JPanel implements KeyListener{
    public int xPrev, yPrev, xNew, yNew, inc;

    public Etch(int start){
        xPrev = start;
        yPrev = start;
        xNew = start;
        yNew = start;
        inc = 10;
        addKeyListener(this);


    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        this.requestFocusInWindow();
    }


    public static void main(String[] args)
    {
        JFrame w = new JFrame("Keyboard");
        w.setBounds(100, 100, 600, 600);
        w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Etch panel = new Etch(200);
        panel.setFocusable(true);
        panel.setBackground(Color.RED);

        Container c = w.getContentPane();
        c.add(panel);

        w.setResizable(true);
        w.setVisible(true);

    }

    public void keyPressed(KeyEvent e){
        int code = e.getKeyCode();


        if (code == KeyEvent.VK_UP){
            xPrev = xNew;
            yPrev = yNew;
            yNew -= inc;

        }
        if (code == KeyEvent.VK_DOWN){
            xPrev = xNew;
            yPrev = yNew;
            yNew += inc;

        }
        if (code == KeyEvent.VK_LEFT){
            xPrev = xNew;
            yPrev = yNew;
            xNew -= inc;
        }
        if (code == KeyEvent.VK_RIGHT){
            xPrev = xNew;
            yPrev = yNew;
            xNew += inc;
        }

        Graphics g = this.getGraphics();
        g.setColor(Color.BLUE);
        g.drawLine(xPrev, yPrev, xNew, yNew);
    }

    // Not used but required by the KeyListener interface
    public void keyReleased (KeyEvent e) { }

    public void keyTyped (KeyEvent e) { }
}

Upvotes: 0

Views: 60

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347184

  • this.requestFocusInWindow(); is a bad idea within the paintComponent method. Painting should paint the current state and never change the state of the component
  • getGraphics is not how painting is done in Swing. Custom painting should be done from within the context of the paintComponent method. See Painting in AWT and Swing and Performing Custom Painting for more details
  • Consider using key bindings over KeyListener, as you can control the focus level required to trigger the key events. See How to Use Key Bindings for more details

Remember, you don't control the paint process in Swing, a paint cycle can be triggered by any number of events, most of which you don't actually control. Try working within the process instead of out of it.

Start by creating a List of java.awt.Point. Add each point to the List when a key event occurs. Use the paintComponent to iterate over the List and paint the lines between the Points...

Upvotes: 2

Related Questions