Keylistener reagiert bei Buttons nicht.

SteveT

Mitglied
Hallo,
mein KeyListener reagiert nicht mehr, sobald der Button angeklickt wurde.
Als erstes habe ich den Button auf setEnabled(false) gesetzt, um zu gucken, ob es generell am Button liegt, aber erst nachdem ich den Button das erste Mal angeklicke, reagiert der Keylistener nicht mehr.
Woran liegt das?
Java:
package programm;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTextField;

public class kkk {

    static Boolean space = false;
    static JButton play;
  
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        JFrame mainframe = new JFrame();
        mainframe.setBounds(250, 70, 900, 500);
        JPanel mainpanel = new JPanel();
        mainpanel.setBackground(Color.gray);
        mainpanel.setLayout(null);
        mainframe.add(mainpanel);

        JMenuBar bar = new JMenuBar();
        bar.setBounds(0, 0, 1366, 23);
        mainpanel.add(bar);
      
        JMenuItem spaufnehmen = new JMenuItem("bla");
        bar.add(spaufnehmen);
      
        play = new JButton("play");
        play.setBounds(10, 50, 20, 20);
        play.setEnabled(false);
        mainpanel.add(play);
      
        mainframe.setVisible(true);
        mainframe.addKeyListener(new KeyListener() {

            public void keyTyped(KeyEvent e) {
                // TODO Auto-generated method stub
            }

            public void keyReleased(KeyEvent e) {
                // TODO Auto-generated method stub
            }

            public void keyPressed(KeyEvent e) {
                // TODO Auto-generated method stub

                if (e.getKeyCode() == 32) { // 32 = leertaste

                    space = true;
                    System.out.println("pressed");
                }
            }
        });

        spaufnehmen.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                Thread tt = new Thread(){
                  
                    public void run(){
                        while (!space) {
                            try {
                                if (space) {
                                  
                                    break;
                                }
                                Thread.sleep(1000);
                            } catch (InterruptedException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                            }
                        }
                        System.out.println("hi");
                        play.setEnabled(true);
                    }
                };
                space = false;
                tt.start();
            };
        });
    }

}
Danke schonmal für die Hilfe!
 
Dein Code ist relativ, wie soll man es sagen... altmodisch. Objektorientierung wäre hier sinnvoll.
Kannst du vielleicht erstmal erklären was du eigentlich vor hast? Vielleicht kann man dann gemeinsam eine objektorientierte Lösung finden. Bisher behandelst du alles in einer Klasse, die einen den Konventionen nach falschen Namen trägt. (CamelCase) Wenn schon "kkk" dann "Kkk", was auch nicht zu empfehlen is^^
 
Der Code ist eine Zusammenfassung meines Originalcodes, da das meiste davon nichts mit dem Thema zu tun hat, aber es spiegelt mein Problem genau wieder. Die Klassen meines Programmes sind alle mit einem großen Anfangsbuchstaben versehen 😉.
Eine umfangreiche Objektorientierung habe ich tatsächlich nicht, jedoch habe ich mein Programm auf 4 Klassen aufgeteilt (siehe Foto).
Mit dem Programm will ich (unter anderem) solange Daten aufnehmen, also das Eingangssignal meines Mikros, bis die Leertaste gedrückt wird. Die Schleife (bzw. der Thread), die darauf wartet, dass die Leertaste gedrückt wird, sieht genauso aus wie in kkk. Die Leertaste reagiert nicht mehr, nachdem ich ein Button bedient hab.
 

Anhänge

  • Unbenannt.png
    Unbenannt.png
    99,1 KB · Aufrufe: 44
Sobald dein Button gedrückt wird, startest du die Schleife, die damit den Thread blockiert. Der Thread kann also den Tastendruck nicht verarbeiten und damit auch nicht den KeyListener ansprechen.
 
jedoch habe ich mein Programm auf 4 Klassen aufgeteilt (siehe Foto).
Objektorientierung heißt nicht Dinge in Klassen aufzuteilen, sondern die Logik so zu modularisieren, dass deine Software erweiterbar und wartbar ist.
Ein Anzeichen dafür das dein Programm nicht gut programmiert ist, sind vor Allem die ganzen statics.
Statics sollte man vermeiden wenn sie nur dazu da sind um globalen Zugriff zu erlauben.

Ein Vorteil der Objektorientierung ist, dass man leicht die Realität in Programmen abbilden kann.
Wenn man dein Projekt mal anschaut, dann könnte man sich ein Tonstudio vorstellen, das ein Pult mit einem Aufnahmekopf hat. Wenn man den Knopf drückt geht eine rote Lampe an, die anzeigt, das die Aufnahme gestartet wird. Aufgenommen wird von einem Micro.

Anhand dieser Beschreibung kann man sich überlegen, welche Objekte man braucht.
Mir fallen spontan drei ein: "Micro", "Aufnahmegerät" und das "Tonstudio".

Das Tonstudio hat ein Aufnahmegerät und ein Micro. Eine "hat" Beziehung ist ein Hinweis darauf, dass dein Objekt bestimmte Attribute hat.
Java:
public class Tonstudio {
    private Micro mirco;
    private Aufnahmegerät aufnahmegerät;
}
Dein Aufnahmegerät könnte die aufgenommenen Spuren abspeichern (Ha da purzelt ja noch ein Objekt raus... "Spur")
Java:
public class Aufnahmegerät {
    private List<Spur> spuren;
}
usw.

Durch diese Vorüberlegung könntest du dein Tonstudio jederzeit erweitern und auch dein Aufnahmegerät mit verschiedenen neuen Funktionen füllen. Oder du könntest auch dein Micro einfach austauschen.

Dazu sei gesagt, der ganze KeyListener quatsch ist alles eher Zeug das für die Steuerung deines Programmablaufs zuständig ist. Stichwort "Controller" im Model View Controller Entwurfsmuster. MVC bietet dir die Möglichkeit deine Daten von deiner GUI oder der Logik zu trennen. Zusätzlich ist es ein weiteres Werkzeug um deinen Code zu strukturieren.
 
Danke für die vielen Tipps, ich werde mein Programm auf jeden Fall objektorientierter gestalten.
Jedoch wird die Leertaste immer noch nicht angesprochen, wenn ich beim Key Binding einen JMenuItem als JComponent auswähle. Wenn ich den Button als JComponent einsetze und dann dementsprechend auch den Actionlistener anpasse, klappt alles ohne Pobleme.
Java:
package programm;

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

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

public class Kkk {

    static Boolean space = false;
  
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        JFrame mainframe = new JFrame();
        mainframe.setBounds(250, 70, 900, 500);
        JPanel mainpanel = new JPanel();
        mainpanel.setLayout(null);
        mainframe.add(mainpanel);
      
        JMenuBar bar = new JMenuBar();
        bar.setBounds(0, 0, 1366, 23);
        mainpanel.add(bar);

        JMenu datei = new JMenu("datei");
        JMenuItem btausw = new JMenuItem("aufnehmen");
        datei.add(btausw);
        bar.add(datei);
      
        JButton spaufnehmen = new JButton();
        spaufnehmen.setBounds(10, 100, 60, 20);
        mainpanel.add(spaufnehmen);
      
        mainframe.setVisible(true);

        Action aufaction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                space = true;
                System.out.println("pressed");
            }
        };
      
        btausw.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "aufaction");
        btausw.getActionMap().put("aufaction", aufaction);
      
        btausw.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                Thread tt = new Thread(){
                  
                    public void run(){
                        while (!space) {
                            try {
                                if (space) {
                                  
                                    break;
                                }
                                System.out.println(space);
                                Thread.sleep(1000);
                            } catch (InterruptedException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                            }
                        }
                        System.out.println("hi");
                    }
                };
                space = false;
                tt.start();
            };
        });
    }

}
 
Du hast nur die Condition vergessen:
btausw.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)

edit: Für alle Buttons brauchst du wahrscheinlich noch das hier:
spaufnehmen.setFocusable(false);
da sonst nach dem Anklicken eines Buttons durch das Drücken der Leertaste der Button nochmal gedrückt wird.
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben