Handling Keyboard Events

Keyboard input works a lot like mouse input - a listener interface, an adapter class that saves you from writing empty methods, and an event object describing what happened. The one extra wrinkle with keyboards is focus: a component only receives key events while it actually has keyboard focus, and an applet doesn't get that for free.

Note: This page's code is a preview, not something you can run right on this website - this server runs PHP, not a Java runtime. Compile and run it locally as covered in Environment Setup.

KeyListener and KeyAdapter

java.awt.event.KeyListener declares three methods: keyTyped, keyPressed, and keyReleased. As with mouse listeners, KeyAdapter implements all three with empty bodies so you only override what you need:

addKeyListener(new KeyAdapter() {
    public void keyPressed(KeyEvent e) {
        // react to the key
    }
});

keyPressed/keyReleased fire for any physical key, including non-printable ones like arrows or Shift; keyTyped fires only for keys that produce an actual character. A KeyEvent exposes both getKeyChar() (the character typed) and getKeyCode() (a constant like KeyEvent.VK_LEFT for non-character keys).

Focus: setFocusable(true) and requestFocus()

An Applet is not focusable by default. Two calls are required before it will ever see a key event:

CallWhat it does
setFocusable(true)Marks the component as eligible to receive keyboard focus at all. Call once, in init().
requestFocus() / requestFocusInWindow()Actively asks the windowing system to hand focus to this component right now.

Extending PaintApplet: Clear and Color-Pick Shortcuts

Add a KeyAdapter in init() that clears drawnPoints when C is pressed, and sets currentColor directly when R, G, or B is pressed. The existing cycleColor() method from the previous lesson stays in the class as-is - it's simply not wired to a key here, though nothing stops a future lesson from calling it:

import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.List;

public class PaintApplet extends Applet {

    private Color currentColor = Color.BLUE;
    private Font titleFont = new Font("Arial", Font.BOLD, 18);
    private List<Point> drawnPoints = new ArrayList<>();

    public void init() {
        setBackground(Color.WHITE);
        setFocusable(true);

        addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                drawnPoints.add(e.getPoint());
                repaint();
            }
        });

        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                char key = Character.toUpperCase(e.getKeyChar());
                if (key == 'C') {
                    drawnPoints.clear();
                } else if (key == 'R') {
                    currentColor = Color.RED;
                } else if (key == 'G') {
                    currentColor = Color.GREEN;
                } else if (key == 'B') {
                    currentColor = Color.BLUE;
                }
                repaint();
            }
        });
    }

    public void start() {
        requestFocus();
    }

    public void paint(Graphics g) {
        g.setFont(titleFont);
        g.setColor(Color.BLACK);
        g.drawString("Welcome to PaintApplet!", 20, 30);
        g.drawRect(10, 10, getWidth() - 20, getHeight() - 20);

        g.setColor(currentColor);
        drawShapes(g);

        g.setColor(currentColor);
        for (Point p : drawnPoints) {
            g.fillOval(p.x, p.y, 4, 4);
        }
    }

    private void drawShapes(Graphics g) {
        g.drawLine(20, 50, 120, 50);
        g.drawRect(20, 60, 60, 40);
        g.fillOval(100, 60, 40, 40);
        int[] xPoints = {200, 230, 260};
        int[] yPoints = {100, 60, 100};
        g.drawPolygon(xPoints, yPoints, 3);
    }

    public void cycleColor() {
        if (currentColor == Color.BLUE) currentColor = Color.RED;
        else if (currentColor == Color.RED) currentColor = Color.GREEN;
        else currentColor = Color.BLUE;
        repaint();
    }
}

Why requestFocus() Lives in start(), Not init()

setFocusable(true) is a one-time capability flag, so it belongs in init(). requestFocus() is different: it's an active request that only succeeds once the component is actually showing on screen and attached to a window. When init() runs, the browser or appletviewer may not have finished laying out and displaying the component yet, so a requestFocus() call made there can silently fail depending on the implementation and timing. start() runs right after the applet becomes visible, which is a much more reliable point to ask for focus - and since start() can run again later (for example if the user navigates away and back), focus gets re-requested each time that happens too.

Next steps: Every value on PaintApplet so far has been hardcoded in the class itself. Head to Applet Parameters to let the HTML page that embeds the applet configure it from the outside.