virtueller Bildschirm

Da mit super.paint(g); auch das Elternelement neu gezeichnet wird, würden alle alten Punkte die wir gemalt haben gelöscht werden. Das ist praktisch bei Animationen, nicht jedoch beim Zeichnen. Um daher korrekt malen zu können, müssen wir unserem Programm beibringen es sich zu merken was schon gezeichnet wurde. Dies bewerkstelligen wir mit einer einzigen Variablen. Zum einen könnten wir es mit einem Array machen:

package miniMalen;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Tafel extends JFrame {

  public static void main(String[] s) {
    new Tafel();
  }

  private int[][] liste = new int[100][2];
  private int zaehler = 0;
  private JPanel panel;
  private int x = -10;
  private int y = -10;

  public Tafel() {
    initialisiereTafel();
  }

  private void initialisiereTafel() {
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    this.setBounds(0, 0, 500, 500);
    this.setLocationRelativeTo(null);
    this.setAlwaysOnTop(true);
    this.setBackground(Color.white);
    this.setTitle("Tafel");
    this.setLayout(null);
    sichtbar();

    panel = new JPanel() {

      public void paintComponent(Graphics g) {
        super.paintComponent(g);

        for (int z = 0; z < liste.length; z++) {
          x = liste[z][0];
          y = liste[z][1];

          g.fillOval(x, y, 10, 10);
        }
      }

    };

    panel.setBackground(Color.WHITE);

    panel.setBounds(0, 0, 500, 500);
    this.add(panel);

    panel.addMouseMotionListener(new MouseAdapter() {
      public void mouseDragged(MouseEvent arg0) {
        System.out.println("Dragged");
        x = arg0.getX();
        y = arg0.getY();

        liste[zaehler][0] = x;
        liste[zaehler][1] = y;
        zaehler++;

        panel.repaint();
      }
    });

    panel.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent arg0) {
        System.out.println("Test");
        x = arg0.getX();
        y = arg0.getY();

        liste[zaehler][0] = x;
        liste[zaehler][1] = y;
        zaehler++;

        panel.repaint();
      }
    });

  }

  private void sichtbar() {
    this.setVisible(true);
  }

}

Wir definieren in Zeile 16 ein Array mit zwei Dimensionen. Also für die X- und Y-Koordinaten. Das heißt in diesem Fall, es gibt 100 Felder die jeweils 2 Speicherzellen für Zahlen, also int, enthalten. Ausserdem brauchen wir noch eine Zählvariable (Zeile 17) damit das Programm weiß in welchem Feld wir gerade sind.

In den MouseListener MouseDragged und MousePressed wird dann ab Zeile 66 bzw. 80 unter Benutzung der Zählvariable zaehler in die erste Zelle die x-Koordinate geschrieben und in die zweite y und anschließend zaehler mit zaehler++ um 1 erhöht. Dann wird mit panel.repaint(), panel, also unsere Zeichenfläche, neu gezeichnet.

Schließlich wird in der paint-Methode, die ja durch repaint() aufgerufen wird, in einer For-Schleife die komplette Liste ausgelesen und auf dem Bildsschirm ausgegeben. Das alles geschieht im Bruchteil einer Sekunde, jedesmal wenn die Maus gedrückt oder gedrückt und gezogen wird.

Allerdings hat die Lösung mit dem Array mehrere Nachteile. Wir müssen im Vorfeld festlegen wie viele Felder das Array hat, es kann sich nicht automatisch erweitern. Auch gibt es früher oder später eine OutOfBounds-Exception, sobald das Ende des Arrays erreicht ist, was ebenfalls behandelt werden müsste.
Einfacher ist es daher eine sogenannte ArrayList zu verwenden. Die Klasse ArrayList hat den Vorteil das es Methoden bereithält um bequem einen neuen Datensatz hinzuzufügen. Generell ist das arbeiten mit einer ArrayList sehr komfortabel wie wir noch sehen werden. Die Lösung mit der ArrayList würde so aussehen:

package miniMalprogramm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Tafel extends JFrame {

  public static void main(String[] s) {
    new Tafel();
  }

  private int[][] liste = new int[100][2];
  private int zaehler = 0;
  private JPanel panel;
  private int x = -10;
  private int y = -10;

  public Tafel() {
    initialisiereTafel();
  }

  private void initialisiereTafel() {
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    this.setBounds(0, 0, 500, 500);
    this.setLocationRelativeTo(null);
    this.setAlwaysOnTop(true);
    this.setBackground(Color.white);
    this.setTitle("Tafel");
    this.setLayout(null);
    sichtbar();

    panel = new JPanel() {

      public void paintComponent(Graphics g) {
        super.paintComponent(g);

        for (int z = 0; z < liste.length; z++) {
          x = liste[z][0];
          y = liste[z][1];

          g.fillOval(x, y, 10, 10);
        }
      }

    };

    panel.setBackground(Color.WHITE);

    panel.setBounds(0, 0, 500, 500);
    this.add(panel);

    panel.addMouseMotionListener(new MouseAdapter() {
      public void mouseDragged(MouseEvent arg0) {
        System.out.println("Dragged");
        x = arg0.getX();
        y = arg0.getY();

        liste[zaehler][0] = x;
        liste[zaehler][1] = y;
        zaehler++;

        panel.repaint();
      }
    });

    panel.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent arg0) {
        System.out.println("Test");
        x = arg0.getX();
        y = arg0.getY();

        liste[zaehler][0] = x;
        liste[zaehler][1] = y;
        zaehler++;

        panel.repaint();
      }
    });

  }

  private void sichtbar() {
    this.setVisible(true);
  }

}

Die ArrayList die wir definieren ist vom Typ Point. Ein Point ist ein einfaches Objekt das zwei Koordinaten, x und y enthält. In den MouseListeners wird einfach ein Point hinzugefügt (Zeile 65 und 77). Schließlich wird nach dem Aufruf von panel.repaint() der virtuelle Bildschirm mit einer for-Schleife ausgelesen und dargestellt.

Eine ArrayList kann natürlich auch mit einem Objekt gefüllt werden das wir selbst definiert haben. Zum Beispiel wollen wir nicht nur eine Point-Liste haben, sondern die Liste soll auch noch die Dicke des Pinsels speichern. Wir brauchen also ein Objekt das diese Daten speichert. Z.B. ArrayList<Grafikobjekt> welches dann zwei int Variablen für die Koordinaten sowie eine int-Variable für die Dicke enthält.
Im nächsten Kapitel wollen wir solch eine Klasse erstellen.
Hattet ihr heute schon einen Kaffee?