# Actionlistener funktioniert nicht "ordnungsgemäß"



## Martin951995 (11. Oktober 2010)

Hallo!
Ich habe folgendes Problem:
Ich will in einer frame ein männchen von links nach rechts wandern lassen und bei x=500pixel stoppen lassen.
Ich habe eine Klasse Schwert:

```
package beta;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

public class Schwert extends JLabel {
    

    public Schwert(int speed, int spieler) {


        setIcon(new ImageIcon("img\\Schwert.jpg"));
        setBounds(0, 270, 91, 139);
        setVisible(true);

    }

    public void move(int speed, Schwert s) {

        for (int i = 0; i <= 500; i = i + speed) {
            s = new Schwert(speed, 1);
            setBounds(i, 270, 91, 139);
            System.out.println(i);
            Programm.jlp.add(this, 0);
        }
    }

}
```

und wenn ich jetz in der main-Methode sage:

```
...
Schwert s = new Schwert(1, 1);
s.move(2, s);
...
```
dann passiert alles so wie ich es mir vorher gedacht hatte.
Aber wenn ich das im ActionListener aufrufe gibt er mir zwar keine Fehler meldung, aber er zeichnet mir nur das letzte Bild.

ich hoffe mir kann jemand helfen, danke für jede antwort im voraus


----------



## vfl_freak (11. Oktober 2010)

Moin,

aha ...... und in welchem ActionListener ? ? ?
Verräst Du das ? ? ? :-(

gruß
Klaus


----------



## Martin951995 (11. Oktober 2010)

achso ja genau

public void actionPerformed(ActionEvent a)

also wenn ich auf einen button drücke


----------



## sheel (11. Oktober 2010)

Zum einen kommt der genannte Listener nirgends in deinem gezeigten Code vor, andererseits
(nicht beleidigt sein) ist der gezeigte Code grauenhaft.

Was um alles in der Welt machst du da?!

Mit einem Aufruf von move erzeugst du 250 Schwerter, lädst 250 mal ein Bild von der Festplatte(bzw. RAM), fügst irgendeiner Collection 250 sinnfreie Objekte dazu...

Beschreib vielleicht einmal, was du genau vorhast, und poste den ganzen Code.

Und wer wandert jetzt eigentlich herum: Ein Männchen oder das (Multi-)Schwert?


----------



## Martin951995 (11. Oktober 2010)

ja kann sein, dass der code "grauenhaft" ist!
das liegt wahrscheinlich daran das ich noch nicht so lange programmiere!
also ich will eine figur namens schwert über die bildfläche wandern lassen...

Class Programm:


```
package beta;

import java.awt.*;

import javax.swing.JLabel;
import javax.swing.JLayeredPane;

public class Programm {

    static public Frame frame = new Frame();
    static public JLayeredPane jlp = new JLayeredPane();

    static JLabel labelMain = new JLabel();

    static Panel panel1 = new Panel();
    static Panel panel2 = new Panel();

    static Button button11 = new Button("Schwert");
    static Button button12 = new Button("Bogen");
    static Button button13 = new Button("");

    static Button button21 = new Button("Schwert (s)");
    static Button button22 = new Button("Bogen (b)");
    static Button button23 = new Button("");

    static ActionListner al = new ActionListner();

    static public Spielfeld sp = new Spielfeld();

    public static void anfang() {

        button21.setEnabled(false);
        button22.setEnabled(false);
        button23.setEnabled(false);

        button11.addActionListener(al);
        button12.addActionListener(al);
        button13.addActionListener(al);

        frame.setLayout(new BorderLayout());
        panel1.setLayout(new GridLayout(3, 1));
        panel2.setLayout(new GridLayout(3, 1));

        panel1.add(button11);
        panel1.add(button12);
        panel1.add(button13);

        panel2.add(button21);
        panel2.add(button22);
        panel2.add(button23);

        labelMain.setText("Spieler 1");

        jlp.add(sp, 1);
        frame.add(jlp, BorderLayout.CENTER);
        frame.add(panel1, BorderLayout.WEST);
        frame.add(panel2, BorderLayout.EAST);
        frame.add(labelMain, BorderLayout.NORTH);

    }

    public static void main(String[] args) {

        anfang();
        
        Schwert s = new Schwert(1, 1);  // das veranlasst, dass das "Schwert" von links nach rechts läuft

    }

}
```

Class Schwert:

```
package beta;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

public class Schwert extends JLabel {

    public int x;

    public Schwert(int speed, int spieler) {

        setIcon(new ImageIcon("img\\Schwert.jpg"));
        setBounds(x, 270, 91, 139);
        setVisible(true);
        this.move(speed, spieler);

    }

    public void move(int speed, int spieler) {

        if (spieler == 1) {
            for (int x = -90; x <= 860; x = x + speed) {

                setBounds(x, 270, 91, 139);
                System.out.println(x);
                Programm.jlp.add(this, 0);

            }
        } else {
            speed = speed * -1;
            for (int x = 860; x >= -90; x = x + speed) {

                setBounds(x, 270, 91, 139);
                System.out.println(x);
                Programm.jlp.add(this, 0);

            }
        }
    }

}
```
Class Frame:

```
package beta;

import javax.swing.JFrame;

public class Frame extends JFrame {

    public Frame(){
        
        setSize(1047, 431);
        setResizable(false);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
    }
}
```
Class ActionListener

```
package beta;

import java.awt.event.*;

public class ActionListner implements ActionListener {
	static String input;
	
	public void actionPerformed(ActionEvent a) {
		String input = a.getActionCommand();
		
		if (input == "Schwert"){
			System.out.println("ja");
			
			Schwert s = new Schwert(1, 1);

		}
		
		System.out.println(input);
	}
}
```


----------



## vfl_freak (11. Oktober 2010)

Moin,

was gibt Dir denn Dein "System.out.println(input)" der Klasse "ActionListener" aus, wenn Du den Button anklickst ? ? ?

gruß
Klaus


----------



## Maddin (11. Oktober 2010)

Hallo,

In deinem geposteten Code wird doch nie ein ActionCommand für einen Button gesetzt, da kann der input in der actionPerformed-Methode in deinem "ActionListner" niemals das von dir geforderte "Schwert" erreichen.

Lösungsvorschlag:

```
button11.setActionCommand( "Schwert" );
```

Gruß,
Martin


----------



## Martin951995 (12. Oktober 2010)

danke erst mal für die zahlreichen Antworten****** 
also wenn ich den meinen Button11 drücke  dann gibt meine konsole schon etwas aus, unzwar das, das auf dem button steht! in dem falle "schwert". er gibt mir dann, wenn ich darauf gedrückt habe unten in der Konsole die ganzen neuen x coordinaten aus, aber er zeichnet sie mir nicht neu.
wenn ich aber ein neues objekt nahmens "schwert" in der main methode aufrufe dann macht er alles wie geplant!


----------



## CPoly (12. Oktober 2010)

Maddin hat gesagt.:


> In deinem geposteten Code wird doch nie ein ActionCommand für einen Button gesetzt, da kann der input in der actionPerformed-Methode in deinem "ActionListner" niemals das von dir geforderte "Schwert" erreichen.



Die Aussage ist falsch. Siehe: http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Button.html#getActionCommand()

Was aber an der Stelle definitiv geändert werden musst ist der String-Vergleich


```
//das wird nie wahr
if (input == "Schwert")

//das schon
if (input.equals("Schwert"))
```

Außerdem fügst du in jedem Schleifendurchlauf das Schwert erneut zum Panel hinzu. Das musst du nur einmal machen. Stattdessen versuch mal per Programm.jlp.repaint() die Fläche neu zu Zeichnen.


----------



## Martin951995 (12. Oktober 2010)

ok!
ich habe deinen Vorschlag aufgenommen, doch das andere funktioniert bei mir auch!
sprich if(input == "Schwert") wird bei mir wahr!


----------



## CPoly (12. Oktober 2010)

Ok, dann war es wohl zu krass formuliert. Es ist nicht garantiert, dass es wahr wird. Dachte es wäre immer so.

Nur kurz als Beispiel:

```
String x = "Schwert";
String y = "Schwer";
String z = "t";

//false
System.out.println(x == (y+z));
//true
System.out.println(x.equals(y+z));
```


----------



## Martin951995 (12. Oktober 2010)

ok
es ist aber immer noch nicht geklärt, warum keine neuen Bilder gezeichnet werden, sondern nur die koordinaten erstellt werden, wenn ich ein neues objekt mit dem actionlistner erstelle!?
kann mir da noch jemand helfen?


----------



## sheel (12. Oktober 2010)

Das mit dem repaint hast du drin?

Jedes Mal, wenn das Schwert ein Stück weiterrückt, muss es ja neu gezeichnet werden.
Bei dir sind alle Zeichendurchgänge bis zur Zielposition in einer Schleife durch in einer einzigen Funktion, die im Actionlistener aufgerufen wird.

Das Problem hier ist:
Im Hintergrund läuft von Java aus ja ein Framework mit (Ist im Gegensatz zu zB C eigentlich das Grundprinzip von Java), dass zB wenn du einen Button erstellst dafür da ist, dass der Button gezeichnet wird, ohne dass du in deinem jeden einzelnen Strich selber extra zeichnen musst; und die Ausgabe zum Bildschirm etc übernimmt.

Wenn jetzt ein Button gedrückt wird, läuft das zuerst auch zum Framework, das dann von sich aus weiter deinen Actionlistener aufruft.

Und eben das ist das Problem.
Das Framework ruft deinen Actionlistener als eine normale Methode auf und macht erst dann mit seiner eigenen Arbeit weiter, wenn dein Actionlistener fertig ist.
Du zeichnest im Actionlistener das erste Mal ein Schwert-gut, ab in die Warteschlange damit.
Zweites mal ein wenig verschoben zeichnen-ab in die Warteschlange.

Wenn das Framework gleichzeitig zu deiner Funktion weiterarbeiten würde, würde es das ganze auch auf den Bildschirm zeichnen.
So wird aber erst weitergemacht, wenn dein Schwert bis zur letzten Position weitergerückt und und zum Zeichnen gegeben worden ist, und dein Actionlistener somit fertig ist.

Das ganze kannst du mit einem Thread lösen.
Ist quasi eine Methode, um mehrere verschiedene Sachen gleichzeitig nebeneinander laufen zu lassen.

Dafür:
1) Rufst du in der Klasse Schwert die Methode move nicht gleich im Konstruktor auf.
2) implementierst für Schwert das Interface Runnable
3) schreibst in Schwert noch eine Methode run, die in sich move aufruft
4) und verwendest den Actionlistener nur noch, um das Schwert zu "starten"


----------



## Martin951995 (12. Oktober 2010)

Danke erstmal für diese Antwort!
Mit Thread bin ich noch nicht so oft in berührung gekommen deshalb hätte ich eine Bitte:
Kannst du mir vieleicht ein konkretes Code beispiel geben?

mit vielem Dank
Martin


----------



## sheel (12. Oktober 2010)

Findet man haufenweise in Google.

zB Hier: http://www.go4expert.com/forums/showthread.php?t=4202

Also:
1) In der Klasse ActionListner, Methode actionPerformed, nach dieser Zeile

```
Schwert s = new Schwert(1, 1);
```
noch ein

```
(new Thread(s)).start();
```
machen.

2) Bei der Klasse Schwert statt

```
public class Schwert extends JLabel {
```
folgendes schreiben:

```
public class Schwert extends JLabel implements Runnable{
```

3) Beim Konstruktor der Klasse Schwert die letzte Codezeile, also den move-Aufruf entfernen

4) In die Klasse Schwert eine neue Methode schreiben, und zwar

```
public void run ( )
```
Hier drin wird jetzt move aufgerufen, statt im Konstruktor.

Denke, das wars.


----------



## Martin951995 (13. Oktober 2010)

Man bist du gut!
Du hast mir echt weiter geholfen!
Ich hätte mich bei google dumm und dämlich geucht!

mfg

Martin


----------



## Martin951995 (13. Oktober 2010)

Jetzt hab ich noch ein Problem, dass man wahrscheinlich auch mit einem Thread lösen kann.
Also, ich will noch ein KeyListener hinzufügen, aber wenn ich einen Button gedrückt habe funktioniert dieser nicht mehr!? 


```
package beta;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class KeyListner implements KeyListener {
	
	char c;
	int i;
	
	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub
		i = e.getKeyCode();
		System.out.println(i);
		if (i == 83){
			Schwert s = new Schwert(2);
			System.out.println(i);
		} else if (i == 66){
			Bogen b = new Bogen(2);
			System.out.println(i);
		}
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

}
```


----------



## sheel (13. Oktober 2010)

Du vergisst bei deinem Code, den Schwertthread zu starten.
Die gleichen Sachen wie für das Schwert gelten auch für den Bogen.

Und dein Satz ist irgendwie zweideutig.
Geht jetzt nach einem Tastendrück kein Button mehr oder reagiert nach einem Buttonklick keine Taste mehr?


----------



## Martin951995 (13. Oktober 2010)

1. ich habe den thread schon im construktor gestartet

2. wenn ich einen button geklickt habe funktioniert der keylistener nicht mehr


----------



## sheel (13. Oktober 2010)

Postest du vllt. nocheinmal den aktuellen Code?

Musst ja nicht jede Datei hierher kopieren, kannst auch einfach den Ordner gezippt hier raufstellen


----------



## Martin951995 (13. Oktober 2010)

Hier ist mal das ganze eclipse projekte


----------

