Search code examples
javaswingevent-handlinggraphics2d

Drawing lines with arrow keys and adding each new line in repaint


I'm teaching myself Java programming with a textbook. An exercise asks you to:

Write a program that draws line segments using the arrow keys. The line starts from the center of the frame and draws toward east, north, west, or south when the right-arrow key, up-arrow key, left-arrow key, or down-arrow key is pressed, as shown in Figure 16.22c.

Figure 16.22c shows a frame with one continuous line flowing in the direction of whichever arrow key the user presses. With each press of an arrow key, the line extends in the direction of the arrow key pressed.

I have gotten as far as drawing a single iteration of the a line, but when I press an arrow key, the original line disappears and a new line is drawn. I know why it does this. And I think I know how to fix it. I was thinking of adding each iteration of a lint into an array (with its corresponding points). I haven't done it yet because it would require rewriting so far.

I figured there might be something I missed in my learning about graphics that could help me perform with task without an array. If there is an easier way, can someone explain it to me.

Here is the code I have so far:

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

public class DrawLinesWithArrowKeys extends JFrame {
    DrawLinesPanel panel = new DrawLinesPanel();

    /** Constructor */
    public DrawLinesWithArrowKeys() {
        add(panel);
        panel.setFocusable(true);
    }

    /** Main Method */
    public static void main(String[] args) {
        JFrame frame = new DrawLinesWithArrowKeys();
        frame.setTitle("Draw Lines With Arrow Keys");
        frame.setSize(400, 300);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    /** Inner class Draw Lines Panel */
    private class DrawLinesPanel extends JPanel {
        private int x1Offset = 0;
        private int x2Offset = 0;
        private int y1Offset = 0;
        private int y2Offset = 0;

        /* Constructor */
        public DrawLinesPanel () {
            addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_UP) {
                    y1Offset = y2Offset;
                    x1Offset = x2Offset;
                    y2Offset -= 10;
                    repaint();
                }   
                else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                    y1Offset = y2Offset;
                    x1Offset = x2Offset;
                    y2Offset += 10;
                    repaint();
                }
                else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    x1Offset = x2Offset;
                    y1Offset = y2Offset;
                    x2Offset -= 10;
                    repaint();  
                }
                else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                    x1Offset = x2Offset;
                    y1Offset = y2Offset;
                    x2Offset += 10;
                    repaint();
                }   
                }
            });
        }

        /* Paint line */
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            g.drawLine(computeXOne(), computeYOne(), computeXTwo(), computeYTwo()); 
        }

        private int computeXOne() {
            return (getWidth() / 2) + x1Offset;
        }

        private int computeXTwo() {
            return (getWidth() / 2) + x2Offset;
        }

        private int computeYOne() {
            return (getHeight() / 2) + y1Offset;
        }

        private int computeYTwo() {
        return (getHeight() / 2) + y2Offset;
        }
    }
}

Solution

  • Accumulate your points in a Shape, such as a Polygon or GeneralPath, seen here. You can draw() the current shape in your implementation of paintComponent(). As an alternative to KeyListener, use key bindings, shown here.