Malen in Swing Teil 2: ein einfaches Malprogramm: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
(Den Bereich, der dargestellt wird, einschränken)
K
 
(23 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
 
__TOC__
 
__TOC__
Dieses Beispielprogramm erlaubt das Malen von farbigen Linien verschiedener Stärke. Das Malen geschieht freihändig durch Ziehen mit der Maus.  
+
Der erste Teil dieses Tutorials erklärt den grundlegenden Malmechanismus: [[Malen in Swing Teil 1: der grundlegende Mechanismus]].
 +
 
 +
Das folgende weiterführende Beispielprogramm erlaubt das Malen von farbigen Linien verschiedener Stärke. Das Malen geschieht freihändig durch Ziehen mit der Maus.  
 
Durch dieses Beispiel lernen wir:  
 
Durch dieses Beispiel lernen wir:  
 
* wie mehrfache repaint Anträge zusammengefasst werden
 
* wie mehrfache repaint Anträge zusammengefasst werden
 
* wie wir den Bereich, der dargestellt wird, einschränken können
 
* wie wir den Bereich, der dargestellt wird, einschränken können
 
+
[[Datei:DrawOnImage.jpg]]
 
==Mehrfache repaint Anträge zusammenfassen==
 
==Mehrfache repaint Anträge zusammenfassen==
  
Zeile 10: Zeile 12:
 
Dabei wird repaint(x,y,brushSize,brushSize) mehrfach in einer Schleife aufgerufen:
 
Dabei wird repaint(x,y,brushSize,brushSize) mehrfach in einer Schleife aufgerufen:
  
<code=java>    @Override
+
<syntaxhighlight lang="java">    @Override
 
     public void mouseDragged(final MouseEvent e) {
 
     public void mouseDragged(final MouseEvent e) {
 
         double xDelta = e.getX() - lastPoint.getX();
 
         double xDelta = e.getX() - lastPoint.getX();
Zeile 34: Zeile 36:
 
         int y = start.y - (brushSize / 2) + 1;
 
         int y = start.y - (brushSize / 2) + 1;
 
         drawingPanel.getG2d().fillOval(x, y,brushSize, brushSize);
 
         drawingPanel.getG2d().fillOval(x, y,brushSize, brushSize);
         drawingPanel.repaint(x, y,brushSize, brushSize);
+
         drawingPanel.repaint(x, y,brushSize, brushSize); //<<---------------------
 
     }
 
     }
</code=java>
+
</syntaxhighlight>
  
Erfolgen mehrfache repaint() Aufrufe auf einer Komponente bevor der erste Antrag verarbeitet wird, kann der Swing Repaintmanager die mehrfachen Anträge zu einem einzigen Aufruf zusammenfassen. Wenn mehrfache Anträge zusammengefasst werden, ist das resultierende Cliprechteck gleich der Vereinigung der Rechtecke, die in den zusammengefassten Anträgen enthalten sind.
+
Erfolgen mehrfache repaint() Aufrufe auf einer Komponente bevor der erste Antrag verarbeitet wird, kann der Swing Repaintmanager die mehrfachen Anträge zu einem einzigen Aufruf zusammenfassen. Genauer gesagt: der RepaintManager wird eine Serie von Malanträgen dann zusammenfassen, wenn der "Anführer" der Serie schon mit invokeLater verschickt wurde, aber noch nicht auf dem EDT verarbeitet wurde (der Vorgang bleibt also "threadsafe"). Wenn mehrfache Anträge zusammengefasst werden, ist das resultierende Cliprechteck gleich der Vereinigung der Rechtecke, die in den zusammengefassten Anträgen enthalten sind.
 +
 
 +
'''BEMERKUNG:'''
 +
 
 +
Diese Zeile:
 +
<syntaxhighlight lang="java">drawingPanel.getG2d().fillOval(x, y,brushSize, brushSize);</syntaxhighlight>
 +
holt mit '''getG2d()''' nicht das Graphics Objekt der Komponente, sondern das Graphics Objekt des '''Bildes'''. In paintComponent wird dann mit "drawImage" das Bild auf das Graphics Objekt der Komponente übertragen, wie der folgende Abschnitt zeigt. Daher auch der Name des Hauptprogramms "DrawOnImage". Man spricht in diesem Fall auch von der "passiven Maltechnik".
  
 
==Den Bereich, der dargestellt wird, einschränken==
 
==Den Bereich, der dargestellt wird, einschränken==
Zeile 45: Zeile 53:
 
Wenn deine Komponente einfach ist -- zum Beispiel, wenn es eine Drucktaste ist -- dann ist sie die Mühe nicht wert, die Darstellung zu bearbeiten, um nur den Teil zu malen, der das Cliprechteck überschneidet; es ist vorzuziehend, die gesamte Komponente zu malen und die Graphics passend einschränken zu lassen. Wenn du jedoch eine Komponente mit komplizierter Ausgabe erzeugt hast, wie eine Textkomponente, dann ist es notwendig, dass dein Code die Clipinformationen gebraucht, um den Umfang der Darstellung einzuschränken. Die Methode Graphics#getClipBounds gibt uns Zugriff auf das Cliprechteck:
 
Wenn deine Komponente einfach ist -- zum Beispiel, wenn es eine Drucktaste ist -- dann ist sie die Mühe nicht wert, die Darstellung zu bearbeiten, um nur den Teil zu malen, der das Cliprechteck überschneidet; es ist vorzuziehend, die gesamte Komponente zu malen und die Graphics passend einschränken zu lassen. Wenn du jedoch eine Komponente mit komplizierter Ausgabe erzeugt hast, wie eine Textkomponente, dann ist es notwendig, dass dein Code die Clipinformationen gebraucht, um den Umfang der Darstellung einzuschränken. Die Methode Graphics#getClipBounds gibt uns Zugriff auf das Cliprechteck:
  
<code=java>    @Override
+
<syntaxhighlight lang="java">    @Override
 
     public void paintComponent(final Graphics g) {
 
     public void paintComponent(final Graphics g) {
 
         super.paintComponent(g);
 
         super.paintComponent(g);
Zeile 53: Zeile 61:
 
             resetImage();
 
             resetImage();
 
         }
 
         }
         Rectangle r = g.getClipBounds();
+
         Rectangle r = g.getClipBounds(); //<<----------------------
 
         g.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y, r.x, r.y, r.width + r.x, r.height + r.y, null);
 
         g.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y, r.x, r.y, r.width + r.x, r.height + r.y, null);
 
     }
 
     }
</code=java>
+
</syntaxhighlight>
Der drawImage(..)-Aufruf, mit den angegebenen Parametern, zeichnet nur den Teil des Bildes neu, der sich mit dem Cliprechteck überschneidet.
+
Der drawImage(..)-Aufruf, mit den angegebenen Parametern, zeichnet nur den Teil des Bildes neu, der sich mit dem Cliprechteck überschneidet. Man spricht in diesem Zusammenhang auch von der "intelligenten Maltechnik" (smart painting).
  
 
==Gesamter Quellcode==
 
==Gesamter Quellcode==
<code=java>import javax.swing.*;
+
<syntaxhighlight lang="java">
 +
import javax.swing.*;
 
import java.awt.*;
 
import java.awt.*;
 
import java.awt.event.*;
 
import java.awt.event.*;
  
public class DrawOnImage extends JFrame implements ActionListener {
+
public class DrawOnImage {
  
     private DrawingPanel drawingPanel;
+
     final private DrawingPanel drawingPanel;
     private JPanel buttonPanel;
+
     final private JPanel buttonPanel;
     private JButton clearButton, upSize, downSize;
+
     final private JButton clearButton, upSize, downSize;
 +
    private final ActionListener actionHandler;
  
 
     public DrawOnImage() {
 
     public DrawOnImage() {
         super("DrawOnImage");
+
         JFrame frame = new JFrame("DrawOnImage");
 
         drawingPanel = new DrawingPanel();
 
         drawingPanel = new DrawingPanel();
 +
        actionHandler = new ActionListener() {
 +
 +
            @Override
 +
            public void actionPerformed(final ActionEvent e) {
 +
                String s = e.getActionCommand();
 +
                if (s.equals("Paint")) {
 +
                    JButton button = (JButton) e.getSource();
 +
                    drawingPanel.setPaintColor(button.getBackground());
 +
                } else if (s.equals("Clear")) {
 +
                    drawingPanel.clearPaint();
 +
                } else if (s.equals("+")) {
 +
                    drawingPanel.increaseBrushSize();
 +
                } else {
 +
                    drawingPanel.decreaseBrushSize();
 +
                }
 +
            }
 +
        };
 
         buttonPanel = new JPanel();
 
         buttonPanel = new JPanel();
 
         buttonPanel.setLayout(new GridLayout(2, 0, 2, 2));
 
         buttonPanel.setLayout(new GridLayout(2, 0, 2, 2));
Zeile 86: Zeile 113:
 
         downSize = addButton(null);
 
         downSize = addButton(null);
 
         downSize.setText("-");
 
         downSize.setText("-");
         getContentPane().add(new JScrollPane(drawingPanel));
+
         frame.getContentPane().add(new JScrollPane(drawingPanel));
         getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+
         frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
 +
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
 +
        frame.pack();
 +
        frame.setLocationRelativeTo(null);
 +
        frame.setVisible(true);
 
     }
 
     }
  
Zeile 100: Zeile 131:
 
         button.setText("Paint");
 
         button.setText("Paint");
 
         buttonPanel.add(button);
 
         buttonPanel.add(button);
         button.addActionListener(this);
+
         button.addActionListener(actionHandler);
 
         return (button);
 
         return (button);
    }
 
 
    public void actionPerformed(final ActionEvent e) {
 
        String s = e.getActionCommand();
 
        if (s.equals("Paint")) {
 
            JButton button = (JButton) e.getSource();
 
            drawingPanel.setPaintColor(button.getBackground());
 
        } else if (s.equals("Clear")) {
 
            drawingPanel.clearPaint();
 
        } else if (s.equals("+")) {
 
            drawingPanel.increaseBrushSize();
 
        } else {
 
            drawingPanel.decreaseBrushSize();
 
        }
 
 
     }
 
     }
  
Zeile 123: Zeile 140:
 
             @Override
 
             @Override
 
             public void run() {
 
             public void run() {
                 JFrame frame = new DrawOnImage();
+
                 DrawOnImage drawOnImage = new DrawOnImage();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
 
                frame.pack();
 
                frame.setLocationRelativeTo(null);
 
                frame.setVisible(true);
 
 
             }
 
             }
 
         };
 
         };
Zeile 133: Zeile 146:
 
         SwingUtilities.invokeLater(gui);
 
         SwingUtilities.invokeLater(gui);
 
     }
 
     }
}</code=java>
+
}
<code=java>import java.awt.Point;
+
 
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="java">
 +
import java.awt.Point;
 
import java.awt.event.MouseEvent;
 
import java.awt.event.MouseEvent;
 
import javax.swing.event.MouseInputAdapter;
 
import javax.swing.event.MouseInputAdapter;
Zeile 140: Zeile 156:
 
class MouseHandler extends MouseInputAdapter {
 
class MouseHandler extends MouseInputAdapter {
  
     private DrawingPanel drawingPanel;
+
     private final DrawingPanel drawingPanel;
 
     private Point lastPoint;
 
     private Point lastPoint;
  
     MouseHandler(DrawingPanel drawingPanel) {
+
     MouseHandler(final DrawingPanel drawingPanel) {
 
         this.drawingPanel = drawingPanel;
 
         this.drawingPanel = drawingPanel;
 
     }
 
     }
Zeile 176: Zeile 192:
 
         int x = start.x - (brushSize / 2) + 1;
 
         int x = start.x - (brushSize / 2) + 1;
 
         int y = start.y - (brushSize / 2) + 1;
 
         int y = start.y - (brushSize / 2) + 1;
         drawingPanel.getG2d().fillOval(x, y,brushSize, brushSize);
+
         drawingPanel.getG2d().fillOval(x, y, brushSize, brushSize);
         drawingPanel.repaint(x, y,brushSize, brushSize);
+
         drawingPanel.repaint(x, y, brushSize, brushSize);
 
     }
 
     }
}</code=java>
+
}
<code=java>import java.awt.*;
+
</syntaxhighlight>
 +
<syntaxhighlight lang="java">
 +
import java.awt.*;
 
import javax.swing.*;
 
import javax.swing.*;
  
class DrawingPanel extends JComponent {
+
public class DrawingPanel extends JComponent {
  
 
     private Image image;
 
     private Image image;
Zeile 212: Zeile 230:
  
 
     public void clearPaint() {
 
     public void clearPaint() {
         g2d.setColor(Color.white);
+
         g2d.setBackground(Color.WHITE);
         g2d.fillRect(0, 0, getWidth(), getHeight());
+
         g2d.clearRect(0, 0, getWidth(), getHeight());
 
         repaint();
 
         repaint();
         g2d.setColor(Color.black);
+
         g2d.setColor(Color.BLACK);
 
     }
 
     }
  
Zeile 234: Zeile 252:
 
         // initialises the image with the first paint
 
         // initialises the image with the first paint
 
         // or checks the image size with the current panelsize
 
         // or checks the image size with the current panelsize
         if (image == null || image.getWidth(this) < getSize().width || image.getHeight(this) < getSize().height) {
+
         if (image == null || image.getWidth(this) < getSize().width
 +
                || image.getHeight(this) < getSize().height) {
 
             resetImage();
 
             resetImage();
 
         }
 
         }
 +
        Graphics2D g2 = (Graphics2D) g;
 
         Rectangle r = g.getClipBounds();
 
         Rectangle r = g.getClipBounds();
         g.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y, r.x, r.y, r.width + r.x, r.height + r.y, null);
+
         g2.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y,
 +
                r.x, r.y, r.width + r.x, r.height + r.y, this);
 
     }
 
     }
  
Zeile 246: Zeile 267:
 
         image = createImage(getWidth(), getHeight());
 
         image = createImage(getWidth(), getHeight());
 
         g2d = (Graphics2D) image.getGraphics();
 
         g2d = (Graphics2D) image.getGraphics();
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
         g2d.setColor(Color.white);
+
                RenderingHints.VALUE_ANTIALIAS_ON);
         g2d.fillRect(0, 0, getWidth(), getHeight());
+
         g2d.setBackground(Color.WHITE);
         g2d.setColor(Color.black);
+
         g2d.clearRect(0, 0, getWidth(), getHeight());
 +
         g2d.setColor(Color.BLACK);
 
         if (saveG2d != null) {
 
         if (saveG2d != null) {
 
             g2d.setColor(saveG2d.getColor());
 
             g2d.setColor(saveG2d.getColor());
 
             g2d.drawImage(saveImage, 0, 0, this);
 
             g2d.drawImage(saveImage, 0, 0, this);
 +
            saveG2d.dispose();
 
         }
 
         }
 
     }
 
     }
Zeile 263: Zeile 286:
 
         return brushSize;
 
         return brushSize;
 
     }
 
     }
}</code=java>
+
}
 +
</syntaxhighlight>
 +
 
 +
=Weitere Tutorials=
 +
* [https://forum.byte-welt.net/t/ein-zeichenprogramm-tutorial/19729 Ein Zeichenprogramm - Tutorial (von Beni & Roar)]
  
[[Kategorie:Java]]
 
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Tutorials (Java)]]
 +
[[Kategorie:Java 2D]]
 
[[Kategorie:Swing]]
 
[[Kategorie:Swing]]

Aktuelle Version vom 22. Dezember 2018, 10:25 Uhr

Der erste Teil dieses Tutorials erklärt den grundlegenden Malmechanismus: Malen in Swing Teil 1: der grundlegende Mechanismus.

Das folgende weiterführende Beispielprogramm erlaubt das Malen von farbigen Linien verschiedener Stärke. Das Malen geschieht freihändig durch Ziehen mit der Maus. Durch dieses Beispiel lernen wir:

  • wie mehrfache repaint Anträge zusammengefasst werden
  • wie wir den Bereich, der dargestellt wird, einschränken können

DrawOnImage.jpg

Mehrfache repaint Anträge zusammenfassen

Jede gemalte Linie setzt sich zusammen aus einer Folge von vielen Kreisen (Graphics#fillOval), die jeweils durch Interpolation zwischen zwei Mauspunkten festgelegt werden. Dabei wird repaint(x,y,brushSize,brushSize) mehrfach in einer Schleife aufgerufen:

    @Override
    public void mouseDragged(final MouseEvent e) {
        double xDelta = e.getX() - lastPoint.getX();
        double yDelta = e.getY() - lastPoint.getY();
        double delta = Math.max(Math.abs(xDelta), Math.abs(yDelta));
        double xIncrement = xDelta / delta;
        double yIncrement = yDelta / delta;
        double xStart = lastPoint.getX();
        double yStart = lastPoint.getY();
        for (int i = 0; i < delta; i++) {
            Point interpolated = new Point((int) xStart, (int) yStart);
            draw(interpolated);
            xStart += xIncrement;
            yStart += yIncrement;
        }
        draw(e.getPoint());
        lastPoint = e.getPoint();
    }

    private void draw(final Point start) {
        int brushSize = drawingPanel.getBrushSize();
        int x = start.x - (brushSize / 2) + 1;
        int y = start.y - (brushSize / 2) + 1;
        drawingPanel.getG2d().fillOval(x, y,brushSize, brushSize);
        drawingPanel.repaint(x, y,brushSize, brushSize); //<<---------------------
    }

Erfolgen mehrfache repaint() Aufrufe auf einer Komponente bevor der erste Antrag verarbeitet wird, kann der Swing Repaintmanager die mehrfachen Anträge zu einem einzigen Aufruf zusammenfassen. Genauer gesagt: der RepaintManager wird eine Serie von Malanträgen dann zusammenfassen, wenn der "Anführer" der Serie schon mit invokeLater verschickt wurde, aber noch nicht auf dem EDT verarbeitet wurde (der Vorgang bleibt also "threadsafe"). Wenn mehrfache Anträge zusammengefasst werden, ist das resultierende Cliprechteck gleich der Vereinigung der Rechtecke, die in den zusammengefassten Anträgen enthalten sind.

BEMERKUNG:

Diese Zeile:

drawingPanel.getG2d().fillOval(x, y,brushSize, brushSize);

holt mit getG2d() nicht das Graphics Objekt der Komponente, sondern das Graphics Objekt des Bildes. In paintComponent wird dann mit "drawImage" das Bild auf das Graphics Objekt der Komponente übertragen, wie der folgende Abschnitt zeigt. Daher auch der Name des Hauptprogramms "DrawOnImage". Man spricht in diesem Fall auch von der "passiven Maltechnik".

Den Bereich, der dargestellt wird, einschränken

Während Swing versucht, den Prozess der Darstellung der Komponenten so leistungsfähig wie möglich zu machen, kann die paintComponent() Implementierung einer Komponente selbst eine bedeutende Auswirkung auf die gesamte Leistung haben. Wir können diesen Prozess beeinflussen, indem wir die Clipinformationen verwenden, um den Bereich, der dargestellt wird, einzuschränken.

Wenn deine Komponente einfach ist -- zum Beispiel, wenn es eine Drucktaste ist -- dann ist sie die Mühe nicht wert, die Darstellung zu bearbeiten, um nur den Teil zu malen, der das Cliprechteck überschneidet; es ist vorzuziehend, die gesamte Komponente zu malen und die Graphics passend einschränken zu lassen. Wenn du jedoch eine Komponente mit komplizierter Ausgabe erzeugt hast, wie eine Textkomponente, dann ist es notwendig, dass dein Code die Clipinformationen gebraucht, um den Umfang der Darstellung einzuschränken. Die Methode Graphics#getClipBounds gibt uns Zugriff auf das Cliprechteck:

    @Override
    public void paintComponent(final Graphics g) {
        super.paintComponent(g);
        // initialises the image with the first paint
        // or checks the image size with the current panelsize
        if (image == null || image.getWidth(this) < getSize().width || image.getHeight(this) < getSize().height) {
            resetImage();
        }
        Rectangle r = g.getClipBounds(); //<<----------------------
        g.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y, r.x, r.y, r.width + r.x, r.height + r.y, null);
    }

Der drawImage(..)-Aufruf, mit den angegebenen Parametern, zeichnet nur den Teil des Bildes neu, der sich mit dem Cliprechteck überschneidet. Man spricht in diesem Zusammenhang auch von der "intelligenten Maltechnik" (smart painting).

Gesamter Quellcode

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

public class DrawOnImage {

    final private DrawingPanel drawingPanel;
    final private JPanel buttonPanel;
    final private JButton clearButton, upSize, downSize;
    private final ActionListener actionHandler;

    public DrawOnImage() {
        JFrame frame = new JFrame("DrawOnImage");
        drawingPanel = new DrawingPanel();
        actionHandler = new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                String s = e.getActionCommand();
                if (s.equals("Paint")) {
                    JButton button = (JButton) e.getSource();
                    drawingPanel.setPaintColor(button.getBackground());
                } else if (s.equals("Clear")) {
                    drawingPanel.clearPaint();
                } else if (s.equals("+")) {
                    drawingPanel.increaseBrushSize();
                } else {
                    drawingPanel.decreaseBrushSize();
                }
            }
        };
        buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(2, 0, 2, 2));
        addButton(Color.BLACK);
        addButton(Color.BLUE);
        addButton(Color.GREEN);
        upSize = addButton(null);
        upSize.setText("+");
        addButton(Color.RED);
        addButton(Color.ORANGE);
        clearButton = addButton(null);
        clearButton.setText("Clear");
        downSize = addButton(null);
        downSize.setText("-");
        frame.getContentPane().add(new JScrollPane(drawingPanel));
        frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JButton addButton(final Color color) {
        JButton button = new JButton();
        button.setBackground(new Color(230, 240, 250));
        button.setBorder(BorderFactory.createEtchedBorder());
        if (color != null) {
            button.setForeground(Color.WHITE);
            button.setBackground(color);
        }
        button.setText("Paint");
        buttonPanel.add(button);
        button.addActionListener(actionHandler);
        return (button);
    }

    public static void main(final String[] args) {
        Runnable gui = new Runnable() {

            @Override
            public void run() {
                DrawOnImage drawOnImage = new DrawOnImage();
            }
        };
        //GUI must start on EventDispatchThread:
        SwingUtilities.invokeLater(gui);
    }
}
import java.awt.Point;
import java.awt.event.MouseEvent;
import javax.swing.event.MouseInputAdapter;

class MouseHandler extends MouseInputAdapter {

    private final DrawingPanel drawingPanel;
    private Point lastPoint;

    MouseHandler(final DrawingPanel drawingPanel) {
        this.drawingPanel = drawingPanel;
    }

    @Override
    public void mousePressed(final MouseEvent e) {
        lastPoint = e.getPoint();
        draw(lastPoint);
    }

    @Override
    public void mouseDragged(final MouseEvent e) {
        double xDelta = e.getX() - lastPoint.getX();
        double yDelta = e.getY() - lastPoint.getY();
        double delta = Math.max(Math.abs(xDelta), Math.abs(yDelta));
        double xIncrement = xDelta / delta;
        double yIncrement = yDelta / delta;
        double xStart = lastPoint.getX();
        double yStart = lastPoint.getY();
        for (int i = 0; i < delta; i++) {
            Point interpolated = new Point((int) xStart, (int) yStart);
            draw(interpolated);
            xStart += xIncrement;
            yStart += yIncrement;
        }
        draw(e.getPoint());
        lastPoint = e.getPoint();
    }

    private void draw(final Point start) {
        int brushSize = drawingPanel.getBrushSize();
        int x = start.x - (brushSize / 2) + 1;
        int y = start.y - (brushSize / 2) + 1;
        drawingPanel.getG2d().fillOval(x, y, brushSize, brushSize);
        drawingPanel.repaint(x, y, brushSize, brushSize);
    }
}
import java.awt.*;
import javax.swing.*;

public class DrawingPanel extends JComponent {

    private Image image;
    private Graphics2D g2d;
    private int brushSize = 5;

    public DrawingPanel() {
        super();
        setPreferredSize(new Dimension(300, 300));
        MouseHandler mh = new MouseHandler(this);
        addMouseListener(mh);
        addMouseMotionListener(mh);
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension size = super.getPreferredSize();
        if (image != null) {
            size.width = image.getWidth(this);
            size.height = image.getHeight(this);
        }
        return size;
    }

    public void setPaintColor(final Color color) {
        g2d.setColor(color);
    }

    public void clearPaint() {
        g2d.setBackground(Color.WHITE);
        g2d.clearRect(0, 0, getWidth(), getHeight());
        repaint();
        g2d.setColor(Color.BLACK);
    }

    public void increaseBrushSize() {
        brushSize += 2;
    }

    public void decreaseBrushSize() {
        brushSize -= 2;
        if (brushSize <= 0) {
            brushSize = 1;
        }
    }

    @Override
    public void paintComponent(final Graphics g) {
        super.paintComponent(g);
        // initialises the image with the first paint
        // or checks the image size with the current panelsize
        if (image == null || image.getWidth(this) < getSize().width
                || image.getHeight(this) < getSize().height) {
            resetImage();
        }
        Graphics2D g2 = (Graphics2D) g;
        Rectangle r = g.getClipBounds();
        g2.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y,
                r.x, r.y, r.width + r.x, r.height + r.y, this);
    }

    private void resetImage() {
        Image saveImage = image;
        Graphics2D saveG2d = g2d;
        image = createImage(getWidth(), getHeight());
        g2d = (Graphics2D) image.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setBackground(Color.WHITE);
        g2d.clearRect(0, 0, getWidth(), getHeight());
        g2d.setColor(Color.BLACK);
        if (saveG2d != null) {
            g2d.setColor(saveG2d.getColor());
            g2d.drawImage(saveImage, 0, 0, this);
            saveG2d.dispose();
        }
    }

    public Graphics2D getG2d() {
        return g2d;
    }

    public int getBrushSize() {
        return brushSize;
    }
}

Weitere Tutorials