5 Stimmen

Java KeyListener wird verzögert registriert

Wie die meisten Leute inzwischen mit dem Key-Listener feststellen würden, registriert Java in der Methode keyPressed einen Tastendruck, pausiert dann für etwa eine halbe Sekunde und zeichnet dann einen gleichmäßigen Strom von Tastendrücken auf. Mein Problem ist, dass ich möchte, dass Java unmittelbar einen kontinuierlichen Strom von keyDown-Ereignissen registriert, sobald eine Taste gedrückt wird. Ich habe viele Artikel zu diesem Problem gelesen und viele von ihnen sprechen von den Swing-Zeitgebern, über die ich auch im Dunkeln bin. Um den folgenden Code schöner und leichter lesbar zu gestalten, habe ich einfach den Ballast herausgeschnitten und den Key-Listener in eine separate Klasse gesteckt! Jeder Input dazu wäre sehr willkommen!

public class Keyer implements KeyListener
{

    Keyer(){}
    @Override
    public void keyPressed(KeyEvent ovent)
    {
        int keyCode = ovent.getKeyCode();
        System.out.println("Du hast gedrückt: "+keyCode);
    }
    @Override
    public void keyReleased(KeyEvent ovent)
    {

    }
    @Override
    public void keyTyped(KeyEvent ovent)
    {

    }
}

7voto

Nick Rippe Punkte 6455

Wenn das Drücken einer Taste ein Auslöser für die Aktualisierung deines GUI ist, dann musst du SwingTimers verwenden. Wenn es keine Aktualisierung deines GUI auslöst, kannst du einfach normale Threads verwenden.

Was ich vermute, auf das sich die Artikel beziehen, ist

  1. Speichern der gedrückten Tasten mit dem KeyListener
  2. Verwendung eines Swing-Timers, um zu überprüfen, welche Tasten in bestimmten Intervallen gedrückt sind (zum Beispiel alle 100 ms)

Hier ist ein Beispiel, wie du das in deinen KeyListener einbauen könntest:

    public class Keyer implements KeyListener{

        /** Speichert momentan gedrückte Tasten */
        HashSet pressedKeys = new HashSet();

        public Keyer(){

            //Überprüfe alle 100ms, ob Tasten gedrückt sind
            //(Dies ist der Swing Timer, von dem sie sprechen)
            new Timer(100, new ActionListener(){
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    String keysString = "";
                    if(!pressedKeys.isEmpty()){
                        Iterator i = pressedKeys.iterator();
                        while(i.hasNext()){
                            keysString += i.next() + ",";
                        }
                    } 
                    System.out.println(keysString);
                }
            }).start();
        }

        @Override
        public void keyPressed(KeyEvent ovent){
            //Füge Taste zum Hashset hinzu, wenn gedrückt
            int keyCode = ovent.getKeyCode();
            pressedKeys.add(keyCode);
        }
        @Override
        public void keyReleased(KeyEvent ovent){
            //Entferne Taste aus Hashset, wenn losgelassen
            int keyCode = ovent.getKeyCode();
            pressedKeys.remove(keyCode);
        }
        @Override
        public void keyTyped(KeyEvent ovent){}
    }

Hier ist ein Beispiel, wo alles zusammengefügt wird - ein Label wird aktualisiert und zeigt genau an, welche Tasten gedrückt sind (nach Keycode).

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

public class TempProject extends JPanel{
    /** Label zur Aktualisierung mit momentan gedrückten Tasten */
    JLabel output = new JLabel();

    public TempProject(){
        super();
        setFocusable(true);
        add(output, BorderLayout.CENTER);
        requestFocus();
        addKeyListener(new Keyer());
    }

    public static void main(String args[])
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                frame.setContentPane(new TempProject());    
                frame.pack();
                frame.setVisible(true);
                new TempProject();
            }
        });
    }

    public class Keyer implements KeyListener{

        /** Speichert momentan gedrückte Tasten */
        HashSet pressedKeys = new HashSet();

        public Keyer(){

            //Überprüfe alle 100ms, ob Tasten gedrückt sind
            //(Dies ist der Swing Timer, von dem sie sprechen)
            new Timer(100, new ActionListener(){
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    String keysString = "";
                    if(!pressedKeys.isEmpty()){
                        Iterator i = pressedKeys.iterator();
                        while(i.hasNext()){
                            keysString += i.next() + ",";
                        }
                    } 
                    output.setText(keysString);
                }
            }).start();
        }

        @Override
        public void keyPressed(KeyEvent ovent){
            //Füge Taste zum Hashset hinzu, wenn gedrückt
            int keyCode = ovent.getKeyCode();
            pressedKeys.add(keyCode);
        }
        @Override
        public void keyReleased(KeyEvent ovent){
            //Entferne Taste aus Hashset, wenn losgelassen
            int keyCode = ovent.getKeyCode();
            pressedKeys.remove(keyCode);
        }
        @Override
        public void keyTyped(KeyEvent ovent){}
    }

}

Bearbeiten

Siehe auch die Warnungen von @HovercraftFullOfEels bezüglich des KeyListener. Je nachdem, was du erreichen möchtest, solltest du in Betracht ziehen, Key Bindings zu verwenden (dieselben Prinzipien wie in diesem Beitrag gelten). Hier ist ein nützliches Tutorial zu Key Bindings, wenn du es dir ansehen möchtest.

1 Stimmen

Warum KeyListener und nicht Key Bindings? Was passiert, wenn Sie fokussierbare Komponenten zum GUI hinzufügen? Werden Sie alle Komponenten davon abhalten, den Fokus zu erhalten, damit der KeyListener funktioniert? Wenn Sie das tun, ist das ein brüchiger Kludge. Eine allgemeine Regel für Swing-GUIs besagt, dass die Verwendung von KeyListeners vermieden werden sollte. Glauben Sie nicht nur meinem Wort, sondern sehen Sie sich auch alle Beiträge von Jeanette/kleopatra und rob/camickr, zwei der besten Swing-Programmierer, die ich kenne, zu diesem Thema an.

0 Stimmen

@HovercraftFullOfEels die Frage bezog sich auf KeyListener, also habe ich sie damit beantwortet. Das gleiche Prinzip würde auch für Key Bindings gelten (Registrierung bei Druck/ Loslassen). Ich verstehe die Auswirkungen der Verwendung eines über dem anderen - Aber es kann auch einen Grund für den OP geben, einen KeyListener zu verwenden.

0 Stimmen

Angesichts seiner Reaktionen auf meine Antwort ist es sicher anzunehmen, dass er vor dem Stellen dieser Frage nicht einmal über Key Bindings Bescheid wusste, daher denke ich, dass die Chancen sehr gering sind, dass es unerklärte Gründe für seine Verwendung eines KeyListeners gibt. Ich glaube, wir tun ihm einen Bärendienst, wenn wir ihm Code-Lösungen geben, die er nicht nachahmen sollte.

6voto

Ich denke, dass dies kein Java-Problem ist, sondern vielmehr ein Betriebssystemproblem - das Betriebssystem verzögert das Senden von Tastenanschlägen für eine bestimmte Zeit, bevor es eine Reihe von Tastenanschlägen sendet. Eine Lösung besteht darin, bei Tastendruck einen Swing-Timer zu starten. Ich würde auch empfehlen, Key Bindings anstelle eines KeyListeners zu verwenden.

Außerdem sagst du, dass du "im Dunkeln" über Swing-Timer bist, und wenn dem so ist, fordere ich dich auf, dasselbe zu tun, was der Rest von uns getan hat, wenn sie sich in dieser Situation befanden: Überprüfe das entsprechende Tutorial. Google wird dir helfen, es ziemlich schnell zu finden. Auch eine Suche auf dieser Website wird dir Beispiele für die Verwendung von Key Bindings mit einem Swing Timer zeigen, sieh dir zum Beispiel hier an.

Bearbeiten
KeyListener ist eine niederstufige Konstruktion, und im Allgemeinen sollten Sie es vorziehen, höherstufige Konstruktionen zu verwenden, da sie sicherer und einfacher zu verwenden sind, ohne Nebenwirkungen zu verursachen oder Probleme zu haben. Beispielsweise können Sie bei Verwendung eines KeyListeners leicht Probleme mit Fokussierungsproblemen haben, da es nur funktioniert, wenn das gehörte Element den Fokus hat. Dies lässt sich leicht umgehen, wenn Sie stattdessen Key Bindings verwenden.

0 Stimmen

Entschuldigen Sie Hovercraft Full Of Eals, warum verwenden Sie Key Bindings anstelle von Key Listener? Ich frage mich nur, was Ihre Überlegungen dazu sind-

3 Stimmen

@BenHagel KeyListeners werden auch oft dort eingesetzt, wo andere, bessere Ansätze verwendet werden sollten, z. B. beim Versuch, Textkomponenten zu filtern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X