Kleine Animation

Würde gerne eine kleine Animation machen. Habe dazu 10 labels, in die ich im Abstand von 500ms was reinschreibe, lösche und in das nächste was reinschreibe…

Meine erste Idee wäre so gewesen:

label01.setText("X");
try{
     Thread.sleep(500);
     }catch(Exception e){}
}
label01.setText("");
label02.setText("X");
try{
     Thread.sleep(500);
     }catch(Exception e){}
}
//usw. bis halt zum label10

Ok, ich denke das dürfte funktionieren, nur finde ich das ziemlich viel Schreibarbeit und die Klasse wird vollgestopft! Das müßte man doch auch irgendwie sauber in einer Schleife verpacken können???

naja das einfachste denke ich wäre nen Array/Vector wo du die Sachen reinpackst und dann einfach drüber läufst, das kann man natürlich noch viel weiter treiben aber das wäre so meine erste einfache Idee

Hm, könntest du deine Idee etwas konkretisieren, evtl. mit einem kleinen Beispiel? :stuck_out_tongue_winking_eye:

naja sowas in der Art

....
Vector ani = new Vector();
ani.add(label1);
ani.add(label2);
...
for(int i=0;i!=ani.size();i++)
{
  for(int y=0;y!=ani.size();y++)
    if(y==i)
      ((JLabel)ani.get(y)).setText("X");
    else
      ((JLabel)ani.get(y)).setText("");
  
   try{
     Thread.sleep(500);
     }catch(Exception e){
}
....

Der Code dürfte etwa so aussehen (das try catch kannst du dir selbst denken:p )


for( int i = 0; i < array.length; i++ ){
  if( i > 0 )
    array[i-1].setText( "" );

  array**.setText( "x" );
  Thread.sleep( 500 );
}```

P.S. Da Swing nicht threadsicher ist, wäre es besser, den Aufruf von "setText" in den EventDispatcherThread (EDT) zu verlegen:
```for( int i = ... ){
  final JLabel current = array**;

  EventQueue.invokeLater( new Runnable(){
    public void run(){
      current.setText( "x" );
    }
  });```

Eine andere Idee, die noch einfacher als der Thread ist: benutz einen javax.swing.Timer :) Da hängst du einen ActionListener an, und der bekommt alle paar Millisekunden eine Nachricht. Über Thread-synchronisation musst du dir dann keine Sorgen mehr machen.

[Edit: Bitte Eagle, komm mal in diesem Jahrtausend an ... und verwende Generics :-P ]

Ja, hinsichtlich Thread-Sicher habe ich schon Probleme… es wird nichts gesetzt… Ok, wie geht das mit dem Timer genau?

Da zitier ich mal frisch und frech aus der API:

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

Du kannst da jede beliebige Klasse als ActionListener nehmen. Ich würde intern ein Zähler machen, der sagt, welches Label gerade das "x" hat. Das dürfte dann etwa so aussehen:
```public class Animation implements ActionListener{
  private JLabel[] labels;
  private int current = -1;

  public Animation( JLabel[] labels ){
    this.labels = labels;
  }

  public void actionPerformed( ActionEvent e ){
    if( current >= 0 )
      labels[ current ].setText( "" );

    current++;
    labels[current].setText( "x" );
  }
}```
Die Labels werden über den Konstruktor gegeben, zusammengebaut werden sie irgendwo in deiner GUI.
Mein Code kümmert sich jetzt nicht um das Ende der Animation, aber ein  zusätzliches "if" dürfte ja nicht so schwer sein ;-) 
Allenfalls kann diese Klasse auch gleich von "Timer" erben, dann hast du eine "start" und "stop" Methode der Animation.

Ich bin echt zu blöd… ich bekomme das Beispiel von Beni nicht hin und jetzt habe ich eigentlich noch ein einfach anmutendes Beispiel gefunden, doch auch hier verzweifle ich:

import java.util.*;
import java.awt.event.*;

class Animation implements ActionListener{
	

int delay = 1000;
  Timer t = new Timer(delay, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      // Neues Bild zeichnen
    }
  });
  t.start();
  }

Was könnte hier alles falsch sein? Der Compiler meint bei t.start(); expected

du musst das alles in eine Methode schreiben du kannstsowas nicht einfach in die Klasse schreiben

So?

import java.util.*;
import java.awt.event.*;

class Warten2 implements ActionListener{
	
public void machWas(){

int delay = 1000;
  Timer t = new Timer(delay, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      // Neues Bild zeichnen
    }
  });
  t.start();
  }
  }

Jetzt gibts folgende Fehlermeldungen:
4: Warten2 is not abstract and does not override abstract method actionPerformed(java.awt.event.ActionEvent) in java.awt.event.ActionListener
class Warten2 implements ActionListener{
9: cannot resolve symbol
symbol : constructor Timer (int,)
location: class java.util.Timer
Timer t = new Timer(delay, new ActionListener() {
14: cannot resolve symbol
symbol : method start ()
location: class java.util.Timer
t.start();

nimm das implements ActionListener raus und importiere javax.swing.Timer

Ok, schon mal danke, jetzt wird sauber compilet. Aber ich bin wohl echt zu blöd, hab das jetzt so gemacht und ausgeführt, es wird aber nichts ausgegeben:

import java.util.*;
import java.awt.event.*;
import javax.swing.Timer;

public class Warten2 {
	public Warten2(){
		machWas();
	}
	
public void machWas(){

int delay = 1000;
  Timer t = new Timer(delay, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      System.out.println("Hallo");
    }
  });
  t.start();
  }
  public static void main(String[] args){
  	new Warten2();
  }
  }

:frowning:

bau mal nach dem t.start ein sleep ein

  try{
Thread.sleep(5000);
}catch(Exception ex){}

Weil so wird dein Programm gestartet, du startest den Timer und dann wird dein Programm auch schon wieder beendet

Ok, das Problem hab ich gelöst, soll ja auf einem JFrame was passieren. Jetzt bin ich etwas weiter und hänge am nächsten Problem, der Text der JLabels wird nicht neu geschrieben:

import java.util.*;
import java.awt.event.*;
import javax.swing.Timer;
import javax.swing.*;
import java.awt.*;

public class Warten2 extends JFrame{
	public JLabel Hallo01, Hallo02;
	public JLabel[] array= {Hallo01, Hallo02};
	private int current = -1;
	public Warten2(){
		setSize(200,200);
		getContentPane().setLayout(new FlowLayout());
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		Hallo01 = new JLabel("Da   ");
		getContentPane().add(Hallo01);
		Hallo02 = new JLabel("Schau   ");
		getContentPane().add(Hallo02);
		setVisible(true);
		machWas();
	}
	
public void machWas(){

	int delay = 1000;
//	for( int i = 0; i < array.length; i++ ){
	if( current >= 0 ) {
		
  	Timer t = new Timer(delay, new ActionListener() {
    	public void actionPerformed(ActionEvent e) {
      	System.out.println("Hallo");
      	array[ current ].setText( "" ); 
		current++;   
		array[current].setText( "x" );
    }
  });
  t.start();
  }
  }
  public static void main(String[] args){
  	new Warten2();
  }
  }

An was könnte das liegen??

ändere das mal weil ich nicht genau weiß wie sich das mit dem Array ist

import java.util.*;
import java.awt.event.*;
import javax.swing.Timer;
import javax.swing.*;
import java.awt.*;

public class Warten2 extends JFrame{
	public JLabel[] array= new JLabel[2]
	private int current = -1;
	public Warten2(){
		setSize(200,200);
		getContentPane().setLayout(new FlowLayout());
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		array[0] = new JLabel("Da   ");
		getContentPane().add(array[0]);
		array[1] = new JLabel("Schau   ");
		getContentPane().add(array[1]);
		setVisible(true);
		machWas();
	}
	
public void machWas(){

	int delay = 1000;
//	for( int i = 0; i < array.length; i++ ){
	if( current >= 0 ) {
		
  	Timer t = new Timer(delay, new ActionListener() {
    	public void actionPerformed(ActionEvent e) {
      	System.out.println("Hallo");
      	array[ current ].setText( "" ); 
		current++;   
		array[current].setText( "x" );
    }
  });
  t.start();
  }
  }
  public static void main(String[] args){
  	new Warten2();
  }
  }

So, jetzt rotiere ich nur noch!!! :frowning:
Also was mache ich damit das wieder aufhört, so wie es jetzt ist, läuft es ja durch/weiter, gegen unendlich!

public void machWas(){

	int delay = 1000;
	System.out.println(array.length);
	for( int i =0;i<=5; i++ ){
//	if( current >= 0 ) {
		
  	Timer t = new Timer(delay, new ActionListener() {
    	public void actionPerformed(ActionEvent e) {
      	System.out.println("Hallo");
      	Hallo01.setText( "" ); 
	current++;   
		Hallo02.setText( "x" );
		System.out.println("Current1: "+current);
    }
  });if(current<array.length){  t.start();
  
 		current++;System.out.println("Current2 :"+current);
  }}
  }

ok habs bisschen geändert und rausbekommen das standardmäßig repeats = true ist

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

public class Warten2 extends JFrame
{
  public JLabel Hallo01,Hallo02;
  public JLabel[] array = {Hallo01,Hallo02};
  private int current = -1;
  private Timer t;

  public Warten2()
  {
    setSize(200,200);
    getContentPane().setLayout(new FlowLayout());
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    Hallo01 = new JLabel("Da   ");
    getContentPane().add(Hallo01);
    Hallo02 = new JLabel("Schau   ");
    getContentPane().add(Hallo02);

    t = new Timer(1000,new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        System.out.println("Hallo");
        if(current%2==0)
        {
          Hallo01.setText("o");
          Hallo02.setText("x");
        }
        else
        {
          Hallo01.setText("x");
          Hallo02.setText("o");
        }
        current++;
        System.out.println("Current1: "+current);
        if(current<10)
        {
          t.start();
          System.out.println("Current2 :"+current);
        }
      }
    });
    t.setRepeats(false);
    t.start();
    setVisible(true);
  }

  public static void main(String[] args)
  {
    new Warten2();
  }
}

Danke Eagle, so hat es funktioniert! :slight_smile: