Farbwähler

Natürlich ist es langweilig immer in derselben Farbe zu malen. Also fügen wir einen Farbwähler hinzu. Praktischerweise müssen wir uns damit nicht lange aufhalten, den Java stellt uns mit JColorChooser einen umfangreichen Farbwähler zur Verfügung. Das ganze sieht so aus, das wir zunächst eine zweite JToolBar erstellen. Schließlich wollen wir noch weitere Werkzeuge hinzufügen und da passt eine Seitenleiste ganz gut. In diese Seitenleiste kommt dann der Button für den Farbwähler. Dieser Button wird mit einem ActionListener versehen, in dessen Methode wir schließlich den Farbwähler aufpoppen lassen. Schreiten wir zur Tat.

StartFenster.java

package miniMalen1;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
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();
  }

  JRadioButton kreisBtn;
  JRadioButton quadratBtn;
  JSpinner linienstaerke;
  JCheckBox fuellen;
  ButtonGroup werkzeugspitzen = new ButtonGroup();
  private JToolBar auswahl;
  private JToolBar seitenleiste;
  private JButton farbwaehlerIcon;
  Color farbe = 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());

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

    Insets nullMargin = new Insets( 5, 7, 5, 5 );
    seitenleiste.setMargin( nullMargin );
    
    kreisBtn = new JRadioButton("Kreis");
    quadratBtn = new JRadioButton("Quadrat");
    werkzeugspitzen.add(kreisBtn);
    werkzeugspitzen.add(quadratBtn);
    auswahl.add(kreisBtn);
    auswahl.add(quadratBtn);
    
    fuellen = new JCheckBox("Füllen");
    auswahl.add(fuellen);
    
    farbwaehlerIcon = new JButton() {
      public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(farbe);
        g.fillRect(20, 20, 20, 20);
      }
    };
    farbwaehlerIcon.setPreferredSize(new Dimension(20,20));
    farbwaehlerIcon.addActionListener(this);
    farbwaehlerIcon.setBackground(farbe);
    farbwaehlerIcon.setForeground(farbe);
    seitenleiste.add(farbwaehlerIcon);
    
    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 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.farbe;
  }

  @Override
  public void actionPerformed(ActionEvent e) {
      Object source = e.getSource();
      if(source == farbwaehlerIcon) {
      	farbe = JColorChooser.showDialog(this, "Farbe wählen", farbe);
      farbwaehlerIcon.setBackground(farbe);
      	farbwaehlerIcon.repaint();
      }	
  }
}

In Zeile 38-40 deklarieren wir die benötigten Variablen für Seitenleiste und Farbwählericon. Außerdem legen wir die voreingestellte Farbe fest.
In Zeile 25 implementieren wir die ActionListener-Schnittstelle
In Zeile 59-62 definieren wir die Seitenleiste.
In Zeile 77-83 initialisieren wir das farbwaehlerIcon mit einem JButton, den wir aber an unsere Bedürfnisse anpassen indem wir seine paint-Methode überschreiben. Anschließend setzen wir den ActionListener auf ihn (Zeile 85) und legen die Vordergrund wie Hintergrundfarbe fest um dann schließlich unserer seitenleiste das farbwaehlerIcon hinzuzufügen.
In Zeile 98 fügen wir die Seitenleiste dem „westlichen“ also linken Teil unserer Seite zu.
In Zeile 119-127 überschreiben wir die Methode des ActionListeners. Hier sehen wir wie einfach der JColorChooser einzusetzen ist. Bei showDialog erwartet drei Angaben um zu starten: der aufrufende Kontext (in unserem Fall this also die Klasse StartFenster), der Titel des Dialogfensters das aufpoppt, sowie die voreingestellte Farbe. Der Compiler blendet das Fenster ein und nachdem eine Farbe gewählt wurde weist er sie unserer Variable farbe zu.
Da wir möchten das unser modifizierter Button farbwaehlerIcon dann auch die neue Farbe zeigt, stellen wir erneut den Background ein und bewirken anschließend ein Repaint() unseres Buttons farbwaehlerIcon.
Ausserdem fügen wir noch einen Getter für unsere neue Variable farbe hinzu (Zeile 115-117).

Grafikobjekt.java

package miniMalen1;

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

import javax.swing.JCheckBox;

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;
  }
}

Die Änderungen an unserem Grafikobjekt sind denkbar einfach: Eine neue Variable farbe (Zeile 13) sowie die entsprechende Änderung am Konstruktor (Zeile 16 und 20) und ein neuer Getter (Zeile 38-40).

Tafel.java

package miniMalen1;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
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.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;

  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);
    
      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);
  }
}

In Zeile 55 greifen wir mit auswahl.getFarbe() auf den Getter von farbe im StartFenster zu und erhalten die derzeitige farbe die wir unserem Grafikobjekt übergeben.

In Zeile 38 müssen wir dann nur noch vor der if-Abfrage, die Farbe einstellen mit der gezeichnet werden soll.

So macht das Malen doch gleich viel mehr Spaß, oder?

Als nächstes wollen wir unsere Seitenleiste ausbauen und zwischen einem Pinsel und einer Radierfunktion hin- und herschalten können.