# JFrames und KeyListener



## SebSnake (16. Jun 2008)

Ich weiß nicht woran es liegt, aber wenn ich einen neuen JFrame erstelle (aus einem bestehenden Frame heraus), und diesem einen neuen KeyListener zuweise, so reagiert dieser nicht auf eingaben....

Woran liegt das, bzw, wie kann ich einem neuen Frame nun den KeyListener zuweisen?

Einfach im Konstruktor des Frames "addKeyListener(new Listener());" (wobei Listener meine KeyListener Klasse ist), funktioniert nicht...


----------



## Wildcard (16. Jun 2008)

JFrame und KeyListener ist meiner Erfahrung nach nicht so prickelnd. Registrier dich lieber als Listener auf einem JPanel.


----------



## SebSnake (16. Jun 2008)

Das JFrame added ein JPanel, auf dem ich gerade mal den Listener eingesetzt habe. Klappt auch nicht.


----------



## Niki (16. Jun 2008)

Die Lösung lautet KeyStrokes:

```
JPanel panel = (JPanel)getContentPane();
      InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
      ActionMap am = panel.getActionMap();

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
      am.put("escape", new AbstractAction(){
         public void actionPerformed(ActionEvent e) {
            System.out.println("escape pressed");            
         }
      });
```


----------



## SebSnake (16. Jun 2008)

hab den code hinter die erstellung des Panels gepackt, klappt immernoch nicht.... =/
Ich pack mal den gesamten relevanten code hoch.


MainKlasse, die mit der main-Methode

```
import java.awt.Toolkit;

public class MainKlasse{
	static MainFrame mainframe;
	static SpielbrettFrame spielframe;
	static LadebalkenFrame ladeframe;
	static int width;
	static int height;

	public MainKlasse() {
		
	}

	public static void main(String[] args) {
		width = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth();
		height = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight();
		height -= 35;
		mainframe = new MainFrame();
		mainframe.setLocation(((width-1350)/2), ((height-850)/2));
		ladeframe = new LadebalkenFrame();
		ladeframe.setVisible(false);
		ladeframe.setLocation(((width-400)/2), ((height-300)/2));
	}

	public static void warten(float x) {
		try {
			Thread.sleep((long) x * 1000);
		} catch (Exception e) {
			System.out.println("Kann nicht warten...");
		}
	}
}
```


Sorry wenns soviel ist...

MainFrame, das Hauptmenü.


```
import java.awt.*;
import javax.swing.*;

public class MainFrame extends JFrame {
	static MainMenu menu = new MainMenu();
	JWindow mitte;

	public MainFrame() {
		setLayout(null);
		setSize(1350, 850);
		setTitle("Spiel");
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		menu.setBounds(0, 0, 1350, 850);
		add(menu);
	}
}
```


MainMenu, Inhalt des MainFrames.


```
import java.awt.event.*;
import javax.swing.*;

public class MainMenu extends JPanel{
	static JButton neuesSpiel, spielLaden, highscore, beenden;

	public MainMenu(){
		neuesSpiel = new JButton();
		neuesSpiel.setText("Neues Spiel");
		neuesSpiel.setBounds(1050, 600, 200, 40);
		neuesSpiel.addActionListener(new Listener());
		spielLaden = new JButton();
		spielLaden.setText("Spiel Laden");
		spielLaden.setBounds(1050, 650, 200, 40);
		spielLaden.addActionListener(new Listener());
		highscore = new JButton();
		highscore.setText("Highscore");
		highscore.setBounds(1050, 700, 200, 40);
		highscore.addActionListener(new Listener());
		beenden = new JButton();
		beenden.setText("Beenden");
		beenden.setBounds(1050, 750, 200, 40);
		beenden.addActionListener(new Listener());
		add(neuesSpiel);
		add(spielLaden);
		add(highscore);
		add(beenden);
	}
}
```


LadebalkenFrame, das Fenster für den Ladebildschirm


```
import java.awt.*;
import javax.swing.*;

public class LadebalkenFrame extends JFrame {
	boolean felderzeugt = false;
	SpielfeldPanel spielfeld;
	Ladebalken balken;

	public LadebalkenFrame() {
		setLayout(null);
		setSize(410, 335);
		setTitle("Lade...");
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public boolean spielstarten() {
		update(this.getGraphics());
		balken = new Ladebalken(581);
		balken.setBounds(0, 0, 400, 300);
		spielfeld = new SpielfeldPanel(balken);
		add(balken);
		return true;
	}

	public void aufbauen() {
		while (felderzeugt == false) {
			felderzeugt = spielfeld.erzeugeFeld();
		}
		MainKlasse.warten(1f);
		dispose();
		MainKlasse.spielframe = new SpielbrettFrame(spielfeld);
	}
}
```


Ladebalken, der Inhalt des Ladebalken-Fensters


```
import java.awt.*;
import javax.swing.*;

public class Ladebalken extends JPanel {
	JLabel ladetext = new JLabel();
	int maxanz = 1, jetztanz = 0;
	TextArea geladen = new TextArea();
	int x;

	public Ladebalken(int a) {
		setLayout(null);
		x = 0;
		maxanz = a;
		setVisible(true);
		setSize(400, 300);
		geladen.setBounds(5, 50, 390, 245);
		ladetext.setBounds(5,0,200,20);
		ladetext.setText("Lädt...");
		add(geladen);
		add(ladetext);
	}

	public void ausgabe(String str) {
		geladen.append(str + "\n");
	}

	public void erneuern(String str, int i, int j) {
		jetztanz++;
		ladetext.setText("Lädt " + str + ": " + i
				+ " / " + j);
		update(getGraphics());
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		x = (int) Math.round((388 / (double) maxanz) * (double) jetztanz);
		g.setColor(Color.BLUE);
		g.drawRect(5, 20, 390, 25);
		g.drawRect(6, 21, 388, 23);
		g.setColor(Color.GREEN);
		g.fillRect(7, 22, x, 22);
	}
}
```

SpielbrettFrame, das Fenster für das Spielfeld (dieses soll bei Tastatureingaben reagieren)!


```
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class SpielbrettFrame extends JFrame{
	boolean felderzeugt = false;
	SpielfeldPanel spielfeld;

	public SpielbrettFrame(SpielfeldPanel brett) {
		spielfeld = brett;
		spielfeld.setBounds(0,0,800,800);
		setLayout(null);
		setSize(800, 800);
		setTitle("Spielfeld");
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		add(spielfeld);
		requestFocus();
		InputMap im = spielfeld.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
		ActionMap am = spielfeld.getActionMap();


                // Hier hab ichs probiert

		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
		am.put("escape", new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				System.out.println("escape pressed");
			}
		});
		


		spielfeld.neumalen = true;
		spielfeld.würfeln(7);
	}
}
```

SpielbrettPanel, Inhalt des Spielbrettfensters.


```
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.File;
import java.util.Stack;

import javax.imageio.ImageIO;
import javax.swing.*;

public class SpielfeldPanel extends JPanel{
	static int richtung = 0;
	static boolean neumalen = false;
	static boolean würfelnerlaubt = false;
	static Stack<String> s = new Stack<String>();
	static Stack<String> s2 = new Stack<String>();
	static boolean würfeln = false;
	static boolean smallmap = true;
	static boolean fader = false;
	BufferedImage[][] spieler = new BufferedImage[6][80];
	BufferedImage feld[] = new BufferedImage[100];
	BufferedImage smallfeld;
	BufferedImage transp = new BufferedImage(800, 800,
			BufferedImage.TYPE_INT_ARGB);
	float transpwert = 1f;
	int a, x, y, z, col;
	String prefix = "C:/Images/Daten/Cluedo/cluedo2/bilder/";
	String[] farbe = { "Blau", "Rot", "Grün", "Gelb", "Lila", "Weiß" };
	Ladebalken balken;

	public SpielfeldPanel() {
	}

	public SpielfeldPanel(Ladebalken balk) {
		setLayout(null);
		balken = balk;
	}

	public boolean erzeugeFeld() {
		try {
			col = 0;
			a = 1;
			x = -1320;
			y = -1260;
			balken.ausgabe("Lade Spielfeld (klein)");
			smallfeld = ImageIO.read(new File(prefix
					+ "/spielfeld/feld_800.jpg"));
			balken.ausgabe("Spielfeld (klein) geladen");
			balken.ausgabe("Lade Spielfeld");
			for (int i = 0; i < 100; i++) {
				balken.erneuern("Spielfeld", i + 1, 100);
				feld[i] = ImageIO.read(new File(prefix + "/spielfeld/feld/"
						+ (i + 1) + ".jpg"));
			}
			balken.ausgabe("Spielfeld geladen");
			for (int j = 0; j < 6; j++) {
				balken.ausgabe("Lade Spieler '" + farbe[j] + "'");
				for (int i = 0; i < 20; i++) {
					balken.erneuern(farbe[j], i + 1, 80);
					spieler[j][i] = ImageIO.read(new File(prefix + farbe[j]
							+ "/Rechts/" + (i + 1) + ".gif"));
				}
				for (int i = 20; i < 40; i++) {
					balken.erneuern(farbe[j], i + 1, 80);
					spieler[j][i] = ImageIO.read(new File(prefix + farbe[j]
							+ "/Runter/" + (i - 19) + ".gif"));
				}
				for (int i = 40; i < 60; i++) {
					balken.erneuern(farbe[j], i + 1, 80);
					spieler[j][i] = ImageIO.read(new File(prefix + farbe[j]
							+ "/Links/" + (i - 39) + ".gif"));
				}
				for (int i = 60; i < 80; i++) {
					balken.erneuern(farbe[j], i + 1, 80);
					spieler[j][i] = ImageIO.read(new File(prefix + farbe[j]
							+ "/Rauf/" + (i - 59) + ".gif"));
				}
				balken.ausgabe("Spieler '" + farbe[j] + "' geladen");
			}
		} catch (Exception e) {
			System.out.println("Geht nicht");
		}
		return true;
	}

	public boolean würfeln(int x) {
		System.out.println("Würfle " + x);
		int anz = x;
		while (anz > 0) {
			if (würfelnerlaubt == true) {
				while (!s.empty() & anz > 0) {
					anz--;
					System.out.println(anz);
					s2.push(s.pop());
				}
				while (!s2.empty()) {
					richtung = Integer.valueOf(s2.pop().toString()).intValue();
					for (int i = 0; i < 20; i++) {
						seta();
						setx();
						sety();
						try {
							Thread.sleep(20);
						} catch (Exception f) {
							System.out.println("Kann nicht warten!");
						}
					}
				}
			}
			update(this.getGraphics());
			/* Muss hier hin, sonst Auslastung -> 100% */
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				System.out.println("Fehler beim warten...");
			}
			/* Ende vor System.burn() Schutz */
		}
		System.out.println("Ende würfeln");
		return true;
	}

	public void seta() {
		a = (a % 20) + 1;
		a += (richtung - 1) * 20;
	}

	public void setcol() {
		col++;
		col = col % 6;
	}

	public void setx() {
		if (richtung == 1)
			x -= 10;
		if (richtung == 3)
			x += 10;
	}

	public void sety() {
		if (richtung == 2)
			y -= 10;
		if (richtung == 4)
			y += 10;
	}

	// Gesamtgröße: 5240, 5440
	public void paintComponent(Graphics g) {
		System.out.println("male");
		super.paintComponent(g);
		if (neumalen == true) {
			Graphics2D g2d = (Graphics2D) g;

			// Würfeln
			g2d.setColor(Color.BLACK);
			g2d.fillRect(0, 0, 800, 800);
			int xi = -2620;
			int yi = -2720;
			for (int i = 0; i < 10; i++) {
				for (int j = 0; j < 10; j++) {
					if ((x + xi + 524 >= 0 & x + xi <= 800)
							&& (y + yi + 544 >= 0 & y + yi <= 800)) {
						g2d.drawImage(feld[(i * 10) + j], x + xi, y + yi, 524,
								544, this);
					}
					xi += 524;
				}
				xi = -2620;
				yi += 544;
			}
			g2d.drawImage(spieler[col][a - 1], 300, 300, 200, 200, this);

			// Smallmap überblenden
			if (smallmap == true) {
				if (fader == true) {
					if (würfeln == false) {
						transpwert += 0.1f;
					}
					if (würfeln == true) {
						transpwert -= 0.1f;
					}
					if (transpwert <= 0f) {
						würfelnerlaubt = true;
						fader = false;
						smallmap = false;
					}
					if (transpwert >= 1f) {
						fader = false;
					}
					update(MainKlasse.mainframe.getGraphics());
				}
				Graphics g2 = transp.getGraphics();
				g2.drawImage(smallfeld, 0, 0, null);

				float[] scales = { 1f, 1f, 1f, transpwert };
				float[] offsets = new float[4];
				RescaleOp rop = new RescaleOp(scales, offsets, null);
				g2d.drawImage(transp, rop, 0, 0);
			}
		}
	}
}
```


----------



## Wildcard (16. Jun 2008)

```
panel.setFocusable(true)
SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        panel.requestFocusInWindow();
    }
});
```


----------



## SebSnake (16. Jun 2008)

irgendwie immernoch keine Reaktion...

Sitz da jetzt seit gestern Nachmittag dran und so langsam hab ich keinen Bock mehr...


----------



## Wildcard (16. Jun 2008)

Du musst jedes getGraphics aus deinem Programm entfernen, das ist falsch.
Ansonsten ist der Quelltext zu umfangreich als das ich das nebenbei prüfen kann. 
Am besten du versuchst dich an einem Minimalbeispiel JFrame + JPanel *+ KeyListener, nicht mehr.


----------



## SebSnake (16. Jun 2008)

Versuchs grad nochmal ganz neu mit nur einem Frame, ich meld mich dann wieder... ^^"
Trotzdem danke...


----------



## SebSnake (16. Jun 2008)

Ok, nochmal eine andere Frage...

du sagst ich soll getGraphics entfernen... gut, aber update() braucht nunmal ein Graphics-Objekt.
Wenn ich nur repaint() benutze, werden die paintComponent Methoden nicht aufgerufen.

Kann mir jemand sagen warum?


----------



## Wildcard (16. Jun 2008)

zu getGraphics siehe hier:
http://www.java-forum.org/de/topic46550_zeichnen-swing-tutorial.html

doch, bei repaint wird paintComponent aufgerufen, insofern man nicht paint falsch überschrieben hat.


----------



## thE_29 (16. Jun 2008)

Zum Thema KeyListener: Was noch gehen würde, wäre die Eventqueue auslesen!

Zb so: 
	
	
	
	





```
java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueue(){
      protected void dispatchEvent(AWTEvent event) {
        if(event instanceof KeyEvent)
        {
          //Hier Keyevent abarbeiten
          if(event == der event was ich will)
             ; //do abarbeitung
          else
            super.dispatchEvent(event);
        }
        else
          super.dispatchEvent(event);
      }
    });
```


----------



## SebSnake (16. Jun 2008)

ich bin glaub ich zu blöd für repaint()...
hab jetzt einen JFrame auf dem alle Komponenten sind...
dann muss ich doch im JFrame die "paint" Methode überschreiben und da drin dann sagen, "male doch bitte alle Componenten neu", oder?


----------



## thE_29 (16. Jun 2008)

Und was machst du in der überschriebenen paint Methode?


----------



## SebSnake (16. Jun 2008)

super.paint()

und dann die paintComponent(g)-Methoden meiner Komponenten??  :autsch:

Ne klappt auch nicht...


----------



## Wildcard (16. Jun 2008)

Nein, paint musst (bzw. solltest) du nicht überschreiben.


----------



## SebSnake (16. Jun 2008)

Ich hab jetzt viele Möglichkeiten ausprobiert, mit paintComponent, paint, in jeweils dem Frame oder den einzelnen Componenten, mit super und ohne, aber es will einfach nicht. nur mit update(this.getGraphics()) zeigt der was an...


----------



## aikar (16. Jun 2008)

Ich hab grad das selbe Problem. Eine gesteuerte Animation in einem Panel, aber wenn ich das Panel neu erstelle funktioniert der Key-Listener nicht mehr.


Im JFrame (Wird immer wieder mal aufgerufen, wenn der Panel neu gestartet werden soll):

```
if(actual!=null) getContentPane().remove(actual);
actual = new PresentationPanel();
getContentPane().add(actual);
pack();
setVisible(true);
```

Im Panel:

Ich speichere die Key-Codes in einem Vector (pressedKeys) und lese sie dann während der Animation aus.
registerKeyListeners(); wird im Konstruktor aufgerufen. Für die Animation wird das Panel in einen eigenen Thread ausgelagert (new Thread(this)) 


```
private void registerKeyListeners() {
            
            System.out.println("Add KeyListener");
		addKeyListener(new KeyAdapter() {
			// * listen for esc, ctrl-c on the canvas to
			//   allow a convenient exit from the full screen configuration
			// * space to un/pause
			public void keyPressed(KeyEvent e) {
				int keyCode = e.getKeyCode();
                                
                                System.out.println("Pressed key: "+keyCode);
                                
				if ((keyCode == KeyEvent.VK_ESCAPE)
						|| ((keyCode == KeyEvent.VK_C) && e.isControlDown())) {
					running = false;
				} else if (keyCode == KeyEvent.VK_SPACE) {
					
                                    isPaused = !isPaused;
                                    if(isPaused)
                                    {
                                        pauseStart = System.currentTimeMillis();
                                    }   
                                    else
                                    {
                                        pauseTime = pauseTime + System.currentTimeMillis()-pauseStart;
                                    }
                                      
				} else if(startCounter<0 && !isPaused)
                                {
                                    Integer keyCodeObject=new Integer(keyCode);
                                    if(!pressedKeys.contains(keyCodeObject))
                                        pressedKeys.add(keyCodeObject);
                                   
                                }
              
			}//keyPressed
                        
                        public void keyReleased(KeyEvent e)
                        {
                           Integer keyCodeObject=new Integer(e.getKeyCode());
                           pressedKeys.remove(keyCodeObject);
                        }
		});
	}
```


Beim ersten mal funktioniert das gut. Aber nach dem Entfernen und Neu-Erstellen funktioniert die Tasteneingabe nicht mehr.
registerKeyListeners() wird aufgerufen und die Animation startet, aber keyPressed wird nie mehr ausgelöst.

Ein neues Panel wird im Frame erst hinzugefügt, wenn der Animationsthread des Panels ausgelaufen ist. 


Bitte um rasche Hilfe, ich muss das Projekt in den nächsten Tagen abgeben! Danke im Vorraus


----------



## aikar (16. Jun 2008)

Ich habe eine Lösung gefunden, vielleicht hilfts auch anderen.

Wenn ich nicht nur das Panel remove und neu hinzufüge sondern den ganzen Frame schließe (dispose) und neu anlege, funktioniert es. Da scheints irgendein Problem mit der Freigabe des Keylisteners beim Eintfernen eines Panels zu geben.


----------

