Dateimenü

Da der Quellcode mittlerweile recht lang ist, führe ich zugunsten der Übersichtlichkeit zuerst nur den Quellcode an der neu ist.
Ganz am Ende füge ich dann den gesamten Quellcode hinzu.

Um ein Menü hinzuzufügen stellt Swing uns die Klasse JMenuBar zur Verfügung. Das Vorgehen ist ähnlich wie mit den anderen Swing Komponenten. Zuerst fügen wir folgende Deklarationen unserem StartFenster hinzu:

private JMenuBar menuBar;
private JMenu menuDatei;
private JMenuItem mneu, mladen, mspeichern, mBeenden;

Dann fügen wir folgenden Quelltext in unserer initialisiereStartFenster() Methode des StartFensters ein:

menuBar = new JMenuBar();
this.setJMenuBar( menuBar );

menuDatei = new JMenu();
menuDatei.setText( "Datei" );
menuDatei.setMnemonic( 'd' ); // setzt Tastaturkürzel Alt+d
menuDatei.addActionListener( this );
menuBar.add( menuDatei );

mneu = new JMenuItem();
mneu.setText( "Neu" );
mneu.setMnemonic( 'n' );
mneu.setToolTipText( "Neues Bild erstellen" );
mneu.addActionListener( this );
menuDatei.add( mneu );

JSeparator sep1 = new JSeparator();
menuDatei.add( sep1 );

mladen = new JMenuItem();
mladen.setText( "Laden" );
mladen.setMnemonic( 'l' );
mladen.setToolTipText( "Datei laden" );
mladen.addActionListener( this );
menuDatei.add( mladen );

mspeichern = new JMenuItem();
mspeichern.setText( "Speichern" );
mspeichern.setMnemonic( 's' );
mspeichern.setToolTipText( "Bild speichern" );
mspeichern.addActionListener( this );
menuDatei.add( mspeichern );

JSeparator sep2 = new JSeparator();
menuDatei.add( sep2 );

mBeenden = new JMenuItem();
mBeenden.setText( "Beenden" );
mBeenden.setMnemonic( 'e' );
mBeenden.setToolTipText( "Programm beenden" );
mBeenden.addActionListener( this );
menuDatei.add( mBeenden );

Zuerst erstellen wir eine JMenuBar die dann unser Ausklappmenü aufnimmt, und setzen sie auf unser Fenster Zeile (1 und 2). In Zeile 4 – 8 fügen modifizieren wir diese MenüBar.

Danach definieren wir die einzelnen Menüeinträge die alle dem gleichen Schema folgen: Zuerst wir ein neues JMenuItem gebildet (Zeile 10), dann wird der Text (Zeile 11), das Tastaturkürzel (Mnemonic, (Zeile 12), sowie der ToolTip (Zeile 13, erscheint wenn den Mauspfeil ein paar Sekunden auf dem Eintrag ruhen läßt) hinzugefügt. Dann wird noch der ActionListener hinzugefügt (Zeile 14) und das ganze unserer JMenuBar namens menuDatei hinzugefügt (Zeile 15).

Der JSeparator den wir in Zeile 17 bilden und in Zeile 18 hinzufügen bildet eine horizontale Linie.

Jetzt brauchen wir noch ein paar if-Abfragen in unserem StartFenster und die Methoden zum speichern, laden und löschen des Bildschirms.
Hierzu fügen wir folgende Abfragen in unsere actionPerformed() Methode ein:

if ( source == mneu )
  tafel.neuesBild();

if ( source == mladen )
	loadPicture();

if ( source == mspeichern )
  savePicture( erstelleIMG( tafel ) );

if ( source == mBeenden )
  this.dispose();

Die Methode für ein neues Bild (Zeile 2) bauen wir am besten in die Tafel ein, da der virtuelle Bildschirm auch zur Zeichenfläche gehört.
Wir rufen also Tafel.java auf und deklarieren zuerst wieder die Variablen:

boolean bildGeladen = false;
public BufferedImage image;

dann die schreiben wir die Methode:

public void neuesBild()
{
  this.virtuellerBildschirm.clear();

  bildGeladen = false;
  image = null;

  repaint();
}

In dieser Methode leeren wir den virtuellenBildschirm indem wir den Inhalt der ArrayList mit clear() löschen.
Anschließend setzen wir bildGeladen auf false und image auf null damit die paint-Methode kein Bild zeichnen kann. Dann rufen wir repaint() auf und lassen damit den Bildschirm neu zeichnen.

Da wir nun eine Methode in der Tafel haben, die vom StartFenster aus aufgerufen wird, brauchen wir im StartFenster natürlich noch eine Referenz auf die Tafel die wir zu den anderen Variablendeklarationen hinzufügen:

private Tafel tafel;

Alle anderen Funktionen wollen wir dem Startfenster zuordnen.

loadPicture() :

private void loadPicture()
{
  JFileChooser chooser = new JFileChooser();
  chooser.setDialogType( JFileChooser.OPEN_DIALOG );

  int rueckgabeWert = chooser.showOpenDialog( this );

  if ( rueckgabeWert == JFileChooser.APPROVE_OPTION )
  {
    File file = chooser.getSelectedFile();
    try
    {
      tafel.image = ImageIO.read( file );
    }
    catch ( IOException e )
    {
      e.printStackTrace();
    }
    tafel.bildGeladen = true;
    tafel.repaint();
  }

}

Da wir nicht wollen das eine andere Klasse auf die loadPicture-Funktion zugreift machen wir diese privat (Zeile 1).

In Zeile 3 erstellen wir einen neuen JFileChooser mit Namen chooser. Dann setzen wir in Zeile 4 den Dialogtyp auf OPEN. D. h. wir teilen damit dem Compiler mit das wir den Dialog zum öffnen einer Datei benötigen.

In Zeile 6 weisen wir einer int-Variablen das öffnen unseres FileChoosers zu. chooser.showOpenDialog( this ); bewirkt zunächst nur das der Dialog geöffnet wird und zwar in this also in dem Objekt in dem der Aufruf stattfindet also unser Startfenster. Sobald eine Aktion – OK oder Abbrechen – getätigt wird gibt der Dialog einen Wert zurück. Dieser Wert wird in rueckgabeWert gespeichert.

In Zeile 8 wird rueckgabeWert auf darauf überprüft ob eine Datei ausgewählt und Ok gedrückt wurde. Ist das der Fall wird in Zeile 10  die Dateiinformation in einem File-Objekt gespeichert.

Jetzt wird in Zeile 11 – 14 versucht das Bild in die Variable image von tafel zu laden. Hierbei wird die Klasse ImageIO verwendet. Die read-Methode erwartet ein Objekt vom Typ File das wir ihr geben.

In Zeile 15 – 18 werden evtl. auftretende Fehler behandelt. Hier lassen wir uns einfach den StackTrace also den Weg wie der Fehler aufgetreten ist in die Konsole schreiben.

Anschließend setzen wir in Zeile 19 die Variable bildGeladen auf true damit die paint-Methode weiß, das sie ein Bild laden muss. Dann wird repaint() ausgelöst (Zeile 20).

savePicture (Zeile 8) benötigt ein Objekt vom Typ BufferedIMG. Dieses IMG erhalten wir durch eine Methode die wir ebenfalls schreiben. Die Methode ließt die Zeichenfläche aus und gibt sie im IMG-Bildformat zurück. Diese Methode könnte man natürlich auch als Getter in der Zeichenfläche realisieren. Aber unsere Zeichenfläche wollen wir am besten nur Zeichnen lassen.

Zuerst die Unterfunktion erstelleIMG():

public BufferedImage erstelleIMG( Component bild ) // gibt ein img der zeichenfläche an die Funktion savePicture zurück
{
  BufferedImage img = new BufferedImage( bild.getWidth(), bild.getHeight(), BufferedImage.TYPE_INT_RGB );
  Graphics2D g = img.createGraphics();
  bild.paintAll( g );
  g.dispose();
  return img;
}

Die Methode erwartet eine Komponente die ‚gescannt‘ werden soll. In unserem Fall also die Zeichenfläche.
In Zeile 3 erstellen wir ein neues leeres BufferedImage und geben ihm die Maße unserer Zeichenfläche. Außerdem setzen wir das Farbmodell auf RGB mit Integerwerten.
Zeile 4 bedeutet nicht das dort die Grafiken erstellt werden, es bedeutet vielmehr das das img in ein Graphics2D-Objekt eingebettet wird. Dies ermöglicht uns in das img Daten zu schreiben.
In Zeile 5 wird schließlich mit der paint-All Methode von bild, alle darin enthaltenen Grafiken in g und damit in das img geschrieben.
Jenes wird dann in Zeile 7 zurückgegeben.

savePicture() :

public void savePicture( BufferedImage img ) 	//  
{
  JFileChooser chooser = new JFileChooser();
  chooser.setDialogType( JFileChooser.SAVE_DIALOG );

  int rueckgabeWert = chooser.showSaveDialog( this );

  if ( rueckgabeWert == JFileChooser.APPROVE_OPTION )
  {
    File file = chooser.getSelectedFile();
    try
    {
      ImageIO.write( img, "png", file );
    }
    catch ( IOException e )
    {
      e.printStackTrace();
    }
  }
}

savePicture empfängt nun das img (Zeile 1).
Wir erstellen in Zeile 3 einen JFileChooser und definieren ihn als SAVE_DIALOG (Zeile 4).
In Zeile 6 bringen wir den Dialog auf den Bildschirm und weisen den Rückgabewert (OK oder Abbrechen) unserer Variablen rueckgabeWert zu.
In Zeile 8 überprüfen wir rueckgabeWert darauf ob Ok geklickt wurde und erstellen ein File-Objekt in das wir die Dateiinformation schreiben (Zeile 10).
Schließlich speichern wir das Bild in Zeile 13 unter zuhilfename der Klasse ImageIO mit der Methode write die drei Werte erwartet ( IMG, dateiendung, Dateipfad ).
In den Zeilen 15 – 18 behandeln wir möglicherweise auftretende Fehler indem wir uns in der Konsole genau ausgeben lassen wo der Fehler auftritt.

Zeile 10, this.dispose() ist ähnlich wie this.exit() nur mit dem Unterschied das der Compiler das Programm nicht sofort beendet sondern erst die Funktion dispose() aufruft. Der Programmierer hat damit die Möglichkeit zusätzliche Funktionen unterzubringen wenn das Programm beendet wird. Dies ist möglich indem er dispose() überschreibt um beispielsweise automatisch zu speichern oder ähnliches. Beispiel:

public void dispose() {
  System.out.println("Tschüß");
  System.exit(0);
}

Die Variable bildGeladen der Tafel, brauchen wir um in der paint das geladene Bild zu zeichnen falls etwas geladen wurde. In der Variablen image wird das Bild geladen. In der paint wird es dann folgendermaßen abgefragt:

if ( bildGeladen == true ) {
  if ( image != null )
	  g.drawImage( image, 0, 0, null ); // ( img-Bild, x-Position, y-position, observer
  }

Sicherhaltshalber fragen wir noch ab ob in image auch wirklich etwas vorhanden ist (Zeile 2).
In Zeile 3 verwenden wir null, da wir keinen observer haben (ein Observer könnte z.B. ein Fortschrittsbalken sein).

Hier wie versprochen der gesamte neue Quellcode.
Gönnt euch einen Kaffee und seht ihn in aller Ruhe durch.
Zuerst die StartFenster.java:

package miniMalprogramm;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButton;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SpinnerNumberModel;

public class StartFenster extends JFrame implements ActionListener {
  public static void main(String[] s) {
    new StartFenster();
  }

  Tafel tafel;
  private JMenuBar menuBar;
  private JMenu menuDatei;
  private JMenuItem mneu, mladen, mspeichern, mBeenden;

  private JToolBar auswahl;
  private JToolBar seitenleiste;

  JRadioButton kreisBtn;
  JRadioButton quadratBtn;
  JCheckBox fuellen;
  JSpinner linienstaerke;
  ButtonGroup werkzeugspitzen = new ButtonGroup();
  JToggleButton pinselBtn;
  JToggleButton radiererBtn;
  private JButton farbwaehlerIcon;
  private JButton farbwaehlerIconHG;

  Color vgfarbe = Color.BLACK;
  Color hgfarbe = Color.WHITE;
  Color aktuelleFarbe = Color.BLACK;

  public StartFenster() {
    initialisiereStartFenster();
  }

  private void initialisiereStartFenster() {
    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(new BorderLayout());

    menuBar = new JMenuBar();
    this.setJMenuBar(menuBar);
    menuDatei = new JMenu();
    menuDatei.setText("Datei");
    menuDatei.setMnemonic('d'); // setzt Tastaturkürzel Alt+d
    menuDatei.addActionListener(this);
    menuBar.add(menuDatei);
    mneu = new JMenuItem();
    mneu.setText("Neu");
    mneu.setMnemonic('n');
    mneu.setToolTipText("Neues Bild erstellen");
    mneu.addActionListener(this);
    menuDatei.add(mneu);
    JSeparator sep1 = new JSeparator();
    menuDatei.add(sep1);
    mladen = new JMenuItem();
    mladen.setText("Laden");
    mladen.setMnemonic('l');
    mladen.setToolTipText("Datei laden");
    mladen.addActionListener(this);
    menuDatei.add(mladen);
    mspeichern = new JMenuItem();
    mspeichern.setText("Speichern");
    mspeichern.setMnemonic('s');
    mspeichern.setToolTipText("Bild speichern");
    mspeichern.addActionListener(this);
    menuDatei.add(mspeichern);
    JSeparator sep2 = new JSeparator();
    menuDatei.add(sep2);
    mBeenden = new JMenuItem();
    mBeenden.setText("Beenden");
    mBeenden.setMnemonic('e');
    mBeenden.setToolTipText("Programm beenden");
    mBeenden.addActionListener(this);
    menuDatei.add(mBeenden);

    auswahl = new JToolBar();
    auswahl.setPreferredSize(new Dimension(300, 30)); // PreferredSize = bevorzugte Größe
    auswahl.setFloatable(false);

    kreisBtn = new JRadioButton("Kreis");
    kreisBtn.setSelected(true);
    quadratBtn = new JRadioButton("Quadrat");
    werkzeugspitzen.add(kreisBtn);
    werkzeugspitzen.add(quadratBtn);
    auswahl.add(kreisBtn);
    auswahl.add(quadratBtn);

    fuellen = new JCheckBox("Füllen");
    auswahl.add(fuellen);

    seitenleiste = new JToolBar();
    seitenleiste.setPreferredSize(new Dimension(30, 200)); // PreferredSize = bevorzugte Größe
    seitenleiste.setFloatable(false);
    seitenleiste.setOrientation(JToolBar.VERTICAL);
    Insets nullMargin = new Insets(5, 7, 5, 5);
    seitenleiste.setMargin(nullMargin);

    pinselBtn = new JToggleButton("P");
    pinselBtn.setPreferredSize(new Dimension(20, 20));
    pinselBtn.setSelected(true);
    pinselBtn.setAlignmentX(CENTER_ALIGNMENT);
    pinselBtn.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    pinselBtn.setSelected(true);
    pinselBtn.addActionListener(this);
    radiererBtn = new JToggleButton("R");
    radiererBtn.setPreferredSize(new Dimension(20, 20));
    radiererBtn.setSelected(false);
    radiererBtn.setAlignmentX(CENTER_ALIGNMENT);
    radiererBtn.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    radiererBtn.addActionListener(this);

    farbwaehlerIcon = new JButton() {
      public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(vgfarbe);
        g.fillRect(20, 20, 20, 20);
      }
    };
    farbwaehlerIcon.setPreferredSize(new Dimension(20, 20));
    farbwaehlerIcon.addActionListener(this);
    farbwaehlerIcon.setBackground(vgfarbe);
    farbwaehlerIcon.setForeground(vgfarbe);
    farbwaehlerIcon.setAlignmentX(CENTER_ALIGNMENT);

    farbwaehlerIconHG = new JButton() {
      public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(hgfarbe);
        g.fillRect(20, 20, 20, 20);
      }
    };
    farbwaehlerIconHG.setPreferredSize(new Dimension(20, 20));
    farbwaehlerIconHG.addActionListener(this);
    farbwaehlerIconHG.setBackground(hgfarbe);
    farbwaehlerIconHG.setForeground(hgfarbe);
    farbwaehlerIconHG.setAlignmentX(CENTER_ALIGNMENT);
    seitenleiste.add(pinselBtn);
    seitenleiste.add(radiererBtn);
    seitenleiste.addSeparator();
    seitenleiste.add(farbwaehlerIcon);
    seitenleiste.add(farbwaehlerIconHG);
    SpinnerNumberModel nummern = new SpinnerNumberModel(10.0, 1.0, 99.0, 1.0); // default, Minimum, Maximum,
                                          // Schrittweite
    linienstaerke = new JSpinner(nummern);
    linienstaerke.setMinimumSize(new Dimension(50, 30)); // setzt die Mindestgröße ( Breite, Höhe )
    linienstaerke.setMaximumSize(new Dimension(50, 30)); // setzt die Maximalgröße
    auswahl.add(linienstaerke);
    this.add(auswahl, BorderLayout.PAGE_START);
    this.add(seitenleiste, BorderLayout.WEST);

    tafel = new Tafel(this);
    this.add(tafel);
    sichtbar();
  }

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

  public double getLinienstaerke() {
    double staerke = (double) this.linienstaerke.getValue();
    return staerke;
  }

  public Color getFarbe() {
    return this.aktuelleFarbe;
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    if (source == farbwaehlerIcon) {
      vgfarbe = JColorChooser.showDialog(this, "Vordergrundfarbe wählen", vgfarbe);
      farbwaehlerIcon.setBackground(vgfarbe);
      aktuelleFarbe = vgfarbe;
      farbwaehlerIcon.repaint();
    } else if (source == farbwaehlerIconHG) {
      hgfarbe = JColorChooser.showDialog(this, "Hintergrundfarbe wählen", vgfarbe);
      farbwaehlerIconHG.setBackground(hgfarbe);
      aktuelleFarbe = hgfarbe;
      farbwaehlerIconHG.repaint();
    }
    if (source == pinselBtn) {
      pinselBtn.setSelected(true);
      radiererBtn.setSelected(false);
      aktuelleFarbe = vgfarbe;
    }
    if (source == radiererBtn) {
      radiererBtn.setSelected(true);
      pinselBtn.setSelected(false);
      aktuelleFarbe = hgfarbe;
    }
    if (source == mneu)
      tafel.neuesBild();

    if (source == mladen)
      loadPicture();

    if (source == mspeichern)
      savePicture(erstelleIMG(tafel));

    if (source == mBeenden)
      this.dispose();

  }

  public BufferedImage erstelleIMG(Component bild) // gibt ein img der zeichenfläche an die Funktion savePicture
                            // zurück
  {
    BufferedImage img = new BufferedImage(bild.getWidth(), bild.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics2D g = img.createGraphics();
    bild.paintAll(g);
    g.dispose();
    return img;
  }

  private void loadPicture() {
    JFileChooser chooser = new JFileChooser();
    chooser.setDialogType(JFileChooser.OPEN_DIALOG);

    int rueckgabeWert = chooser.showOpenDialog(this);

    if (rueckgabeWert == JFileChooser.APPROVE_OPTION) {
      File file = chooser.getSelectedFile();
      try {
        tafel.image = ImageIO.read(file);
      } catch (IOException e) {
        e.printStackTrace();
      }
      tafel.bildGeladen = true;
      tafel.repaint();
    }

  }

  public void savePicture(BufferedImage img) //
  {
    JFileChooser chooser = new JFileChooser();
    chooser.setDialogType(JFileChooser.SAVE_DIALOG);

    int rueckgabeWert = chooser.showSaveDialog(this);

    if (rueckgabeWert == JFileChooser.APPROVE_OPTION) {
      File file = chooser.getSelectedFile();
      try {
        ImageIO.write(img, "png", file);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  public void dispose() {
    System.out.println("Tschüß");
    System.exit(0);
  }
}

Dann die Tafel.java

package miniMalprogramm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;

public class Tafel extends JPanel implements MouseListener, MouseMotionListener {
  private ArrayList<Grafikobjekt> virtuellerBildschirm = new ArrayList<Grafikobjekt>();
  private int x = -10;
  private int y = -10;
  private StartFenster auswahl;

  boolean bildGeladen = false;
  public BufferedImage image;

  public Tafel(StartFenster auswahl) {
    this.auswahl = auswahl;
    this.setBackground(Color.WHITE);
    this.addMouseListener(this);
    this.addMouseMotionListener(this);
  }

  public void paintComponent(Graphics g0) {
    Graphics2D g = (Graphics2D) g0;
    super.paintComponent(g);
    if (bildGeladen == true) {
      if (image != null)
        g.drawImage(image, 0, 0, null); // ( img-Bild, x-Position, y-position, observer
    }

    for (int z = 0; z < virtuellerBildschirm.size(); z++) {
      Grafikobjekt go = virtuellerBildschirm.get(z);
      g.setColor(go.getFarbe());
      if (go.isGefuellt()) {
        g.fill(go.getForm());
      } else {
        g.draw(go.getForm());
      }
    }
  }

  public void zeichneAufVirtuellenBildschirm(double dx, double dy) {
    Shape werkzeug;

    if (auswahl.quadratBtn.isSelected()) {
      werkzeug = new Rectangle2D.Double(dx, dy, auswahl.getLinienstaerke(), auswahl.getLinienstaerke());
    } else {
      werkzeug = new Ellipse2D.Double(dx, dy, auswahl.getLinienstaerke(), auswahl.getLinienstaerke());
    }
    virtuellerBildschirm
        .add(new Grafikobjekt(new Point(x, y), werkzeug, auswahl.fuellen.isSelected(), auswahl.getFarbe()));
    this.repaint();
  }

  @Override
  public void mouseDragged(MouseEvent e) {
    System.out.println("Dragged");
    x = e.getX();
    y = e.getY();

    zeichneAufVirtuellenBildschirm(x, y);
  }

  @Override
  public void mousePressed(MouseEvent e) {
    System.out.println("Pressed");
    x = e.getX();
    y = e.getY();

    zeichneAufVirtuellenBildschirm(x, y);
  }

  @Override
  public void mouseMoved(MouseEvent arg0) {
    // TODO Automatisch generierter Methodenstub

  }

  @Override
  public void mouseClicked(MouseEvent arg0) {
    // TODO Automatisch generierter Methodenstub

  }

  @Override
  public void mouseEntered(MouseEvent arg0) {
    // TODO Automatisch generierter Methodenstub

  }

  @Override
  public void mouseExited(MouseEvent arg0) {
    // TODO Automatisch generierter Methodenstub

  }

  @Override
  public void mouseReleased(MouseEvent arg0) {
    // TODO Automatisch generierter Methodenstub

  }

  public void neuesBild() {
    this.virtuellerBildschirm.clear();

    bildGeladen = false;
    image = null;

    repaint();
  }
}

In der Grafikobjekt.java wurde nichts verändert. Aber der Vollständigkeit halber:

package miniMalprogramm;

import java.awt.Color;
import java.awt.Point;
import java.awt.Shape;

class Grafikobjekt {
  private Point koordinaten;
  private Shape form;
  private Color farbe;
  private boolean gefuellt;

  public Grafikobjekt(Point p, Shape st, boolean cb, Color f) {
    this.koordinaten = p;
    this.form = st;
    this.gefuellt = cb;
    this.farbe = f;
  }

  public Point getKoordinaten() {
    return this.koordinaten;
  }

  public void setKoordinaten(Point koordinaten) {
    this.koordinaten = koordinaten;
  }

  public Shape getForm() {
    return this.form;
  }

  public boolean isGefuellt() {
    return this.gefuellt;
  }

  public Color getFarbe() {
    return this.farbe;
  }
}