Wie kann man eine Linie zeichnen, deren Endpunkt dem Mauscursor folgt?

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.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

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

public class LinieZiehen2 extends JPanel implements MouseListener, MouseMotionListener {

    private static final long serialVersionUID = 1L;

    private int startX, startY, tempX, tempY;
    
    private Image img = null;
    
    private static final Color BGCOLOR = new Color(170, 100, 100);

    private static final Color FGCOLOR = new Color(10, 200, 10);

    public LinieZiehen2() {
        this.setBackground(BGCOLOR);
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setPaintMode();
        g.drawImage(img, 0, 0, this);
        g2.setColor(FGCOLOR);
        g2.drawLine(startX, startY, tempX, tempY);
    }
    
    public void zeichne(){
        if(img == null){
            img = createImage(this.getWidth(), this.getHeight());
        }
        Graphics2D g2d = (Graphics2D)img.getGraphics();
        this.paint(g2d);
        g2d.dispose();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.add(new LinieZiehen2());
        frame.setBackground(BGCOLOR);
        frame.setSize(400, 300);
        frame.setTitle("Eine gerade Linie ziehen");
        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) {
        zeichne();
    }

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

    public void mouseMoved(MouseEvent e) {
    }

In der Methode mousePressed(MouseEvent e) wird der Startpunkt der Linie durch Initialisieren der Variablen festgelegt, in mouseDragged(MouseEvent e) wird die aktuelle Mausposition in die Variablen geladen, die den Endpunkt der Linie bestimmen. So ist gewährleistet, dass die jeweils aktuelle Mausposition das Ende der Linie angibt. repaint() bewirkt schließlich ein Neuzeichnen der Oberfläche, sodass verhindert wird, dass während der Mausbewegung eine Schar von Linien gezeichnet wird.
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.

Möchte man, dass bereits gezeichnete Linien beim Erzeugen einer neuen Linie erhalten bleiben, so muss nach dem Zeichnen einer Linie der Zustand des Panels zwischengespeichert werden. Hierzu erzeugt man eine Methode zeichne(), in der ein sog. Offscreen-Image erzeugt wird, dessen Grafikkontext an die paint()-Methode des JPanels übergeben wird. Diese Methode wird jedes Mal beim Beenden eines Zeichenvorgangs, also in mouseReleased(MouseEvent e), aufgerufen. Das Offscreen-Image muss schließlich jedes Mal in paintComponent(Graphics g) vor dem Ziehen der Linie gezeichnet werden.
Möchte man gleichzeitig die Hintergrundfarbe steuern ist ein kleiner Trick notwendig, da dieser nicht einfach mit fillRect() in paintComponent(Graphics g) erzeugt werden kann: Man weist sowohl dem JPanel, als auch dem Hauptfenster die gleiche Hintergrundfarbe zu.

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