# Applet Frage (Animation) Double Buffer?



## JavaEc (30. Mai 2004)

Möchte in Java eine Analoguhr programmieren, jedoch weiß ich nicht so genau wie ich die Bewegungen der Zeiger realisieren soll. Nachdem ich das Ziffernblatt entworfen hatte (g.drawArc (0,0,400,400,360,0) und alle drei Zeiger eingezeichnet waren (die Markierungen für die Minutenschritte und Fünfminutenschritte sind auch schon implementiert worden) muss ich jetzt noch die Zeiger irgendwie in Bewegung bekommen. Also z.B. der Sekundenzeiger muss jede Sekunde vorwärts springen und nach sechzig Sekungen muss der Minutenzieger eine Minute weiter...
Was könnte ich zur Realisierung machen?

Wie kann ich bei Java eigendlich die aktuelle Uhrzeit in das Applet implementieren?


----------



## Roar (30. Mai 2004)

mit einem javax.swing.Timer kannst du deine uhr aktualisieren, für das datum schau dir java.util.Calendar und GregorianCalendar an-


----------



## Guest (30. Mai 2004)

Ok, danke, aber wie bekomme ich die Zeiger in Bewegung?


----------



## Maks (30. Mai 2004)

um den Uhrzeiger vorwärts zu bewegen kannst Du immer eine Linie vom Mittelpunkt des Uhrkreises zum Kreisbogen ziehen.
einzelne Punkte auf dem Uhrkreis kann man mit dem Satz von Pythagoras ausrechnen (sinus/cosinus Berechungen in Java solltest Du auch mal probiert haben)

Dann kann man den 360 grad Kreis einfach in 60 Teile einteilen 360/60=6, also hast Du dann für alle 6 Grad eine Linie zu zeichnen, die einfach wieder gelöscht werden muß, wenn der Zeiger weiterspringt.


----------



## Guest (30. Mai 2004)

Die Minutenstriche und die Fünfminutenstriche habe ich in das Ziffernbalatt schon implementiert. Die Ausrichtung der einzelnnen Zeiger auf eine bestimmte Stelle funktioniert ebenfalls. 
Wie kann ich den die Position des Zeigers löschen? Muss ich da nicht festlegen, das der Zeiger jede Sekunde gelöscht werden soll und jede Sekunde wieder auf einer anderen Stelle dargestellt werden soll?


----------



## Roar (30. Mai 2004)

du zeichnest deine uhr einfach jede sekunde neu


----------



## Guest (30. Mai 2004)

Wie und wo genau kann ich das festlegen?


----------



## Roar (30. Mai 2004)

Roar hat gesagt.:
			
		

> mit einem javax.swing.Timer kannst du deine uhr aktualisieren



 :autsch:  :?:


----------



## Guest (4. Jun 2004)

Wie genau geht das ? 


Habe auf der Javaseite mal geschaut und das hier gefunden: 


```
int delay = 1000; //milliseconds 
  ActionListener taskPerformer = new ActionListener() { 
      public void actionPerformed(ActionEvent evt) { 
          //...Perform a task... 
      } 
  }; 
  new Timer(delay, taskPerformer).start();
```


Bei Preform a task habe ich mal 

```
g..drawLine (200,200,400,50);
```

eingetragen, aber wenn ich das Applet starte wir der Strich nicht angezeigt. 

Wie mach ich das jetzt nun genau, dass der Strich 1 Sekunde angezeigt wird und dann nicht?


----------



## L-ectron-X (4. Jun 2004)

Hast Du es schon mit

```
repaint();
```
 versucht?
Damit wird die paint()-Methode aufgerufen und alle Änderungen werden neu gezeichnet. Bevor Du die Uhr neu zeichnest, zeichnest Du den Hintergrund neu. Entweder in dem Du mit 

```
clearRect(int x, int y, int width, int height)
```
einen bestimmten Bereich des Applets löscht, oder in der paint()-Methode, in der Du den Hintergrund jedesmal zu aller erst zeichnest.


----------



## Guest (5. Jun 2004)

Danke für deine Antwort!

Wenn ich "repaint" benutze fängt meine Uhr stark an zu flackern. Kann ich da irgendwie noch einen Parameter angeben der Festlegt wie viel mal in der Sekunde die Uhr aktualisiert werden soll?

Ich weiß nicht genau wie das Applet abgearbeitet wird. Habe zuerst eine Methode paint erstellt, wenn ich gedoch jetzt eine andere Methode erstelle wird diese nicht beachtet. Es wird immer nur die erste Methode ausfegührt. Wenn ich ohne Applets programmiere kann ich ja in der main - Methode die anderen aufrufen. Wie funktioniert das bei Applets?


----------



## L-ectron-X (5. Jun 2004)

Hm ja, das Flackern kommt zustande, weil jedes Mal vor dem Zeichnen der Uhr der Hintergrund gezeichnet wird, und somit die Uhr komplett gelöscht wird. Man kann das etwas beeinflussen, in dem man die update()-Methode überschreibt und sich die paint()-Methode möglichst nur auf's Zeichnen konzentriert. Das heißt, keinerlei Berechnungen in der paint()-Methode, sie muss sehr schnell sein. Manchmal liegt es auch nur einfach an der Reihenfolge, des Zeichnens. Außerdem ist der Einsatz eines Puffers zu empfehlen.
Die update()-Methode ist die Reaktion auf repaint(). Also füge sie doch mal ins Applet ein und experimentiere etwas mit paint() und update().

```
private Graphics offscreen; // Speicher internes "Zeichenblatt"
private Image buffer; // Pufferbild
...

public void init() {
  buffer = createImage(width, height); //
  offscreen = buffer.getGraphics();
...
}

public void start() {
  repaint() //kann u. U. nötig sein
}

public void update(Graphics g) {
  offscreen.setColor(getBackground());
  offscreen.fillRect(0, 0, width, height); //Hintergrund mit Hintergrundfarbe füllen
  //an dieser Stelle alles auf das offscreen image zeichen und damit das
  //Bild im Hintergrund zum Zeichnen vorbereiten.
  ...

  offscreen.setColor(getForeground()); //Fordergrundfarbe einstellen
  //Texte auf's offscreen image schreiben
  offscreen.drawString("Text", 20, 50);
  ...

  //zum Schluss fertiges Bild auf den Bildschirm kopieren
  g.drawImage(buffer, 0, 0, this);
  
  paint(g);
}
```
So etwas in der Art könnte helfen. Diese Methode nenn man Double Buffering, also das schreiben in ein Speicher internes Bild (Offscreen Image).

Bei Applets wird in der init()-Methode zunächst erst mal alles initialisiert. Sie kommt dann der main()-Methode von Applikationen in ihrer Funktion recht nahe. Die eigentliche Ausführung des Applets kann dann auch in der start()-Methode erfolgen, die ihrerseits wieder private Methoden oder Objekte aufrufen und benutzen kann. Möglich ist es auch mit Threads zu arbeiten.


_Edit: Am 21.07.2004 modifiziert. Code vom Double Buffering verbessert.
Noch ein paar Suchbegriffe für die Forum-Suchfunktion: Applet flackern, Grafik, Image, Bilder, Buffer, bewegen, verschieben_


----------



## Guest (5. Jun 2004)

Danke !!!

Jetzt müsste ich nur noch wissen, wie ich einstellen kann das ein Appletupdate jede Sekunde oder jede zweite Sekunde erfolgt. Der Zeider muss ja eine Sekunde lang stehen bleiben und dann verschwinden. Dann sollte 6° später der nächste Zeiger eine Sekunde lang stehn bleiben und dann wieder verschwinden...

Wie könnte ich das jetzt festlegen?


----------



## L-ectron-X (5. Jun 2004)

Um das für Deine Zeiger zu programmieren, brauchst Du auf jeden Fall einen Thread, der jede Sekunde die aktuelle Zeit besorgt und an eine Methode weiter reicht, die das Ergebnis für Deine Zeigerstellung berechnet. Danach zeichnest Du die aktuelle Zeigerstellung.


----------



## Guest (5. Jun 2004)

Mit Threads kanne ich mich nicht so gut aus. Es müsste aber auch ohne irgendwie funktionieren.

Auf der Javaseite gibt es diese Beispiel:


```
int delay = 1000; //milliseconds 
  ActionListener taskPerformer = new ActionListener() { 
      public void actionPerformed(ActionEvent evt) { 
          //...Perform a task... 
      } 
  }; 
  new Timer(delay, taskPerformer).start();
```



Dort kann man doch die Sekunden einstellen. Wie könnte ich das jetzt lösen? Beim Beispiel bedarf es noch an Erklärungshilfe!


----------



## L-ectron-X (5. Jun 2004)

Hm, mag funktionieren, weiß ich nicht. Du kannst aber folgende Klasse rein theoretisch in Dein Applet als innere Klasse programmieren. Also einfach in den Klassenrumpf des Applet einfügen. Ob's funktioniert, weiß ich jetzt aber auch nicht, ist nur so 'ne Idee.

```
ZeitGeber zg;
...

class ZeitGeber extends Thread {
  public void run() {
    while(!isInterrupt()) {
      ...
      repaint();
      try {
        Thread.sleep(1000);
      }
      catch(InterruptedException e) {
         interrupt();
      }
    }
  }
}

public void init() {
...
  zg = new ZeitGeber();
}

public void start() {
...
  if(zg == null) {
    zg = new ZeitGeber();
  }
  zg.start();
}

public void stop() {
  zg.interrupt();
  zg = null;
}
```
Kannst Du ja mal probieren, könnte funktionieren.


----------



## Guest (6. Jun 2004)

Danke, aber mit deiner Lösung habe ich Probleme.

Ich habe mich mal ein bisschen mit dem TimerTask auseinander gesetzt.


```
public class TimerTaskDemo extends Applet
{
  public void init ()
  {
    Timer timer = new Timer();
    // nach 2 Sek geht's los
    timer.schedule( new Task(), 2000 );
    // nach 1 Sek geht's los und dann alle 5 Sekunden
    timer.schedule( new Task(), 1000, 5000 );
  }
}


class Task extends TimerTask
{
  public void run()
  {
    System.out.println( "Ausgabe" );
  }
}
```

Ausgegeben wir immer "Ausgabe" jede 5 Sekunden...


Ich weiß jetzt jedoch nicht genau wie ich die Methode Paint implementieren muss.




```
public void paint (Graphics g)
{
g.drawLine (200,200,400,50)
}
```




Wie kann ich jetzt nun die Methode paint implementieren, anstelle von System.out.println ?


----------



## Illuvatar (6. Jun 2004)

Die paint-Methode wird ständig vom Betriebssystem (oder so) aufgerufen, d.h. du musst in der run-Methode ein Objekt verändern, dass in der paint-Methode gezeichnet wird bzw. eine Variable hochzählen wo ein Strich gezeichnet wird.


----------



## L-ectron-X (6. Jun 2004)

Illuvatar hat gesagt.:
			
		

> Die paint-Methode wird ständig vom Betriebssystem (oder so) aufgerufen


paint() ist eine "automatische" Methode, die von der VM aufgerufen wird. Z.B. wenn man die Fenstergröße ändert, oder die Maus über das Applet bewegt.
Eigentlich sollte das Ganze funktionieren, wenn Du in der run()-Methode die repaint()-Methode aufrufst.
Die run()-Methode enthält den Code, den der Thread abzuarbeiten hat.


----------



## Guest (6. Jun 2004)

Danke für eure Antworten!

Repaint() einfach in die run-Methode einfügen geht nicht.

Wie mache ich das jetzt genau was Illuvatar vorgeschlagen hat?
Gibt es vielleicht noch andere Lösungsvorschläge?


----------



## Illuvatar (6. Jun 2004)

Du machst drei int-Variablen, in denen die Stellung der Zeiger beschrieben wird, und jenachdem zeichnest du das ganze dann in der paint-Methode.


----------



## Guest (6. Jun 2004)

Muss ich nicht vier Variablen anlegen?

Wo muss ich die drei/vier Variablen paltzieren? Static int -Variablen oder in der init Methode oder...?

Ich muss ja die Stellung der Zeiger irgendwie  in die Task Klasse bekommen...


----------



## L-ectron-X (6. Jun 2004)

Hier noch mal die ganz einfache, komplette Applet-Klasse, die eine Digitaluhr simuliert. Vielleicht kannst Du ja auch was für Deine analoge Variante gebrauchen.

```
import java.awt.*;
import java.applet.*;
import java.util.*;
import java.text.*;

public class DigitalUhrApplet extends Applet {
  ZeitGeber zg;
  String zeit;
  Font schriftart;
  
  class ZeitGeber extends Thread {
    public void run() {
      while(!isInterrupt()) {
        DateFormat df = DateFormat.getTimeInstance();
        zeit = df.format(new Date());
        repaint();
        try {
          Thread.sleep(1000);
        }
        catch(InterruptedException e) {
           interrupt();
        }
      }
    }
  }

  public void init() {
    zg = new ZeitGeber();
    schriftart = new Font("Arial", Font.BOLD, 20);
  }
  
  public void start() {

    if(zg == null) {
      zg = new ZeitGeber();
    }
    zg.start();
  }
  
  public void stop() {
    zg.interrupt();
    zg = null;
  }
  
  public void paint(Graphics g) {
    g.setFont(schriftart);
    g.drawString(zeit, 0, 20);
  }
}
```


----------



## Guest (6. Jun 2004)

Danke!


----------



## Guest (11. Jun 2004)

Gibt es sonst noch irgend welche Lösungsmöglichkeiten mit der ich die Zeiger einer Analoguhr in Bewegung setzten könnte?
Am besten ohnen Threads.


----------



## L-ectron-X (11. Jun 2004)

Eine Lösung ohne Threads würde die Maschine zu 100% auslasten, das ist nicht Sinn und Zweck der Sache.


----------



## Guest (11. Jun 2004)

Die CPU-Auslastung ist erst mal nebensächlich. Wenn das Applet läuft kann ich mich an Verbesserungen wagen und mich mit Threads auseinandersetzen.


----------



## L-ectron-X (12. Jun 2004)

:!: *Anonymous* hat einen weiteren :arrow: Thread zu diesem Thema geöffnet.


----------

