Für diejenigen, die es interessiert, gibt es hier den vollständigen Java-Quelltext:
Diesen Textteil kann man auch direkt als HTML-Quelltext lesen, falls der Browser ihn im Fenster nicht vollständig oder korrekt darstellt. (< und > werden möglicherweise als Tags interpretiert)
zum Applet
zur Homepage



//
/* ** Auge ** Anfang: 15.2.1999,  letzte Änderung: 12.2.2000,  Java Version 1.0 */
//
// Tab-stop = 4 Zeichen,    sonst wird alles unleserlich
// die Kommentare stehen vor oder neben dem entsprechendem Quellcode 

import java.awt.*;
import java.applet.*;
import java.net.URL;

public class Auge extends Applet {

    Fenster   f;
    Button    but;

    // das eigentliche Applet zeigt nur einen Knopf,
    // mit dem man dann das Haupt-Fenster öffnet
    public void init() {
        f = new Fenster(this);
        setLayout(new BorderLayout());
        setBackground(Color.yellow);
        but = new Button("Fenster öffnen");
        add("Center", but);
        f.normZeit();
    }
    public Insets insets() { return new Insets(30,15,30,15); }

    public void stop() {
        if (f.t != null) f.t.stop();
        f.hide();
        f.diaZeit.hide();
        f.diaTast.hide();
        f.diaFarb.hide();
    }

    public boolean action(Event evt, Object arg) {
        if (evt.target == but) {  
            f.show();
            f.resize(650,500);
            f.move(100,50);
            f.requestFocus();
            f.initial();
        }
        return true;
    }
}

class Fenster extends Frame implements Runnable {        // zentrale Steuer-Klasse

        // Objekte aus selbst definierten Klassen, für Referenz-Zwecke
        Schirm    sch;
        Auswert   aus;
        Korrel    kor;
        Auge      aug;
        DialogEi  diaTast;                   // Dialogfenster für Tasten-Einstellungen
        DialogEi  diaFarb;                   // Dialogfenster für Farb-Einstellungen
        DialogEi  diaZeit;                   // Dialogfenster für Zeit-Einstellungen
        // sichtbare Eigenschaften und Menu-Leiste
        Dimension dim;                       // Schirm-Abmessungen bei t.start()
        boolean   diaAn;                     // ein Dialogfenster ist geöffnet
        Menu      mEinst, mInfo, mStart, mKreuz;
        MenuItem  miZeit, miFarb, miTast, miInfo, miStart, miWeit, miAusw,
            miLinks, miMitte, miRechts;
        Button    butZeit, butFarb, butTast; // die jeweiligen OK-Knöpfe
        String    aus_but3 = "noch was";     // Aufschrift auf diesem Button
        int       kreuz;                     // Kreuz ist links, mitte, rechts (-1,0,+1)
        // Variablen des Dialog-Fensters "Zeiten"
        Button    reset;                     // Reset-Button im "Zeiten-Fenster"
        TextField txZ[];                     // die Textfelder im "Zeiten-Fenster"
        int       iTxZ;                      // dieses Textfeld hat den Fokus
        Label     lb;                        // Fehlerhinweis
        // Variablen des Dialog-Fensters "Tasten"
        String    sTas[] = {                 // Bezeichnungen für alle verfügbaren Tasten
            "Leerzeichen-Taste",
            "Enter",
            "0  (null)",
            "Pfeil nach unten",
            "Pfeil nach oben",
            "Pfeil nach links",
            "Pfeil nach rechts",
            "Escape",
            "Maus,  linke Taste" };
        int       key[] = {32, 10, 48, 1005, 1004, 1006, 1007, 27, -1};
                                             // key-Schlüssel für diese Tasten und "Maus"
        String    strStart;                  // Bezeichnung für die verwendete Taste
        String    strHalt;                   // Bezeichnung für die verwendete Taste
        Checkbox  cb1[], cb2[];              // für Tasten-Aauswahl
        Label     lb6;                       // ein Hinweis im Tasten-Fenster
        int       keyStart;                  // Taste zum Starten und Reagieren
        int       keyHalt;                   // Taste zum Halten und Auswerten
        int       st=3, ha=4;                // Array-Nummern dieser Tasten und Checkbox
        // Variablen des Dialog-Fensters "Farben"
        CanEi     can;                       // das Farb-Muster-Quadrat, eigene Klasse
        Button    butF1, butF2;              // für Hintergrund- und Punkt-Farbe
        Button    butF3, butF4;              // für "Punkt größer", "Punkt kleiner"
        TextFiel  tfF1;                      // zeigt aktuelle Punkt-Größe an
        Scrollbar sbF0, sbF1, sbF2, sbF3;    // die 4 Schiebe-Regler im Farb-Fenster
        int       val;                       // aktueller Wert der Schiebe-Regler
        Label     lbh, lbr, lbg, lbb;        // zeigen Helligkeit, rot, grün, blau
        Checkbox  lock;                      // Helligkeit bleibt konstant
        int       hell, rot, grun, blau;     // Farb-Parameter für die Muster-Farben
        double    h=0, r=0, g=0, b=0;        // Zwischenwerte für eine Farbe
        Color     cBuf;                      // Muster-Farbe für Punkt
        Color     bBuf;                      // Muster-Farbe für Hintergrund
        int       dBuf;                      // Muster-Punkt-Größe
        boolean   punktBol;                  // wenn die Punkt-Farbe verändert wird
        boolean   bolr, bolg, bolb, bol      // gewisse Erinnerungen für die Regler
        // Variablen für den Haupt-Ablauf und Auswertung
        Thread    t;                         // steuert die Blink-Abfolge in run()
        int       dur        =10;            // Durchmesser vom Blink-Punkt
        int       dau;                       // Blink-Dauer
        int       p_min;                     // minimaler Zeitabstand beim Blinken
        int       p_max;                     // maximaler Zeitabstand beim Blinken
        Color     c         =Color.r         // Blink-Farbe
        Color     back    =Color.black;      // Hintergrund-Farbe
        int       i;                         // fortlaufender Zähler der Blinker
        long      time;                      // Blink-Zeitpunkt, Anfang
        long      anzeit;                    // Anfangszeit, auch nach Pause
        int       gezeit;                    // Gesamtzeit des Versuchs
        int       gesp;                      // Anzahl der gesehenen Gespenster-Punkte
        int       anz;                       // maximale Anzahl der Blinker
        // in diesen Arrays werden die Ergebnisse gespeichert
        int       res_x[];                   // Resultate jedes Blinkens, x-Wert
        int       res_y[];                   // Resultate jedes Blinkens, y-Wert
        int       res_t[];                   // Resultate, Reaktionszeit
        int       res_g[];                   // = 1 wenn Gespenst gesehen
        int       res_w[];                   // die Wartezeit vor dem Blinken
        // einige Werte, die den Programm-Zustand kennzeichnen
        boolean   wert;                      // wenn das Auswertungs-Fenster zu sehen ist
        boolean   lauf;                      // solange run() läuft (auch unterbrochen)
        boolean   suspend;                   // wenn Thread unterbrochen
        boolean   scharf;                    // scharf für Reaktion nach dem Blinken
        boolean   ende;                      // sperrt Start-Taste nach Beenden

    // Fenster einrichten, Referenzen zu anderen Objekten festlegen
    // auch die Dialog-Fenster werden hier eingerichtet,
    // nächstes Mal bekommen sie gleich eigene Klassen
    Fenster(Auge aug) {
        super(" teste deine Augen");
        this.aug = aug;
        // Anfangs-Zuweisungen
        keyStart = key[st];
        keyHalt = key[ha];
        strStart = sTas[st];
        strHalt = sTas[ha];
        // Menu-Leiste einrichten
        MenuBar mb = new MenuBar();
        setMenuBar(mb);
        mStart = new Menu(" Start ");
        mb.add(mStart);
        miStart = new MenuItem("Neu-Start   ( F1 )");
        mStart.add(miStart);
        miAusw = new MenuItem("unterbrechen");
        mStart.add(miAusw);
        miWeit = new MenuItem("weiter");
        mStart.add(miWeit);
        mEinst = new Menu("Einstellungen");
        mb.add(mEinst);
        miZeit = new MenuItem("Frequenz");
        mEinst.add(miZeit);
        miFarb = new MenuItem("Farben");
        mEinst.add(miFarb);
        miTast = new MenuItem("Tasten");
        mEinst.add(miTast);
        mKreuz = new Menu("Kreuz");
        mEinst.add(mKreuz);
        miLinks = new MenuItem("links");
        mKreuz.add(miLinks);
        miMitte = new MenuItem("mitte");
        mKreuz.add(miMitte);
        miRechts = new MenuItem("rechts");
        mKreuz.add(miRechts);
        mInfo = new Menu("  I n f o  ");
        mb.add(mInfo);
        miInfo = new MenuItem("zur Web-Seite");
        mInfo.add(miInfo);
        // Layout-Manager für alle Dialog-Fenster, GridBagLayout ist umständlich
        // und unanschaulich, aber man hat die besten Gestaltungs-Möglichkeiten
        GridBagLayout gri = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();
        // Dialog-Fenster "Zeiten" wird eingerichtet
        diaZeit = new DialogEi(this, " Frequenz-Einstellungen");
        diaZeit.setBackground(new Color(230,230,250));
        diaZeit.show();                        // ist merkwürdigerweise notwendig,
        diaZeit.hide();                        // damit resize() und move() funktioniert
        diaZeit.resize(350, 300);
        diaZeit.move(300, 150);
        Label lbZ[] = {
            new Label("Blink-Dauer  (in m.sek):"    // 0
            new Label("Blink-Pause,  minimal:"),    // 1
            new Label("Blink-Pause,  maximal:"),    // 2
            new Label("Blink-Anzahl,  maximal:")    // 3
        };                                  // wenn man hier ein Label hinzufügt,
                                            // wird es automatisch mit Textfeld platziert
        txZ = new TextField[lbZ.length];
        diaZeit.setLayout(gri);
        c.fill=c.HORIZONTAL;
        c.weightx=0;
        c.weighty=1;
        c.insets=new Insets(0,6,0,6);
        for (int i=0; i< lbZ.length; i++) {
            c.gridwidth=2;
            gri.setConstraints(lbZ[i], c);
            diaZeit.add(lbZ[i]);
            c.gridwidth=c.REMAINDER;
            txZ[i]=new TextField(10);
            gri.setConstraints(txZ[i], c);
            diaZeit.add(txZ[i]);
        }
        c.insets=new Insets(10,0,10,0);
        c.gridwidth=1;
        c.weighty=2;
        c.fill=c.NONE;
        reset = new Button("reset");
        gri.setConstraints(reset, c);
        diaZeit.add(reset);
        c.fill = c.HORIZONTAL;
        lb = new Label(" ");
        gri.setConstraints(lb, c);
        diaZeit.add(lb);          
        c.fill=c.NONE;
        butZeit = new Button("   O K   ");
        gri.setConstraints(butZeit, c);
        diaZeit.add(butZeit);
        // Dialog-Fenster "Tasten" wird eingerichtet
        diaTast = new DialogEi(this, " Tasten-Einstellungen");
        diaTast.setBackground(new Color(240,240,210));
        diaTast.show();
        diaTast.hide();
        diaTast.resize(300, 500);
        diaTast.move(300, 150);
        diaTast.setLayout(gri);
        c.insets=new Insets(0,10,20,10);
        c.fill=c.NONE;
        c.weightx=1;
        c.weighty=0;
        c.gridwidth=c.REMAINDER;
        Label lb1 = new Label("wähle die Tasten, die am bequemsten sind");
        gri.setConstraints(lb1, c);
        diaTast.add(lb1);
        c.insets=new Insets(20,10,0,30);
        c.gridwidth=1;
        c.fill=c.HORIZONTAL;
        Label lb2 = new Label("Taste zum Starten");
        gri.setConstraints(lb2, c);
        diaTast.add(lb2);
        c.gridwidth=c.REMAINDER;
        Label lb3 = new Label("Taste zum Anhalten");
        gri.setConstraints(lb3, c);
        diaTast.add(lb3);
        c.insets=new Insets(0,10,20,30);
        c.gridwidth=1;
        Label lb4 = new Label("und Reagieren");
        gri.setConstraints(lb4, c);
        diaTast.add(lb4);
        c.gridwidth=c.REMAINDER;
        Label lb5 = new Label("und Auswerten");
        gri.setConstraints(lb5, c);
        diaTast.add(lb5);
        CheckboxGroup cg1 = new CheckboxGroup();
        CheckboxGroup cg2 = new CheckboxGroup();
        cb1 = new Checkbox[sTas.length];
        cb2 = new Checkbox[sTas.length];
        c.insets=new Insets(0,6,0,6);
        for (i=0; i< sTas.length; i++) {
            cb1[i] = new Checkbox(sTas[i], cg1, (i == st));
            c.gridwidth=1;
            gri.setConstraints(cb1[i], c);
            diaTast.add(cb1[i]);
            cb2[i] = new Checkbox(sTas[i], cg2, (i == ha));
            c.gridwidth=c.REMAINDER;
            gri.setConstraints(cb2[i], c);
            diaTast.add(cb2[i]);
        }
        butTast = new Button("   O K   ");
        c.insets=new Insets(0,30,0,30);
        lb6 = new Label(" ");
        gri.setConstraints(lb6, c);
        diaTast.add(lb6);
        c.insets=new Insets(0,20,20,20);
        c.fill=c.NONE;
        gri.setConstraints(butTast, c);
        diaTast.add(butTast);
        // Dialog-Fenster "Farben" wird eingerichtet
        diaFarb = new DialogEi(this, " Farb-Einstellungen  (nicht minimieren -->)");
        diaFarb.setBackground(new Color(220,250,220));
        diaFarb.show();
        diaFarb.hide();
        diaFarb.resize(350, 520);
        diaFarb.move(300, 150);
        diaFarb.setLayout(gri);
        c.weightx = 1;
        c.weighty = 1;
        c.fill = c.NONE;
        c.gridwidth=c.REMAINDER;
        c.insets=new Insets(10,0,0,0);
        can = new CanEi(this);                // eigene Klasse, siehe unten
        can.resize(80, 80);
        can.setBackground(Color.black);
        gri.setConstraints(can, c);
        diaFarb.add(can);
        can.ini();
        c.fill = c.NONE;
        c.gridwidth=1;
        c.insets=new Insets(10,0,20,0);
        butF1 = new Button("Grund");
        gri.setConstraints(butF1, c);
        diaFarb.add(butF1);
        butF2 = new Button("Punkt");
        gri.setConstraints(butF2, c);
        diaFarb.add(butF2);
        c.anchor=c.EAST;
        butF3 = new Button(" -");
        gri.setConstraints(butF3, c);
        diaFarb.add(butF3);
        c.anchor=c.CENTER;
        tfF1 = new TextField("xxx",4);
        tfF1.setEditable(false);
        tfF1.setBackground(Color.white);
        gri.setConstraints(tfF1, c);
        diaFarb.add(tfF1);
        c.gridwidth=c.REMAINDER;
        c.anchor=c.WEST;
        butF4 = new Button("+");
        gri.setConstraints(butF4, c);
        diaFarb.add(butF4);
        c.anchor=c.CENTER;
        c.gridwidth=1;
        c.gridheight=1;
        c.weighty=7;
        c.insets=new Insets(0,0,0,0);
        c.fill=c.VERTICAL;
        sbF0 = new Scrollbar(1, 40, 0, 0, 255);
        sbF0.setBackground(Color.white);
        gri.setConstraints(sbF0, c);
        diaFarb.add(sbF0);
        Label lab = new Label("");
        gri.setConstraints(lab, c);
        diaFarb.add(lab);
        sbF1 = new Scrollbar(1, 40, 0, 0, 255);
        sbF1.setBackground(Color.white);
        gri.setConstraints(sbF1, c);
        diaFarb.add(sbF1);
        sbF2 = new Scrollbar(1, 40, 0, 0, 255);
        sbF2.setBackground(Color.white);
        gri.setConstraints(sbF2, c);
        diaFarb.add(sbF2);
        c.gridwidth=c.REMAINDER;
        sbF3 = new Scrollbar(1, 40, 0, 0, 255);
        sbF3.setBackground(Color.white);
        gri.setConstraints(sbF3, c);
        diaFarb.add(sbF3);
        c.gridheight=1;
        c.gridwidth=1;
        c.weighty=1;
        c.fill=c.NONE;                            
        lbh = new Label("xxxxxxxxxx");        // die xxx halten den Platz
        gri.setConstraints(lbh, c);           // für spätere Text-Zuweisungen
        diaFarb.add(lbh);
        Label lb14 = new Label("");
        gri.setConstraints(lb14, c);
        diaFarb.add(lb14);
        lbr = new Label("xxxxx");
        gri.setConstraints(lbr, c);
        diaFarb.add(lbr);
        lbg = new Label("xxxxx");
        gri.setConstraints(lbg, c);
        diaFarb.add(lbg);
        c.gridwidth=c.REMAINDER;
        lbb = new Label("xxxxx");
        gri.setConstraints(lbb, c);
        diaFarb.add(lbb);
        c.gridwidth=1;
        Label hel = new Label("Helligkeit");
        gri.setConstraints(hel, c);
        diaFarb.add(hel);
        lock = new Checkbox("lock");
        c.anchor=c.WEST;
        gri.setConstraints(lock, c);
        diaFarb.add(lock);
        c.anchor=c.CENTER;
        Label rot = new Label("rot  ");
        gri.setConstraints(rot, c);
        diaFarb.add(rot);
        Label gru = new Label("grün");
        gri.setConstraints(gru, c);
        diaFarb.add(gru);
        c.gridwidth=c.REMAINDER;
        Label bla = new Label("blau");
        gri.setConstraints(bla, c);
        diaFarb.add(bla);
        c.insets=new Insets(0,0,10,0);
        butFarb = new Button("   O K   ");
        gri.setConstraints(butFarb, c);
        diaFarb.add(butFarb);
    }

    // wird kurz aufgerufen, bevor ein neuer Durchlauf gestartet werden soll
    void initial() {
        removeAll();
        if (t != null) t.stop();            // immer erst Thread stoppen, bevor neu starten
        sch = new Schirm(this);
        setLayout(new GridLayout(1,1));
        add(sch);
        show();
        Warte.warte(this, 1, 300);                     // wartet hier 300 ms damit sich  
    }                                                  // in Ruhe das Fenster aufbauen kann
    void weiter1() {                                   // siehe unten, class Warte
        lauf = false;
        suspend = false;
        ende = false;
        aus_but3 = "noch was";
        gezeit = 0;
        gesp = 0;
        res_x = new int[anz];               // setzt die Werte auch gleichzeitig auf 0
        res_y = new int[anz];
        res_t = new int[anz];
        res_g = new int[anz];
        res_w = new int[anz];
        sch.ini1();
        sch.ini2();
        requestFocus();
    }

    // Dies ist die eigentliche Methode, die die Punkte auf dem Schirm aufblinken lässt
    // in Zusammenarbeit mit der Klasse "Schirm". Wird aufgerufen mit "t.start()"
    public void run() {
        dim = sch.size();
        anzeit = System.currentTimeMillis();
        for (i=0; i< anz ; i++) {
            int pause = p_min+dau+(int)((p_max-p_min)*Math.random());
            try {Thread.sleep(pause);}
            catch (Exception e) { }
            int x = 15+(int)((dim.width-dur-30)*Math.random());
            int y = 15+(int)((dim.height-dur-30)*Math.random());
            sch.blink(x,y,dur,c,dau);
            scharf = true;
            res_w[i] = pause;
            res_x[i] = x;
            res_y[i] = y;
            time = System.currentTimeMillis();
            // (jetzt wird i erhöht)
        }
        try {Thread.sleep((p_max+p_min)/2);}
        catch (Exception e) { }
        suspend = true;
        ende = true;
        i = i-1;
        gezeit = gezeit + (int)(System.currentTimeMillis() - anzeit);
        sch.fertig();
    }

    // setzt die Werte der Zeiten-Einstellungen wieder zurück
    void normZeit() {
        dau =    200;
        p_min    800;
        p_max    2400;
        anz =    10000;
        txZ[0].setText(Integer.toString(dau));
        txZ[1].setText(Integer.toString(p_min));
        txZ[2].setText(Integer.toString(p_max));
        txZ[3].setText(Integer.toString(anz));
    }

    // setzt die Schiebe-Regler auf die entsprechenden Positionen für eine Farbe
    // wenn das Farben-Fenster geöffnet wird
    void setBars(Color Buf) {
            rot  = Buf.getRed();
            grun = Buf.getGreen();
            blau = Buf.getBlue();
            hell = (rot+grun+blau);
            lbh.setText(Integer.toString(hell/3));
            lbr.setText(Integer.toString(rot));
            lbg.setText(Integer.toString(grun));
            lbb.setText(Integer.toString(blau));
            sbF0.setValue(255-hell/3);
            sbF1.setValue(255-rot);
            sbF2.setValue(255-grun);
            sbF3.setValue(255-blau);
    }

    // In den Methoden handleEvent(), action() und keyDown() werden die Ereignisse 
    // vom Haupt-Fenster und auch von den Dialog-Fenstern aufgefangen. Die Anweisungen 
    // stehen hier überwiegend direkt in den entsprechenden verzweigten if-Blöcken.
    public boolean handleEvent(Event evt) {
        // Action- und Key-Events weiterleiten
        if (evt.id == Event.ACTION_EVENT) { action(evt, evt.arg); }
        if (evt.id == 401 || evt.id == 403) { keyDown(evt, evt.key); }
        // Fenster schließen
        if (evt.id == Event.WINDOW_DESTROY && diaAn == false) {
            if (t != null) t.stop();
            hide();
        }
        else if (evt.id == Event.WINDOW_DESTROY && diaAn == true) {
            diaAn = false;
            diaZeit.hide();
            diaFarb.hide();
            diaTast.hide();
       }
        // ***** Farb Einstellungen *****
        // weitere Farb-Einstellungen in der action()-Methode
        if (evt.target instanceof Scrollbar) {
            if (evt.target == sbF1) {
                if (bolr == false) {            // dieser Block soll nur einmal 
                    g = grun+.1;                // pro Regler ausgeführt werden
                    b = blau+.1;
                    bolr = true;
                    bolg = false;    bolb = false;    bolh = false;
                }
                val = 255 - sbF1.getValue();    // unten ist doch immer Null? Oder? 
                rot  = val;
                if (lock.getState() == true) {
                    grun = (int)((hell-rot)/(b/g+1));
                    blau = (int)((hell-rot)/(g/b+1));
                }
                else
                    hell = rot+grun+blau;
            }
            if (evt.target == sbF2) {    
                if (bolg == false) {
                    r = rot+.1;
                    b = blau+.1;
                    bolg = true;
                    bolr = false;    bolb = false;    bolh = false;
                }
                val = 255 - sbF2.getValue();
                grun = val;
                if(lock.getState() == true) {
                    rot  = (int)((hell-grun)/(b/r+1));
                    blau = (int)((hell-grun)/(r/b+1));
                }
                else
                    hell = rot+grun+blau;
            }
            if (evt.target == sbF3) {
                if (bolb == false) {
                    g = grun+.1;
                    r = rot+.1;
                    bolb = true;
                    bolg = false;    bolr = false;    bolh = false;
                }
                val = 255 - sbF3.getValue();
                blau = val;
                if(lock.getState() == true) {
                    grun = (int)((hell-blau)/(r/g+1));
                    rot  = (int)((hell-blau)/(g/r+1));
                }
                else
                    hell = rot+grun+blau;
            }
            if (evt.target == sbF0) {
                if (bolh == false) {
                    r = rot+.1;
                    g = grun+.1;
                    b = blau+.1;
                    h = hell+.1;
                    bolh = true;
                    bolr = false;    bolg = false;    bolb = false;
                }
                val = 255 - sbF0.getValue();
                rot  = (int)(val*3/(g/r+b/r+1));
                grun = (int)(val*3/(r/g+b/g+1));
                blau = (int)(val*3/(r/b+g/b+1));
                hell = val*3;
            }
            // die Schieberegler und Labels werden auf ihre neuen Werte gesetzt,
            // hell verändert die Farben; rot, grün, blau beeinflussen sich gegenseitig
            if(rot  > 255)rot=255;
            if(grun > 255)grun=255;
            if(blau > 255)blau=255;
            if(rot  < 0)rot=0;
            if(grun < 0)grun=0;
            if(blau < 0)blau=0;
            int i = hell-rot-grun-blau;
            if (i >= -1 && i <= 2)
                lbh.setText(Integer.toString(hell/3));
            else
                lbh.setText(Integer.toString(hell/3)+" ("+Integer.toString((hell-i)/3)+")");
            lbr.setText(Integer.toString(rot));
            lbg.setText(Integer.toString(grun));
            lbb.setText(Integer.toString(blau));
            sbF0.setValue(255-hell/3);
            sbF1.setValue(255-rot);
            sbF2.setValue(255-grun);
            sbF3.setValue(255-blau);
            // das Farb-Muster wird gefärbt
            if (punktBol) cBuf = new Color(rot,grun,blau);
            else          bBuf = new Color(rot,grun,blau);
            can.fillRect(bBuf);
            can.fillOval(cBuf, dBuf);
        }                
        return false;
    }

    public boolean action(Event evt, Object arg) {
        // die Ereignise zu den entsprechenden Tasten weiterleiten, 
        // dort werden sie dann richtig verarbeitet
        if (evt.target == miStart) {  keyDown(evt, Event.F1); }
        if (evt.target == miWeit) {   keyDown(evt, keyStart); }
        if (evt.target == miAusw) {   keyDown(evt, keyHalt); }
        
        // ***** Zeit Einstellungen *****
        // Dialog-Fenster öffnen und Textfelder neu beschriften
        if (evt.target == miZeit) {
            lb.setText(" ");
            diaZeit.show();
            diaAn = true;
            txZ[0].setText(Integer.toString(dau));
            txZ[1].setText(Integer.toString(p_min));
            txZ[2].setText(Integer.toString(p_max));
            txZ[3].setText(Integer.toString(anz));
            iTxZ = 1;
            txZ[1].requestFocus();
        }
        // die neuen Werte übernehmen und prüfen
        if (evt.target == butZeit ||
                (evt.target instanceof TextField && diaZeit.isShowing())) {
            try {
                dau =    Integer.parseInt(txZ[0].getText());
                p_min =  Integer.parseInt(txZ[1].getText());
                p_max =  Integer.parseInt(txZ[2].getText());
                anz =    Integer.parseInt(txZ[3].getText());
            }
            catch (Exception ex) {
                System.out.println("falsche Eingabe im \"Zeiten\"-Fenster!"+ex);
                lb.setText("  falsche Eingabe !");
                return true;    // hier wird die action()-Methode vorzeitig abgebrochen
            }
            diaZeit.hide();
            if (dau <= 10) dau=10;
            if (p_min < 0) p_min=0;
            if (p_max < 0) p_max=0;
            if (anz <= 1)  anz=1;
            if (p_min > p_max) {
                int buf = p_min;
                p_min = p_max;
                p_max = buf;
            }
            if (t != null) t.stop();
            initial();            // mit veränderten Werten ist es besser, neu zu starten
        }
        // veränderte Werte zurücksetzen
        if (evt.target == reset) {
            lb.setText(" ");
            normZeit();
        }
        // ***** Tasten Einstellungen *****
        if (evt.target == miTast) {
            diaTast.show();
            diaAn = true;
        }
        // die Check-Box wird abgefragt und die "Key-Array-Nummer" gemerkt
        if (evt.target == butTast) {
            for (i=0; i< sTas.length; i++) {
                if (cb1[i].getState() == true) {
                    st = i;
                }
                if (cb2[i].getState() == true) {
                    ha = i;
                }
            }
            if (st != ha) {
                keyStart = key[st];
                strStart = sTas[st];
                keyHalt = key[ha];
                strHalt = sTas[ha];
                lb6.setText(" ");
                diaTast.hide();
            }
            else {
                lb6.setText("Tasten müssen verschieden sein!  O K ");
            }
        }
        // ***** Farb Einstellungen *****
        // weitere Farb-Einstellungen in der handleEvant()-Methode
        // Fenster anzeigen und aktuelle Werte setzen
        if (evt.target == miFarb) {
            diaFarb.show();
            diaAn = true;
            punktBol = true;
            can.ini();                        // zeigt das Muster-Quadrat
            cBuf = new Color(c.getRed(), c.getGreen(), c.getBlue()); // klonen, per Hand
            bBuf = new Color(back.getRed(), back.getGreen(), back.getBlue());
            dBuf = dur;
            setBars(cBuf);                    // setzt die Schiebe-Regler
            tfF1.setText(Integer.toString(dBuf));
        }
        // Punkt oder Hintergrund wählen, neue Werte vor-merken
        if (evt.target == butF1 && punktBol == true) {
            punktBol = false;
            cBuf = new Color(rot, grun, blau);
            setBars(bBuf);
        }
        if (evt.target == butF2 && punktBol == false) {
            punktBol = true;
            bBuf = new Color(rot, grun, blau);
            setBars(cBuf);
        }
        // Punkt-Größe wird verändert
        if (evt.target == butF3) {
            dBuf = dBuf-1;
            if (dBuf < 1) dBuf = 1;
            tfF1.setText(Integer.toString(dBuf));
            can.fillRect(bBuf);
            can.fillOval(cBuf, dBuf);
        }
        if (evt.target == butF4) {
            dBuf = dBuf+1;
            tfF1.setText(Integer.toString(dBuf));
            can.fillRect(bBuf);
            can.fillOval(cBuf, dBuf);
        }
        // neue Farben ins Haupt-Programm übernehmen
        if (evt.target == butFarb) {
            if (punktBol == true)    cBuf = new Color(rot, grun, blau);
            else                     bBuf = new Color(rot, grun, blau);
            c =    new Color(cBuf.getRed(), cBuf.getGreen(), cBuf.getBlue());
            back = new Color(bBuf.getRed(), bBuf.getGreen(), bBuf.getBlue());
            dur = dBuf;
            diaFarb.hide();
            initial();
        }
        // Kreuz versetzen, links, mitte, rechts
        // mit verändertem Kreuz ist ein Neu-Start sinnvoll
        if (evt.target == miLinks && kreuz != -1) {
            kreuz = -1;
            initial();
        }
        if (evt.target == miMitte && kreuz != 0) {
            kreuz = 0;
            initial();
        }
        if (evt.target == miRechts && kreuz != 1) {
            kreuz = 1;
            initial();
        }
        // Info anfordern, die HTML-Seite wird im Browser angezeigt
        if (evt.target == miInfo){
          hide();
// vorübergehend außer Kraft gesetzt
//          String a = "allgemein";
//          URL theURL;
//          try { theURL = new URL(aug.getDocumentBase(),"Auge.html#" + a);
//          aug.getAppletContext().showDocument(theURL);
//          }
//          catch (Exception ex) {System.out.println(ex+" "+ex.getMessage()); }
        }
        return true;
    }

    // Drei Tasten werden verwendet für Neu-Start, unterbrechen, weitermachen, auswerten,
    // je nach Status des Programms ändern sie oft ihre Bedeutung und Reaktionen, die sie
    // auslösen müssen; deshalb die vielen Boolean und if-Abfragen. 
    // Für den Anwender ist es bequemer, mit nur wenigen Tasten auszukommen
    public boolean keyDown(Event evt, int key) {
        if (key == keyStart && sch.isShowing()) {
            // Reaktions-Eingaben während eines Ablaufs
            if (lauf == true && suspend == false) {
                if (scharf == true) {
                    res_t[i-1] = (int)(System.currentTimeMillis() - time);
                    System.out.println("i= "+(i-1)+" res_t "+res_t[i-1]+" res_w "+res_w[i-1]);
                    scharf = false;
                }
                else {
                    gesp = gesp+1;
                    res_g[i-1]++;
                    System.out.println(" Gespenst "+gesp);
                }
            }
            // neu starten oder weitermachen
            else {
                if (suspend == false && ende == false) {
                    sch.ini1();
                    lauf = true;
                    if (t != null) t.stop();
                    t = new Thread(this);
                    t.start();
                    }
                if (suspend == true && ende == false) {
                    sch.ini1();
                    suspend = false;
                    anzeit = System.currentTimeMillis();
                    try {Thread.sleep(p_min);}
                    catch (Exception e) { }
                    t.resume();
                }
            }
        }
        // Schirm-Fenster wieder anzeigen und weitermachen
        if (key == keyStart && !sch.isShowing() && wert == true && ende == false) {
            wert = false;
            mehr();
        }
        // unterbrechen und dann auch auswerten
        if (key == keyHalt && lauf == true) {
            if (suspend == false) {
                if(t.isAlive()) t.suspend();
                suspend = true;
                gezeit = gezeit + (int)(System.currentTimeMillis() - anzeit);
                if (i >=2) i = i-2;
                sch.susp();
            }
            else {
                wert = true;
                wertung();                    // die Auswertung wird vorgenommen
            }
        }
        // Neu-Start, immer mit F1 (oder anderen Knöpfen)
        if (key == 1008) { // F1
            if (t != null) t.stop();
            initial();
        }
        // bewegt den Fokus im Zeiten-Fenster (in Java 1.1 nicht mehr nötig)
        if (key == 9) { //tab
            iTxZ++;
            if (iTxZ >= txZ.length) iTxZ=0;
            txZ[iTxZ].requestFocus();
        }
    return true;
    }
        // die Auswertung in der Klasse Auswert wird eingeleitet und angezeigt
        void wertung() {
            removeAll();
            aus = new Auswert(this);
            setLayout(new GridLayout(1,1));
            add(aus);
            show();
        }
        // die extra Auswertung "Korrelation" wird aufgerufen und angezeigt
        // ähnlich wie wertung()
        void korrel() {
            removeAll();
            kor = new Korrel(this);
            setLayout(new GridLayout(1,1));
            add(kor);
            show();
        }
        // vom Auswerte-Fenster aus wird der gleiche Versuch wieder aufgenommen
        void mehr() {
            removeAll();
            sch = new Schirm(this);
            setLayout(new GridLayout(1,1));
            add(sch);
            setTitle(" teste deine Augen");
            show();
            Warte.warte(this, 3, 300);               // wartet hier 300 ms damit sich  
        }                                            // in Ruhe das Fenster aufbauen kann
        void weiter3() {                             // siehe unten, class Warte
            sch.ini1();
            sch.susp();
        }
}

// erzeugt den (schwarzen) Schirm mit den blinkenden Punkten
class Schirm extends Canvas implements Runnable {

    Fenster f;
    Thread t;
    Graphics g;
    Dimension dim;                                   // Abmessungen des Schirms
    int mit_x, mit_y;                                // x und y für die Bildmitte
    int x; int y; int d; Color c; int zeit;          // aus "Fenster" übertragene Daten

    Schirm(Fenster f) {
        super();
        this.f = f;
        setBackground(f.back);
    }
    // "löscht" den Schirm und zeichnet das Kreuz (nur ein mal)
    void ini1() {
        dim = size();
        setBackground(f.back);
        g = getGraphics();
        g.setColor(f.back);
        g.fillRect(0, 0, dim.width, dim.height);
        mit_x = dim.width/2+(int)(dim.width*0.34*f.kreuz);
        mit_y = dim.height/2;
        g.setColor(Color.lightGray);
        g.drawLine(mit_x-8, mit_y, mit_x+8, mit_y);
        g.drawLine(mit_x, mit_y-8, mit_x ,mit_y+8);
    }
    // schreibt die drei Zeilen zentriert (nur ein mal)
    void ini2() {
        g = getGraphics();
        dim = size();
        String s1 = "Mit \""+f.strStart+"\" starten";
        String s2 = "und dann damit  jedes Blinken bestätigen";
        String s3 = "Mit \""+f.strHalt+"\" stoppen und auswerten";
        Font fo = new Font("Helvetica", Font.PLAIN, 16);
        FontMetrics fm = getFontMetrics(fo);
        int x1, x2, x3, la;
        la = fm.stringWidth(s1);
        x1 = (dim.width-la)/2;
        la = fm.stringWidth(s2);
        x2 = (dim.width-la)/2;
        la = fm.stringWidth(s3);
        x3 = (dim.width-la)/2;
        g.setFont(fo);
        g.setColor(Color.lightGray);
        g.drawString(s1, x1, mit_y+50);
        g.drawString(s2, x2, mit_y+80);
        g.drawString(s3, x3, mit_y+110);
    }
    // schreibt die drei Zeilen (ein mal)
    void susp() {
        String s1 = "angehalten";
        String s2 = "weiter mit \""+f.strStart+"\"";
        String s3 = "auswerten mit \""+f.strHalt+"\"";
        Font f = new Font("Helvetica", Font.PLAIN, 16);
        FontMetrics fm = getFontMetrics(f);
        int x1, x2, x3, la;
        la = fm.stringWidth(s1);
        x1 = (dim.width-la)/2;
        la = fm.stringWidth(s2);
        x2 = (dim.width-la)/2;
        la = fm.stringWidth(s3);
        x3 = (dim.width-la)/2;
        g.setFont(f);
        g.setColor(Color.lightGray);
        g.drawString(s1, x1, mit_y+50);
        g.drawString(s2, x2, mit_y+80);
        g.drawString(s3, x3, mit_y+110);
    }
    // schreibt die zwei Zeilen (ein mal)
    void fertig() {
        String s1 = "f e r t i g";
        String s3 = "auswerten mit \""+f.strHalt+"\"";
        Font f = new Font("Helvetica", Font.PLAIN, 16);
        FontMetrics fm = getFontMetrics(f);
        int x1, x2, x3, la;
        la = fm.stringWidth(s1);
        x1 = (dim.width-la)/2;
        la = fm.stringWidth(s3);
        x3 = (dim.width-la)/2;
        g.setFont(f);
        g.setColor(Color.lightGray);
        g.drawString(s1, x1, mit_y+50);
        g.drawString(s3, x3, mit_y+110);
    }
    // die Parameter für den Blink-Vorgang werden hier übergeben
    // direkt in run() kann man keine Parameter übergeben
    public void blink(int x, int y, int d, Color c, int zeit) {
        this.x=x; this.y=y; this.d=d; this.c=c; this.zeit=zeit;
        t = new Thread(this);
        t.start();
    }
    // ein mal blinken, bitte !
    public void run() {
        int x=this.x; int y=this.y; int d=this.d; int zeit=this.zeit;
        g.setColor(c);
        g.fillOval(x, y, d, d);
        try {Thread.sleep(zeit);}
        catch (Exception e) {}
        g.setColor(f.back);
        g.fillRect(x, y, d, d);
        g.setColor(Color.lightGray);
        g.drawLine(mit_x-8, mit_y, mit_x+8, mit_y);
        g.drawLine(mit_x, mit_y-8, mit_x, mit_y+8);
    }
    // verwandelt den Mausklick in ein Key-Event mit dem Schlüssel "-1"
    public boolean mouseDown(Event evt, int x, int y) {
        f.keyDown(evt, -1);
        return true;
    }
    // wird das Fenster verändert, werden die jeweils aktuellen Schriftzüge erneuert
    public void paint(Graphics g) {
        if (f.suspend == true) {
            ini1();
            susp();
        }
        if (f.lauf == false && f.suspend == false) {
            ini1();
            ini2();
        }
        requestFocus();
    }
}

// hier werden die Daten ausgewertet und am Monitor aufbereitet angezeigt
class Auswert extends Panel {

    Fenster f;
    Graphics g;
    Dimension dim, dimS;                           // Abmessungen des Schirms
    Button but1, but2, but3;                       // Knöpfe auf dem Auswert-Schirm
    Color c = Color.red;                           // Farbe der Diagramm-Punkte
    int mit_x, mit_y;                              // x und y für die Bildmitte
    int inx, iny, ind;                             // Rand oben und links und mitte
    int nicht;                                     // nicht gesehene Punkte
    int dopp;                                      // doppelt gesehene Punkte
    int rzeit;                                     // mittlere Reaktionszeit
    int res_x[]; int res_y[]; int res_t[]; int res_g[]; int res_w[]; int i_in;
                                                   // Daten aus "Fenster" übernommen
    // Daten übertragen , Knöpfe einrichten
    Auswert(Fenster f) {
        super();
        this.f = f;
        this.res_x = f.res_x;
        this.res_y = f.res_y;
        this.res_t = f.res_t;
        this.res_g = f.res_g;
        this.res_w = f.res_w;
        dim = f.dim;
        i_in = f.i;
        setBackground(new Color(255,245,206));
        but1 = new Button("  weiter  ");
        but2 = new Button("Neu-Start");
        but3 = new Button(f.aus_but3);
        add(but1);
        add(but2);
        add(but3);
    }

    // Farbe und Abstände festlegen
    void ini() {
        c = f.c;
        if ((c.getRed()+c.getGreen()+c.getBlue()) > 510) c = Color.gray;
        g = getGraphics();
        dimS = size();
        inx = (int)(dimS.width*0.05);
        iny = (int)(dimS.width*0.05);
        if (iny< 20) iny=20;
        ind = (int)(dimS.width*0.05);
    }

    // das Netzhaut-Abbild mit den gesehenen Punkten wird gemacht
    void retina() {
        // Quadrat und Kreuzchen werden gezeichnet
        g.setColor(Color.white);
        g.fillRect(inx, iny, dim.width/2, dim.height/2);
        g.setColor(Color.black);
        g.drawRect(inx, iny, dim.width/2, dim.height/2);
        mit_x = dim.width/4+(int)(dim.width*0.17*f.kreuz)+inx;
        mit_y = dim.height/4+iny;
        g.setColor(new Color(128,128,128));
        g.drawLine(mit_x-5, mit_y, mit_x+5, mit_y);
        g.drawLine(mit_x, mit_y-5, mit_x ,mit_y+5);
        // Punkte werden gezeichnet und entsprechend gefärbt
        int dur = f.dur/2;
        if (dur < 4) dur = 4;
        for (int i=0; i<=i_in; i++) {
            if (res_t[i] == 0) {
                g.drawOval(res_x[i]/2+inx, res_y[i]/2+iny, dur+1, dur+1);
            }
        }
        g.setColor(c);
        for (int i=0; i<=i_in; i++) {
            if (res_t[i] != 0) {
                g.fillOval(res_x[i]/2+inx, res_y[i]/2+iny, dur, dur);
            }
        }
    }

    // das Reaktions-Diagramm wird gemacht
    void graph() {
        // Lage und größe festlegen
        int posx = inx;
        int posy = 2*iny+dim.height/2+25;
        int lang = dimS.width-2*inx;
        int hoch = dimS.height-posy-25;
        Color gr = new Color(255,130,0);
        g.setColor(Color.white);
        g.fillRect(posx, posy, lang, hoch);
        g.setColor(Color.black);
        g.drawRect(posx, posy, lang, hoch);
        String s1 = "Reaktions-Verlauf :";
        Font fo = new Font("Helvetica", Font.BOLD, 14);
        g.setFont(fo);
        g.drawString(s1, inx, posy-8);
        // mittlere Reaktions-Zeit und (nicht)gesehene Anzahl ermitteln
        int sum=0; int zahl=0;
        nicht = 0;
        dopp = 0;
        for (int i=0; i<=i_in; i++) {
            if (res_t[i] > 0) {
                sum = sum + res_t[i];
                zahl = zahl + 1;
            }
            if (res_t[i] == 0) { nicht++; }
            if (res_g[i] >= 1) { dopp++; }
        }
        int tmax = 0;
        if (zahl != 0) {
            tmax = 2*(sum/zahl);
            rzeit = sum/zahl;
        }
        else { tmax = 1000; }
        // Diagramm-Faktoren für X- und Y-Achse festlegen
        double fy = 0;
        if (tmax > 0) fy = (hoch-20)/(double)(tmax);
        double fx = 0; 
        if (i_in >1) fx = (lang-45)/(double)(i_in);
        // die Kurve zeichnen
        g.setColor(gr);
        int zt1, zt2;                    // vorherige Zeit, diese Zeit
        int x1, x2, y1, y2;              // Parameter für jeden Strich
        for (int i=1; i<=i_in; i++) {
            boolean leer = false;        // für nicht gesehene Punkte
            zt2 = res_t[i];
            if (zt2 > (int)(tmax*1.2)) zt2=(int)(tmax*1.2);
            if (zt2 == 0) {zt2=tmax/2; leer=true;}
            zt1 = res_t[i-1];
            if (zt1 == 0) zt1 = tmax/2;
            if (zt1 > (int)(tmax*1.2)) zt1=(int)(tmax*1.2);
            x1 = (int)((i-1)*fx)+posx+35;
            x2 = (int)(i*fx)+posx+35;
            y1 = posy+hoch-(int)(zt1*fy)-10;
            y2 = posy+hoch-(int)(zt2*fy)-10;
            g.drawLine(x1, y1, x2, y2);
            // "nicht gesehen" markieren
            if (leer == true) {
                g.setColor(Color.black);
                g.drawOval(x2-2, y2-2, 5, 5);
                g.setColor(Color.white);
                g.fillOval(x2-1, y2-1, 3, 3);
                g.setColor(gr);
            }
            // "doppelt gesehen" markieren
            if (res_g[i] >= 1) {
                g.setColor(Color.blue);
                g.fillOval(x2-2, y2-2, 5, 5);
                g.setColor(gr);
            }
        }
        // Lienien und Beschriftung des Diagramms
        fo = new Font("TimesRoman", Font.PLAIN, 11);
        g.setFont(fo);
        FontMetrics fm = getFontMetrics(fo);
        g.setColor(Color.black);
        String st = Integer.toString(tmax);
        g.drawString(st, posx+5, posy+14);
        st = Integer.toString(tmax/2);
        g.drawString(st, posx+5, posy+hoch/2+4);
        st = "    0";
        g.drawString(st, posx+5, posy+hoch-6);
        st = "in ms";
        g.drawString(st, posx+5, posy+hoch-20);
        st = Integer.toString(i_in+1);
        g.drawString(st, posx+lang-fm.stringWidth(st)-12, posy+hoch-12);
        st = "1";
        g.drawString(st, posx+38, posy+hoch-12);
        g.setColor(Color.lightGray);
        g.drawLine(posx+35, posy+10, posx+55, posy+10);
        g.drawLine(posx+35, posy+hoch/2, posx+55, posy+hoch/2);
        g.drawLine(posx+35, posy+hoch-10, posx+35, posy+hoch-25);
        g.drawLine(posx+27, posy+hoch-10, posx+lang-5, posy+hoch-10);
        g.drawLine(posx+lang-10, posy+hoch-10, posx+lang-10, posy+hoch-25);
    }

    // die "Zahlen" anzeigen und genaues Layout festlegen (per Hand) 
    void daten() {
        // Lage und Größe festlegen, Rechteck zeichnen
        int x = inx+dim.width/2+ind;
        int y = iny+dim.height/4;
        int w = dimS.width-2*inx-ind-dim.width/2;
        int h = dim.height/4;
        g.setColor(Color.white);
        g.fillRect(x, y, w, h);
        g.setColor(Color.black);
        g.drawRect(x, y, w, h);
        // Bezeichnungen der Daten anzeigen
        String s1 = "Anzahl Blinker:";
        String s2 = "Dauer des Versuchs:";
        String s3 = "nicht gesehen:";
        String s4 = "zuviel gesehen:";
        String s5 = "mittlere Reaktionszeit:";
        Font fo = new Font("TimesRoman", Font.PLAIN, 13);
        g.setFont(fo);
        int a = (h-100)/2;
        if (a <= 0) a=0;
        g.drawString(s1, x+8, y+a+14);
        g.drawString(s2, x+8, y+a+34);
        g.drawString(s3, x+8, y+a+54);
        g.drawString(s4, x+8, y+a+74);
        g.drawString(s5, x+8, y+a+94);
        // die Daten selbst anzeigen
        s1 = Integer.toString(f.i+1);
        // Uhrzeit-Format realisieren
        int sek = (f.gezeit/1000)%60;
        int min = (f.gezeit/1000)/60;
        if (min == 0)
            s2 = (Integer.toString(sek)+"  s");
        if (min > 0)
            s2 = (Integer.toString(min)+" m  "+Integer.toString(sek)+" s");
        // die übrigen Daten anzeigen
        s3 = Integer.toString(nicht);
        s4 = Integer.toString(dopp);
        s5 = (Integer.toString(rzeit)+"  ms");
        g.setColor(new Color(0,160,0));
        fo = new Font("Helvetica", Font.BOLD, 13);
        g.setFont(fo);
        g.drawString(s1, x+135, y+a+14);
        g.drawString(s2, x+135, y+a+34);
        g.drawString(s3, x+135, y+a+54);
        g.drawString(s4, x+135, y+a+74);
        g.drawString(s5, x+135, y+a+94);
        // Überschrift anzeigen
        s1 = "Ergebnis in Zahlen:";
        fo = new Font("Helvetica", Font.BOLD, 14);
        g.setFont(fo);
        g.setColor(Color.black);
        g.drawString(s1, x, y-8);
    }
    
    // die übrige Beschriftung der Auswert-Seite und die Knöpfe
    void schrift() {
        String s1 = "Auswertung";
        String s4 = "Das wurde gesehen:";
        String s2 = "  = gesehene Punkte         ";
        String s3 = "  = nicht gesehene Punkte";
        String s5 = "  = nicht gesehene Punkte        ";
        String s6 = "  = doppelt gesehene Punkte";
        Font fo;
        FontMetrics fm;
        // Überschrift schreiben, variable Größe und Lage
        fo = new Font("Helvetica", Font.PLAIN, dimS.width/21);
        g.setFont(fo);
        fm = getFontMetrics(fo);
        int x1, la;
        int w = (dimS.width-2*inx-ind-dim.width/2)-fm.stringWidth(s1);
        if (w < -2*ind) w = -2*ind;
        int x = inx+dim.width/2+ind+w/2;
        g.setColor(Color.black);
        g.drawString(s1, x, (int)(dimS.height*0.03)+fm.getAscent());
        // die übrigen Überschriften schreiben
        fo = new Font("Helvetica", Font.BOLD, 14);
        g.setFont(fo);
        g.setColor(Color.black);
        g.drawString(s4, inx, iny-8);
        // die übrigen Beschriftungen schreiben
        fo = new Font("TimesRoman", Font.PLAIN, 11);
        fm = getFontMetrics(fo);
        int dur = f.dur/2;
        if (dur > 15) dur=15;
        if (dur < 4) dur = 4;
        int y  = iny+dim.height/2+fm.getAscent()+8;
        int yd = y-(fm.getAscent()+dur)/2;
        g.setFont(fo);
        g.drawString(s2, inx+dur, y-2);
        g.drawString(s3, inx+fm.stringWidth(s2)+dur*2, y-2);
        g.drawString(s5, inx+5, dimS.height-8);
        g.drawString(s6, inx+fm.stringWidth(s5)+10, dimS.height-8);
        // die Symbole der Diagramme anbringen
        g.setColor(c);
        g.fillOval(inx, yd, dur, dur);
        g.setColor(Color.gray);
        g.drawOval(inx+fm.stringWidth(s2)+dur-1, yd-1, dur+1, dur+1);
        g.setColor(Color.black);
        g.drawOval(inx, dimS.height-13, 5, 5);
        g.setColor(Color.blue);
        g.fillOval(inx+fm.stringWidth(s5)+5, dimS.height-13, 5, 5);
        // Lage und Größe der Knöpfe festlegen
        but1.reshape(dimS.width-inx-125, iny+dim.height/8-13, 55, 26);
        but2.reshape(dimS.width-inx-55, iny+dim.height/8-13, 55, 26);
        but3.reshape(dim.width/2+inx+ind, iny+dim.height/8-13, 55, 26);
    }

    // Reaktionen der drei Knöpfe 
    public boolean action(Event evt, Object arg) {
        // werden weitergeleitet und später wie die Key-Events behandelt
        if (evt.target == but1)
            f.keyDown(evt, f.keyStart);
        if (evt.target == but2)
            f.keyDown(evt, Event.F1);
        // ruft das Korrelations-Fenster auf (auf Umwegen, über "f")
        if (evt.target == but3) {
            f.aus_but3 = "Korrelat.";
            f.korrel();
        }
        return false;
    }

    // alle zeichnenden Methoden werden hier nochmals (und erstmals) aufgerufen
    public void paint(Graphics g) {
        ini();
        retina();
        graph();
        daten();
        schrift();
        requestFocus();
    }
}

// ist für die zusätzliche Korrelations-Auwertung und -Anzeige zuständig
class Korrel extends Panel {

    Fenster f;
    Dimension dim;
    Graphics g;
    Button but4;
    int inx1, inx2, iny1, iny2;            // Mindest-Einrückungen

    // Referenzen zuweisen, Knopf einfügen
    Korrel(Fenster f) {
        super();
        this.f = f;
        setBackground(new Color(255,245,206));
        but4 = new Button("zurück");
        add(but4);   // ruft indirekt auch paint() auf, daher darf paint(), 
                     // (auch indirekt) nicht add() aufrufen
    }

    // die Haupt-Methode, erstellt die Korrelations-Anzeige
    void korrel() {
        // Größe und Position festlegen, Rechteck zeichnen
        dim = size();
        g = getGraphics();
        inx1 = 200;
        inx2 = (int)(dim.width*0.10);
        iny1 = (int)(dim.width*0.10);
        if (iny1 < 25) iny1 = 25;
        iny2 = (int)(dim.width*0.10);
        if (iny2 < 40) iny2 = 40;
        int lang = Math.min(dim.width-inx1-inx2, dim.height-iny1-iny2);
        int hoch = lang;
        int posx = dim.width-lang-inx2;
        int posy = iny1;
        g.setColor(Color.white);
        g.fillRect(posx ,posy , lang, hoch);
        g.setColor(Color.black);
        g.drawRect(posx, posy, lang, hoch);
        but4.reshape(35, dim.height-60, 55, 26);
        // Punkte eintragen und farblich kennzeichnen
        double fx = 0;
        if (f.p_max-f.p_min > 0) fx = (lang)/(double)(f.p_max-f.p_min);
        double fy = 0; 
        if (f.aus.rzeit*2 > 0) fy = (hoch)/(double)(f.aus.rzeit*2);
        int max = f.aus.rzeit*2;
        int x, y;
        int r_t;
        for (int i=0; i<=f.i; i++) {
            g.setColor(new Color(180,140,0));
            if (i >=1) if (f.res_g[i-1] > 0) g.setColor(new Color(110,110,255));
            r_t = f.res_t[i];
            if (r_t >= max) r_t = max;
            if (r_t > 0) {
                x = posx+(int)((f.res_w[i]-f.p_min-f.dau)*fx)-3;
                y = posy+hoch-(int)(r_t*fy)-3;
                g.fillOval(x, y, 6, 6);
            }
            if (f.res_t[i] == 0) {
                x = posx+(int)((f.res_w[i]-f.p_min-f.dau)*fx)-3;
                y = posy+hoch-10;
                g.drawOval(x, y, 6, 6);
            }
        }
        // Beschriftung Titel, variable Größe und zentriert
        Font fo = new Font("Helvetica", Font.BOLD, (posx-40)/17);
        FontMetrics fm = getFontMetrics(fo);
        g.setFont(fo);
        g.setColor(Color.black);
        String s[] = {
            "K o r r e l a t i o n",
            " ",
            "zwischen Reaktions-Zeit",
            "und Blink-Pause"
        };
        for (int i=0; i< s.length; i++) {
            g.drawString(s[i], (posx-40-fm.stringWidth(s[i]))/2,
                posy+(fm.getHeight()+6)*(i+1));
        }
        // Beschriftung Diagramm und Achs-Zahlen
        fo = new Font("TimesRoman", Font.PLAIN, 11);
        fm = getFontMetrics(fo);
        String s1 = Integer.toString(f.p_min);
        String s2 = Integer.toString((f.p_max+f.p_min)/2);
        String s3 = Integer.toString(f.p_max);
        String s4 = "Blink-Pause in ms";
        g.setFont(fo);
        g.setColor(Color.black);
        g.drawString(s1, posx-fm.stringWidth(s1)/2, posy+hoch+24);
        g.drawString(s2, posx+lang/2-fm.stringWidth(s2)/2, posy+hoch+24);
        g.drawString(s3, posx+lang-fm.stringWidth(s3)/2, posy+hoch+24);
        g.drawString(s4, posx+lang-fm.stringWidth(s4)+fm.stringWidth(s3)/2, posy+hoch+38);
        s1 = Integer.toString(0);
        s2 = Integer.toString(f.aus.rzeit);
        s3 = Integer.toString(f.aus.rzeit*2);
        s4 = "Reaktions-Zeit in ms";
        g.drawString(s1, posx-14-fm.stringWidth(s1), posy+hoch+4);
        g.drawString(s2, posx-14-fm.stringWidth(s2), posy+hoch/2+4);
        g.drawString(s3, posx-14-fm.stringWidth(s3), posy+4);
        g.drawString(s4, posx-14-fm.stringWidth(s3), posy-11);
        // die kleinen Striche zeichnen
        g.drawLine(posx, posy+hoch, posx, posy+hoch+10);
        g.drawLine(posx+lang/2, posy+hoch, posx+lang/2, posy+hoch+10);
        g.drawLine(posx+lang, posy+hoch, posx+lang, posy+hoch+10);
        g.drawLine(posx-10, posy+hoch, posx, posy+hoch);
        g.drawLine(posx-10, posy+hoch/2, posx, posy+hoch/2);
        g.drawLine(posx-10, posy, posx, posy);
    }

    // der "zurück"-Knopf ruft wieder die Auswertung auf
    public boolean action(Event evt, Object arg) {
        if (evt.target == but4) f.wertung();
        return true;
    }

    // wird das Fenster verändert, geschieht korrel() einfach noch mal
    public void paint(Graphics g) {
        korrel();
        requestFocus();
    }
}

// dies ist das kleine Muster-Rechteck im Farb-Fenster
// ich hab es nicht geschafft, die Anweisungen zum Zeichnen zu realisieren,
// ohne eine eigene Klasse für dieses Objekt anzulegen, jetzt kann man 
// indirekt die draw..() und fill..()-Methoden hierfür aufrufen
class CanEi extends Canvas {
    Graphics g;
    Fenster f;
    CanEi(Fenster f) {
        this.f = f;
    }
    void ini() {
        g = getGraphics();
    }
    void fillOval(Color c, int d) {
        g.setColor(c);
        g.fillOval((size().width-d)/2, (size().height-d)/2, d, d);
    }
    void fillRect(Color c) {
        g.setColor(c);
        g.fillRect(0,0,80,80);
    }
    public void paint(Graphics g) {
        fillRect(f.bBuf);
        fillOval(f.cBuf, f.dBuf);
    }
}

// Wird nur Thread.sleep() aufgerufen, so wartet das Programm anstandslos sine Zeit,
// aber das Schlafen geschieht nicht in einem Thread (nebenläufig). Das heißt, dass
// während dieser Zeit das Applet keine anderen Aktivitäten ausführen kann, zum Beispiel
// Tastatur-Ereignisse oder anstehende paint-Befehle.
// Da aber in jeder Klasse nur eine run()-Methode frei ist, gibt es hier die Warte-Klasse,
// nur damit sleep() auch wirklich als Thread ausgeführt wird.
// Später kehrt die Steuerung je nach Ziel-Schlüssel wieder zurück, wo sie herkam.

class Warte extends Thread {

    static Thread    t;
    static Fenster   f;
    static int       ziel;
    static int       dauer;

    // Parameter werden übergeben, mit run() kann man das nicht
    public static void warte(Fenster f_in, int ziel_in, int dauer_in) {
        f = f_in;
        ziel = ziel_in;
        dauer = dauer_in;
        Warte w = new Warte();
        t = new Thread(w);
        t.start();
    }

    public void run() {
        try {Thread.sleep(dauer);}
        catch (Exception e) { }
        if (ziel==1) f.weiter1();
        if (ziel==3) f.weiter3();
    }
}

/* Die Dialogfenster sind nicht von der Standard Klasse "Dialog", sondern eigenständige
   Frames "DialogEi" und geben ihre Events wohldefiniert weiter. Ich hatte sie nachträglich
   umgewandelt, damit auch die Version JAVA 1.1 damit etwas anfangen kann.   */
class DialogEi extends Frame {
    Fenster f;
    DialogEi(Fenster f, String str) {
        super(str);
        this.f = f;
    }
    public boolean handleEvent(Event evt) {
        f.handleEvent(evt);
        return false;
    }
}


zum Applet