/* B E S C H R E I B U N G
Das Gleiche wie die letzte Version, außer dass noch ein
GridBagLayout verwendet wird (aber ohne Listener)

I)
1)
Es werden 2 Threads erzeugt:
-> main-Thread
-> EDT-Thread, der im Wesentlichen zwei Aufgaben hat:
   Event-Dispatching und Gui-Zeichnen
a)
repaint() verwendet intern quasi ein invokeLater(...this.paint()...)
um den paint()-Aufruf in den EDT zu bringen. Nur deshalb ist repaint auch
eine der wenigen Ausnahmen, wo eine Methode einer Swing-Komponente aus
einem anderen Thread als dem EDT ausgeführt werden darf.

b)
Verwendung eines Timers:
Es wird ein Objekt eines ActionListener (bzw. einer Unterklasse)
Dann wird ein Timer erstellt und das Objekt des ActionListeners dabei an
diesem Timer registriert (angebracht).
Nach einer gewissen Zeit feuert der Timer immer wieder ein Objekt der
Klasse ActionEvent ab, das automatisch der entsprechenden Methode des
ActionListeners übergeben wird.
Wichtig:
Die Handler des Timers (z.B: actionPerformed()) werden vom EDT abgearbeitet.

2)
a)
Die 2 Threads müssen nicht durch synchronised voneinander geschützt werden,
weil es in den verschiedenen Threads keine Lese - und Schreibzugriffe auf
eine gemeinsame Variable gibt.
Das Lesen (d.h. zeichen) und das Schreiben (setzen von Pixeln) geschieht
im _gleichen_ Thread (EDT).

b)
Wenn man in main(..) die folgende Anweisung macht:
myZf.setKreisNummer(kreisNummer);
dann wird in main(...) _und_ im EDT (durch myZf.setKreisNummer(kreisNummer))
auf die Variable
myZf.kreisNummer
zugegriffen, wobei mindestens ein Thread einen Schreibzugriff macht.
Deshalb kann es Problme geben.(Lese-Lesezugriff ist erlaubt,
Schreib-Lesezugriff nicht erlaubt, Schreib-Schreibzugriff nicht
erlaubt))
Auf die Variable myZf mit dem Wert 0100 wird zwar auch von allen
zwei Threads aus zugegriffen, doch sind das nur Lesezugriffe (d.h. der
Wert 0100 wird _nicht_ verändert), deshalb gibt es keine Probleme.

4)
Von außerhalb des EDT soll auch nicht auf bereits realisierte
Swing/AWT-Objekte zugegriffen werden.
Deshalb soll ja auch die Erzeugung der Swing-Komponenten nicht
direkt in main() erfolgen, sondern in der Klasse MyActionListener
in actionPerformed().
Warum?
Weil diese 2 Threads auf gemeinsame Daten zugreifen könnten.
Wenn man so etwas machen will, nuss man dies durch synchronized
realisieren.

Warum stellt man dann die Erzeugung von Swing-Objekten in den
EDT? Man muss doch einfach nur garantieren, dass keine Lese-
und Schreibzugriffe gleichzeitig erfolgen.
Antwort:
Weil innerhalb des EDT alles sequenziell (und nicht parallel)
vor sich geht.

Bem:
Sachen, die lange dauern sollen außerhalb des EDT gemacht werden,
da diese im EDT den EDT lahmlegen würden.

5)
Swing verwendet intern beim Zeichnen backbuffer und coalsizing.
Deswegen kann es Probleme geben, wenn man verzögert zeichnen will
(und dies ungeschickt anstellt): Alles wird dann auf einen Schlag gezeichent.

II)
Es wird ein eigenes Fenster gebastelt und dieses mit einer Zeichenfläche
versehen.
An die Zeichenfläche werden verschiedene Buttons geklebt, die jeweils mit
einem GridBagConstraints (Einschränkung) versehen werden, d.h. dass z.B.
ein Button über mehrere Zeilen und Spalten gehen kann (siehe unten).
Die Zeichenfläche wird dann mit einem GridBagLayout "formatiert".



Layout:
+----------------------!---!
!                      ! 2 !
!..........1...........!---!
!                      ! 3 !
!----------------------!---!
!          4           .   !
!----------------------!---!
!          5           !   !
!----------------------! 7 !
!          6           !   !
+----------------------!---+

Das Layout besteht aus einer Tabelle mit 5 Zeilen und 2 Spalten,
wobei ein Element der Tabelle über mehrere Zeilen und Spalten gehen kann.

1)gridwidth, gridheight
Im oberen Beispiel geht
+----------+----------------+-----------------+
+ Element  + über gridwidth +    gridheight   +
+----------+----------------+-----------------+
+ Element1 + über 1 Spalten + und 2 Zeilen    +
+----------+----------------+-----------------+
+ Element2 + über 1 Spalten + und 1 Zeilen    +
+----------+----------------+-----------------+
+ Element3 + über 1 Spalten + und 1 Zeilen    +
+----------+----------------+-----------------+
+ Element4 + über 2 Spalten + und 1 Zeilen    +
+----------+----------------+-----------------+
+ Element5 + über 1 Spalten + und 1 Zeilen    +
+ ---------+----------------+-----------------+
+ Element6 + über 1 Spalten + und 1 Zeilen    +
+ ---------+----------------+-----------------+
+ Element7 + über 1 Spalten + und 2 Zeilen    +
+ ---------+----------------+-----------------+

2) gridx, gridy
Die x- und y- Koordinaten der Elemente:
Elementn (gritdx|gridy)
Element1 (0|0)
Element2 (1|0)
Element3 (1|1)
Element4 (0|2)
Element5 (0|3)
Element6 (0|4)
Element7 (1|3)

3) weightx, weighty
a) Wenn alle Komponenten (z.B. Buttons) den Wert weightx-Wert 0 haben,
so wird eventuell anfallender Freiraum (falls die Buttons alle recht
klein sind), rechts und links eingefügt.

b) Wenn genau eine Komponente den weightx-Wert 0 hat, so wird genau nur
diesem einen Element eventuell anfallender Freiraun zugewiesen.

c) Ansonsten gibt der Wert an ,wieviel (relativ) Platz des Freiraums
verwendet wird.

d) Analoges gilt für weighty
*/


package verzoegertzeichnentimer2;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MainVerzoegertZeichnenTimer2 {
    public static void main(String[] args){
        int i;
        MyZeichenflaeche myZf = new MyZeichenflaeche(400, 400);
        JFrame f = new JFrame();
        f.setSize(550,550);
        f.getContentPane().add(myZf);
        MyActionListener myAl = new MyActionListener(myZf);
        javax.swing.Timer t = new javax.swing.Timer(100, myAl);
        t.start();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

class MyZeichenflaeche extends JPanel{
    private int kreisNummer;
    private Image myimg;

    public MyZeichenflaeche(int xpAnz, int ypAnz){
        Container myCont;
        GridBagLayout gbl;
        JButton myb1, myb2, myb3, myb4;
        gbl = new GridBagLayout();
		myb1=new JButton("B1");
		myb2=new JButton("B2");
		myb3=new JButton("B3");
		myb4=new JButton("B4");

        kreisNummer=0;
        myimg=null;

        addiereKomponente(gbl, new JLabel(), 0, 0, 2, 5, 1, 1);
        addiereKomponente(gbl, myb1, 0, 5, 1, 1, 1, 0);
        addiereKomponente(gbl, myb2, 1, 5, 1, 1, 0, 0);
        addiereKomponente(gbl, myb3, 2, 5, 1, 1, 0, 0);
        addiereKomponente(gbl, myb4, 3, 5, 1, 1, 0, 0);





        setLayout(gbl);


    }

    public void setKreisNummer(int pKreisnummer){
        kreisNummer=pKreisnummer;
    }

    public int getKreisNummer(){
        return (kreisNummer);
    }

    void erhoeheKreisNummer(){
        kreisNummer++;
    }

    // ist im EDT (siehe Methode void run)
    public void male(){
        Graphics myg;
        int sx, sy;

/*
Ein JFrame (bzw. sein ContentPane) hat standardmäßig ein BorderLayout, und
die Zeichenfläche liegt im CENTER des BorderLayouts
sx = 542, sy = 516 wird wie folgt berechnet:
Der Frame hat (siehe oben) eine Gesamtgröße von 550,550
Davon wird die Titelleiste und die Ränder (jeweils 4 Pixel) abgezogen
542 = 550-2*4,
516 = 550 - ...
*/
        sx = this.getSize().width;
        sy = this.getSize().height;
        System.out.println("sx="+sx);
        System.out.println("sy="+sy);
        //myimg = createImage(100, 100);
        myimg = createImage(sx, sy);
        myg = myimg.getGraphics();

        // Schreibzugriff auf myimg
        myg.setColor(Color.red);
        myg.drawOval(kreisNummer*20 , kreisNummer*20, 20, 20);
        myg.fillOval(kreisNummer*20 , kreisNummer*20, 20, 20);
    }

    // ist im EDT
    public void paintComponent(Graphics g){
        // Lesezugriff auf myimg
	g.drawImage(myimg,0,0,null);
    }

    public void addiereKomponente(GridBagLayout gbl, Component c, int x, int y, int width, int height, double weightx, double weighty){
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridx = x;
        gbc.gridy = y;
        gbc.gridwidth = width;
        gbc.gridheight = height;
        gbc.weightx = weightx;
        gbc.weighty = weighty;
        // Beschränkung für Komponente c (z.B. Button)am Layout-Manager anmelden.
        gbl.setConstraints(c, gbc);
        add(c);
    }

}

class MyActionListener implements ActionListener {
    private MyZeichenflaeche myZf;

    public MyActionListener(MyZeichenflaeche pz){
        myZf = pz;
    }

    public void actionPerformed(ActionEvent e) {
        myZf.erhoeheKreisNummer();
        // Schreibzugriff auf mying
        myZf.male();
        // Lesezugriff auf mying in paintComponent
        myZf.repaint();
    }
}


