Frage von yeretor, 55

Wie Kann man in Java Events nach unten weitergeben?

Hallo! Wie lassen sich in java den Events von einem objekt nach unten weiterleiten? Ich möchte NICHT in der obersten ebene einen listener hinzufügen.

Hier ein Beispiel-code: package play2B;

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

@SuppressWarnings("serial") public class Test1 extends JFrame implements KeyListener{

private JButton Knopf;

public Test1() {
    super("Test");

    addKeyListener(this);
    
    System.out.println("add key listener");

    JPanel Platte = new JPanel();
    Platte.setLayout(new FlowLayout());
    Platte.setBackground(Color.WHITE);

    Knopf = new JButton("Test");
    Knopf.setFont(new Font("Arial", Font.BOLD, 20));
    
    Platte.add(Knopf);

    setContentPane(Platte);

    System.out.println("snake1 fertig");
}

public void keyPressed(KeyEvent Taste) {

    System.out.println("keyPressed");
    
}

public void keyReleased(KeyEvent Taste) {
    System.out.println("keyReleased");
}

public void keyTyped(KeyEvent Taste) {
    System.out.println("keyTyped");
}

public static void main(String[] args) {
    System.out.println("main start");
    
    Test1 Spiel = new Test1();
    Spiel.setSize(900, 600);
    Spiel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Spiel.setVisible(true);

}}

sobald ich die "Platte.add(Knopf);" -Zeile lösche funktioniert alles perfekt. Ich nehme an, der Knopf fängt die Events ab, deshalb möchte ich wissen wie ich sie zu menem fenster, der hintersten Ebene weiterleiten kann.


Wer Rechtschreibfehler findet, der kann sie behalten.

Expertenantwort
von KnusperPudding, Community-Experte für Java, 25

Naja, das Problem besteht darin, dass du glaub ich gar nicht so recht weißt, was du genau möchtest - Und verstehst auch noch nicht das Problem, weshalb dein Button keine Events hat.


Also folgendes:

Deine Klasse leitet von JFrame ab. Also einem Fenster. Dem Fenster verpasst du einen Keylistener. - Du hast zumindest den Eindruck: Sobald du jetzt dein Panel mit dem Button anfügst, dass der Keylistener nicht mehr funktioniert, hab ich recht soweit?

Zum ersten: Damit ein Keylistener funktioniert, muss deine Komponente den Focus haben (also ausgewählt sein).

Dein Denkfehler setzt wohl ein, bei dem du die Annahme hast, dass der Keylistener automatisch an alle 'Childen' vererbt wird. - Das ist nicht der Fall!!

Heißt: Sobald du eine fokusierbare Komponente anfügst, nämlich den Button, wird der Keylistener vom JFrame unwirksam, da sonst der Frame keinen Focus bekommt.

Lösung für dich: du fügst deinem Button den Keylistener an.



    Knopf = new JButton("Test");
Knopf.setFont(new Font("Arial", Font.BOLD, 20));
Knopf.addKeyListener(this);
Platte.add(Knopf);



Kommentar von yeretor ,

ok. am liebsten hätte ich aber den Focus von einer vokusierbaren komponente auf den Frame übertragen, d.h. der Knopf gibt das event an den frame weiter.

Kommentar von KnusperPudding ,

Auf die Art stößt du wieder auf dasselbe Problem wie bereits geschildert.

theoretisch kannst du den focus via Component#requestFocus(); erzwingen, aber das bringt dich nicht wirklich weiter, da, wie bereits gesagt, der KeyListener nur für die Komponente mit dem Focus funktioniert.

Du hast doch bereits in deiner Klasse einen Keylistener. Weis den doch einfach den Komponenten zu, die darauf reagieren sollen, also konkret: Deinem Frame und deinem Button.

So sehr du dir eine Vererbung des Listeners wünscht, das kann man nicht erzwingen. 

Aber wenn du mir erklärst was du damit bezweckst, wird es ja verständlicher.

Kommentar von yeretor ,

wie sähe das dan bei meinem beispielcode aus?

Kommentar von KnusperPudding ,

Die Variante, bei der du dem Frame zusätzlich einen Keylistener zuweist?

Zusätzlich zu der Ergänzung von oben via:

this.addKeyListener(this);

Das erste this bezieht sich auf die Aktuelle Klasse, die Methode addKeylistener steht zur verfügung weil du von JFrame erbst. Das zweite this bezieht sich auf den Keylistener den du implementierst in der selben klasse.

Kommentar von yeretor ,

nein die variante, bei der ich den focus auf meinen rahmen erzwinge (
 Platte.requestFocus(); oder this.requestFocus(); funktioniert nicht)

Kommentar von KnusperPudding ,

Das wiederum ist die 'unsaubere Methode' von der ich Sprach. 

requestFocus() setzt umgehend den Focus. - Dadurch geht aber natürlich das Keyevent verloren, um das nachzutragen wird dein Code deutlich unsauberer und länger und läuft letztendlich auf dasselbe hinaus.

Kommentar von yeretor ,

ich will schlicht und einfach nicht jeder komponente einen keylistener anhängen. und woher weiß ich dann, welche komponente im focus liegt (wen ich mehrere habe)/ welche den listener angesprochen hat?

Kommentar von KnusperPudding ,

ich will schlicht und einfach nicht jeder komponente einen keylistener anhängen.

Ja, exakt das ist der Punkt. Ein Keylistener funktioniert aber nun mal ausschließlich auf fokussierten Elementen und entsprechend ist bei deiner Anforderung auf alle Elemente ein Keylistener anzuhängen. 

Kommentar von yeretor ,

und woher weiß ich, auf welcher komponente der fukus liegt?

Kommentar von KnusperPudding ,

Codeseitig über: #hasFocus(), 

Optisch unterscheidet es sich stark, je nach Komponente:

Beim Button über eine Gestrichelte Linie, Beim Textfield über den Blinkenden Cursor. - Jedoch beim Frame gar nicht.

Defaultmäßig hat der Frame auch nur dann den Focus, wenn sonst keine fokusierbaren Elemente enthalten sind. D.h. die erste Komponente, die wirklich fokusierbar ist, erhält dann beim Starten auch die den Fokus.

Kommentar von KnusperPudding ,

Natürlich könntest du, sofern du keine Tastatursteuerung zulässt, alle Komponenten auf nicht fokusierbar setzen, somit würde dein Frame alle Key-Events abfangen.

D.h. du müsstest für jede Angefügte Fokusierbare Komponente 

.setFocusable(false);

setzen.

Kommentar von yeretor ,

ok. ich habe aber nur 1 mal die listener methoden. woher weiß ich - z.b. bei 2 textfeldern - vom programm auß, von welchem das event stammt?

Kommentar von KnusperPudding ,

Die 'Quelle' woher das Event stammt, bekommst du relativ Simpel via: KeyEvent#getSource() - Über getSource() bekommst du das Objekt zurück, welches das Event ausgelöst hat. D.h. Dein Frame oder dein Button.

Kommentar von yeretor ,

wie würde den ein beispielcode mit
 requestFocus(); außsehen?

 Platte.requestFocus(); oder this.requestFocus(); funktioniert nicht.

0

Kommentar von KnusperPudding ,

 funktioniert nicht.

Doch, funktioniert sehr wohl.

Wenn du deinen Frame anzeigen lässt:

frame.setVisible(true);
frame.setSize(300, 300);
frame.requestFocus();

Und dein Keylistener nur auf dem Frame liegt, dann werden genau so eingaben akzeptiert.

Fügst nach requestFocus() allerdings eine neue 'wirklich fokusierbare' Komponente an, ändert sich auch wieder der Focus.

Genauso verlierst du den Focus auf deinem Frame, sofern du eine Fokusierbare Komponente anklickst.

Kommentar von yeretor ,

und wie kann man vermeiden, dass der focus, sobald der knopf 1 mal gedrückt wurde dauerhaft auf ihm liegt, und nicht z.b. nach drücken des knopfs wieder auf dem frame liegt?

Kommentar von KnusperPudding ,

Am sinnvollsten indem du den Button nicht fokussierbar machst:

.setFocusable(false);

alternativ könntest du einen Actionlistener an den Button hängen, indem du dann Frame#requestFocus() aufrufst.

Kommentar von yeretor ,

1. würden die events vom knopf dann noch weitergegeben werden?

2. den frame hab ich ja als objekt nur in meiner main- methode.

    wie soll ich den von einer methode IN dem objekt ansprechen?

    (this.requestFocus(); funktioniert nicht!)

Kommentar von KnusperPudding ,

Zu 1.: Nein - Da ja keine Vererbung statt findet. Hat dein Button den Focus wird kein Listener des Frames aufgerufen.

Zu 2. Da kommt es dann drauf an, wie du den Rest Außenrum gestaltet hast. - Wovon leitet denn nun deine Klasse ab?

Kommentar von yeretor ,

Z.B. mal bei dem Beispiel-code in der Fragestellung

Kommentar von KnusperPudding ,

Im deinem Beispielcode leitest du ja bereits vom Frame ab. da brauchst du ja in der Main Methode keinen extra Frame

Kommentar von yeretor ,

und wie würdest du jetzt bei diesem konkreten beispiel den focus im Button-listener auf den frame setzen?

Kommentar von KnusperPudding ,

Hier ein eigenes Beispiel bei dem das deutlicher rüber kommt:

http://pastebin.com/Ah0jaspB

Kommentar von yeretor ,

danke

Keine passende Antwort gefunden?

Fragen Sie die Community