Wie kann man auf ein JPanel freihand zeichnen?

Dies lässt sich mit Hilfe eines MouseListeners und eines MouseMotionListeners realisieren.

Die Klasse wird von JPanel abgeleitet, einem Container, auf den durch Überschreiben der Methode paintComponent(Graphics g) gezeichnet werden kann. Zunächst werden vier Instanzvariablen deklariert, die die x- und y-Positionen des Startpunktes der Linie und der aktuellen Position der Maus speichern.
Im Konstruktor wird die Klasse jeweils bei einem MouseListener1 und einem MouseMotionListener angemeldet. Die Klasse implementiert die Listener selber. Die Listener müssen die folgenden Methoden implementieren:
MouseListener:


MouseMotionListener:

Prinzipiell sollten die Methoden-Bezeichner selbsterklärend sein.

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class Freihandzeichnen extends JPanel implements MouseListener, MouseMotionListener {

    private int startX, startY, tempX, tempY;
    
    private Graphics2D g2;

    public Freihandzeichnen() {
        System.out.println("Freihandzeichnen aufgerufen...");
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
    }

    protected void paintComponent(Graphics g) {
        // hier darf kein super.paintComponent() aufgerufen werden!
        g2 = (Graphics2D) g;
        g2.setPaintMode();
        g2.drawLine(startX, startY, tempX, tempY);
        startX = tempX;
        startY = tempY;
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.add(new Freihandzeichnen());
        frame.setSize(400, 300);
        frame.setTitle("Freihandzeichnen");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        startX = e.getX();
        startY = e.getY();
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        tempX = e.getX();
        tempY = e.getY();
        repaint();
    }

    public void mouseMoved(MouseEvent e) {
    }

In der Methode mousePressed(MouseEvent e) wird der Startpunkt der Linie zunächst durch Initialisieren der vier Variablen festgelegt, in mouseDragged(MouseEvent e) wird die aktuelle Mausposition in die Variablen tempX und tempY geladen. Vorher jedoch wird die bisherige Mausposition als Startposition abgespeichert. Letztlich werden also viele kleine Linien hintereinander gezeichnet, wobei der Startpunkt der nächsten immer der Endpunkt der vorhergehenden ist.
Der Zeichenvorgang selber findet in der Methode paintComponent(Graphics g) statt. Hier wird das als Parameter übergebene Graphics-Objekt zunächst in ein (mächtigeres) Graphics2D-Objekt gecastet. Nach Setzen des Paint-Modes wird schließlich mit der Methode drawLine(int startX, int startY, int endX, int endY) die Linie gezeichnet. Die Methode erwartet vier Parameter: jeweils einen x- und y-Wert für den Start- und Endpunkt.

1) Die Funktionsweise eines Listeners kann hier etwas genauer nachgelesen werden.