Schnelle Tastaturabfrage

Status
Nicht offen für weitere Antworten.

Moonlight1234

Bekanntes Mitglied
Ich will die Pfeiltasten abfragen.
Der KeyListener fragt mir die tasten nicht oft genug ab.

Daher wollte ich einen KeyEvent starten und in einen Thread verlagern der die Abfrage vornimmt:

Code:
class MainFrame extends JFrame implements  Runnable {
  

    Thread keythread;    
    KeyEvent keyRight;
    KeyEvent keySpace;
    
    public MainFrame(){
        
        setFocusable(true);
        
        setSize (1024, 768);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        
        setVisible(true); 
        
        keyRight=new KeyEvent(this, KeyEvent.CHAR_UNDEFINED,1000,0,KeyEvent.VK_RIGHT,KeyEvent.CHAR_UNDEFINED);
        keySpace=new KeyEvent(this, KeyEvent.CHAR_UNDEFINED,1000,0,KeyEvent.VK_SPACE,KeyEvent.CHAR_UNDEFINED);
        
       keythread=new Thread(this);
       keythread.start();
        
    }
  
    public void run() {

        if (keyRight.getKeyCode()==KeyEvent.VK_RIGHT){
                System.out.println("Pfeil rechts gedrückt");  
        }
        if (keySpace.getKeyCode()==KeyEvent.VK_SPACE){
            System.out.println("Space gedrückt"); 
        }    
    }   
}

class keyEventTest {
    
    public keyEventTest() {
    }
    
    public static void main(String[] args) {
        MainFrame mf=new MainFrame();
    }
    
}
Das Programm führt dazu das bei einem Tastendruck das Fenster geschlossen wird.

Außerdem wird bei jeder gedrückten Taste Pfeil rechts und Space erkannt wird

Was mache ich falsch?

Oder gibt es eine andere Möglichkeit die Tasten schnell und oft abzufragen?
 

Wildcard

Top Contributor
Moonlight1234 hat gesagt.:
Ich will die Pfeiltasten abfragen.
Der KeyListener fragt mir die tasten nicht oft genug ab.
Was soll denn das heißen???
Ein KeyListener fragt überhaupt nichts ab. Er bekommt mitgeteilt wenn eine Taste gedrückt wird (und das genauso oft wie's nunmal passiert). ???:L
 

Moonlight1234

Bekanntes Mitglied
Wildcard hat gesagt.:
Moonlight1234 hat gesagt.:
Ich will die Pfeiltasten abfragen.
Der KeyListener fragt mir die tasten nicht oft genug ab.
Was soll denn das heißen???
Ein KeyListener fragt überhaupt nichts ab. Er bekommt mitgeteilt wenn eine Taste gedrückt wird (und das genauso oft wie's nunmal passiert). ???:L

Ich will ein Sprite über den Bildschirm bewegen.

Mit KeyListener habe ich festgestellt das die Bewegung der Image sehr langsam ist, wenn ich die Pfeiltaste gedrückt halte.
Ich bewege praktisch eine Image um einen Pixel in die entsprechende Richtung.

Ich glaube nicht das es an zu langamen Bildaufbau liegt.
Ich lade die Images mit Mediatracker und habe es schon ohne Swing probiert.
Die Bewegung ist nach wievor langsam.
Also liegt es meiner Meinung nach an der tastaturabfrage.

Oder liege ich da falsch?

Ich kann natürlich die image nicht nur um einen Pixel, sondern um zwei, drei Pixel versetzten und erhöhe damit die Geschwindigkeit, das würde aber auf Kosten der Genauigkeit gehen
 

Wildcard

Top Contributor
Als liegt am Intervall in dem das Keyboard sich meldet. Ist in einem Textverarbeitungsprogramm genauso.
Du musst da anders ran gehen:
-Bewegen wenn Taste gedrückt wurde
-stoppen wenn Taste losgelassen wird
 

Moonlight1234

Bekanntes Mitglied
Kann man den Intervall nicht erhöhen?

Meiner Ansicht nach mache ich genau das was du sagst:
Code:
public void keyPressed(java.awt.event.KeyEvent keyEvent) {
            if (keyEvent.getKeyCode()==KeyEvent.VK_RIGHT){
                PlayPane.cowboy.moveSpriteRight(1);
                repaint();
                setVisible(true);
            } 
}
moveSpriteRight bewirkt das die Position der Image um ein Pixel nach rechts verschoben wird, dh. in der paintComponent() wird die mit drawImage erzeugte Position der Image verändert
 

Wildcard

Top Contributor
1) nein kann man nicht
2) nein machst du nicht
btw:
Code:
PlayPane.cowboy.moveSpriteRight(1);
mach Instanz-Variablen IMMER private oder du kriegst ganz schnell Probleme...
und diese static Sache(oder falsche Benennung) sieht auch ungesund aus!
 

Moonlight1234

Bekanntes Mitglied
Deine Antworten bringen mich nicht wirklich weiter.....
die Antworten sind zu kurz.

Du hattest geschrieben ich soll das Sprite bewegen wenn Taste gedrückt, nicht bewegen wenn Taste nicht gedrückt.
Ich frage mit dem og. Code ab ob zb. Pfeilttaste rechts gedrückt wurde.
Wenn ja wird die x Position der image um 1 erhöht.
Die in der paintComponent() aufgerufene drawImage() Methode zeichnet die Image dann an der neuen Position.

Ob die Pfeil-Taste rechts nicht mehr gedrückt wird, frage ich nicht mehr extra ab, da eine Bewegung ja ohnehin nur stattfindet wenn die Taste gedrückt wird.
 

Wildcard

Top Contributor
Es geht um das Tastatur-Delay.
Du brauchst einen Thread, und musst solange bewegen bis die Taste losgelassen wird(nicht solange du Events bekommst. Das ist ein Unterschied).
 

Moonlight1234

Bekanntes Mitglied
Wildcard hat gesagt.:
Es geht um das Tastatur-Delay.
Du brauchst einen Thread, und musst solange bewegen bis die Taste losgelassen wird(nicht solange du Events bekommst. Das ist ein Unterschied).

Ich lagere die Bewegung in einen thread aus und überbrücke damit die leere Zeit zwischen den Tastaturimpulsen.?
 

Wildcard

Top Contributor
nein!
Du setzt irgendeine Bewegungsvariable wenn eine Taste gedrückt wurde,
lässt den Thread immer wieder Bewegen und Schlafen,
und setzt die Variable wieder zurück wenn die Taste losgelassen wurde.
Die anderen Events interessieren dich nicht, nur drücken und loslassen.
 
B

bygones

Gast
Code:
public void keyPressed(java.awt.event.KeyEvent keyEvent) {
            if (keyEvent.getKeyCode()==KeyEvent.VK_RIGHT){
                PlayPane.cowboy.moveSpriteRight(1);
                repaint();
                setVisible(true);
            }
}
wenn dass dein Code ist, dann folgendes:

PlayPane.cowboy.moveSpriteRight(1); ist wie Wildcard schon sagte nicht gerad elegant. Nicht gerade im Sinne von: Gar nicht

warum setVisible(true) ? es ist doch schon beim ersten mal zu sehen ?

außerdem geschieht bei dem code folgendes:

1. taste wird gedrückt
2. listener erkennt und reagiert.
3. nach rechts verschoben ? (oder was ide methode auch immer macht)
4. nix / aus

wenn ich dich richtig verstanden habe musst du in einer schleife, die solange läuft wie die Taste gedrückt wird eine Bewegung durchführen, dann bekommst du eine stetige Bewegung !
 

Wildcard

Top Contributor
Moonlight1234 hat gesagt.:
Hast du mal Beispielcode?
das hab ich mal in einer langweiligen Vorlesung gemacht. :wink: Such dir raus was du brauchst:
Code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @author Wildcard
 * created at 10.05.2005
 */
public class Pong extends JFrame implements Runnable 
{ 
    
    private Ball ball = new Ball(18,Color.RED); 
    private Stick stick = new Stick(50,Color.BLUE); 
    private Stick stick2 = new Stick(50,Color.GREEN);
    private Point speed = new Point(3,3); 
    private static final int LEFT = -5; 
    private static final int RIGHT = 5; 
    private int counter1 = -1;
    private int counter2 = -1;
    private int direction=0; 
    private int direction2=0;
    
    public Pong() 
    { 
        JPanel panel = new JPanel((LayoutManager)null); 
        getContentPane().add(panel); 
        
        panel.addKeyListener(new KeyAdapter() 
        { 
            public void keyTyped(KeyEvent e) 
            { 
                if(e.getKeyChar()=='a') 
                    direction=LEFT; 
                else if(e.getKeyChar()=='d') 
                    direction=RIGHT; 
                if(e.getKeyChar()=='l')
                    direction2=LEFT;
                else if(e.getKeyChar()=='ä')
                    direction2=RIGHT;

            } 

            public void keyReleased(KeyEvent e) 
            { 
                if(e.getKeyChar()=='a' || e.getKeyChar()=='d')
                    direction=0;
                else if(e.getKeyChar()=='ä'|| e.getKeyChar()=='l')
                    direction2=0;
            } 
        }); 


        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        setSize(500,500); 
        stick2.setLocation(getWidth()/2-28,80);
        stick.setLocation(getWidth()/2-25,getHeight()-120); 
        ball.setLocation(50,50); 
        
        panel.add(stick2);
        panel.add(stick); 
        panel.add(ball); 
        
        new Thread(this).start(); 
        setVisible(true); 
        panel.requestFocus(); 
        
    } 

    /** 
     * @see java.lang.Runnable#run() 
     */ 
    public void run() 
    { 
        // TODO Auto-generated method stub 
        Rectangle frame = new Rectangle(0,0,getContentPane().getWidth(),getContentPane().getHeight()); 
        Rectangle ballRect; 
        final Point ballLocation = ball.getLocation(); 
        
        while(true) 
        { 
            repaint(); 
            if (!(stick.getLocation().x<=5) && !(stick.getLocation().x+50>=getContentPane().getWidth()-5)) 
                stick.setLocation(stick.getLocation().x+direction,stick.getLocation().y); 
            else if (stick.getLocation().x<50) 
                stick.setLocation(stick.getLocation().x+1,stick.getLocation().y); 
            else 
                stick.setLocation(stick.getLocation().x-1,stick.getLocation().y);
            
            if (!(stick2.getLocation().x<=5) && !(stick2.getLocation().x+50>=getContentPane().getWidth()-5)) 
                stick2.setLocation(stick2.getLocation().x+direction2,stick2.getLocation().y); 
            else if (stick2.getLocation().x<50) 
                stick2.setLocation(stick2.getLocation().x+1,stick2.getLocation().y); 
            else 
                stick2.setLocation(stick2.getLocation().x-1,stick2.getLocation().y);
            
            ballRect = new Rectangle(ball.getBounds()); 
            if (!frame.contains(ballRect)) 
            { 
                if (ball.getLocation().x<0 || ball.getLocation().x+ball.durchmesser>getWidth()) 
                    speed.x=-speed.x; 
                else if (ball.getLocation().y<0 || ball.getLocation().y+ball.durchmesser>getContentPane().getHeight()) 
                    speed.y=-speed.y; 
                
                if(ball.getLocation().y<0)
                    counter1++;
                else if(ball.getLocation().y+ball.durchmesser>getContentPane().getHeight())
                    counter2++;
            } 
            
            if(stick.getBounds().intersects(ball.getBounds())) 
            { 
                speed.y=-speed.y; 
            } 
            if(stick2.getBounds().intersects(ball.getBounds())) 
            { 
                speed.y=-speed.y; 
            } 
            
            try 
            { 
                Thread.sleep(8); 
            } catch (InterruptedException e) 
            { 
                // TODO Auto-generated catch block 
                e.printStackTrace(); 
            } 
            
            
            ballLocation.x=ballLocation.x+speed.x; 
            ballLocation.y=ballLocation.y+speed.y; 
            ball.setLocation(ballLocation); 
            

                      
        }      
    } 
    
    public static void main(String[] args) 
    { 
       new Pong(); 
    } 

} 

class Ball extends JComponent 
{ 
    int durchmesser; 
    private Color color; 
    
    
    public Ball(int durchmesser, Color color) 
    { 
        this.durchmesser=durchmesser; 
        this.color=color; 
        setSize(durchmesser,durchmesser); 
    } 
    
    
    protected void paintComponent(Graphics g) 
    { 
        
        g.setColor(color); 
        g.fillOval(0,0,durchmesser,durchmesser); 
    } 
    
} 

class Stick extends JComponent 
{ 
    int length; 
    private Color color; 
    
    
    public Stick(int length, Color color) 
    { 
        this.length=length; 
        this.color=color; 
        setSize(length,10); 
    } 
    
    
    protected void paintComponent(Graphics g) 
    { 
        g.setColor(color); 
        g.fillRoundRect(0,0,length,10,5,5); 
    } 
}
 

Moonlight1234

Bekanntes Mitglied
Mann o Mann . Kann ja wohl nicht war sein das man für so eine tastatureingabe so ein Häck meck verstalten muß.

:x Mit DirectX ist das ganze ganz einfach.

Also ich erzeuge für jede Bewegungsrichtung einen Thread.
In dem thread lasse ich eine Schleife laufen, mit dem KeyListener starte, stope ich die threads.

Dann habe ich jetzt folgendes Problem:

Das ganze läuft in einem JFrame.
Ich lasse also vier Threads in dem Frame laufen.

Ich habe, da ja die run-Methode() aufgerufen wird aber nur eine run Methode in die ich die Schleifen schreiben kann.
Ich bräuchte aber vier run-Methoden.

Oder soll ich vier JPanels mit je einem thread schreiben und in die jeweilige run()-Methode die schleifen programmieren?


Warum setVisible.

Weil die image in der paintComponent()-Methode des JPanels gezeichnet wird.
Ich muß die Anzeige ja aktuallisieren.

mit repaint() geht das irgendwie nicht.
mit setVisible(true) aber schon
 

Wildcard

Top Contributor
Wie kommst du denn auf den Käse?
Ein Thread der die ganze Zeit läuft und mehr nicht.
Das ist auch kein 'Häck meck' sondern eine Sache von ein paar Zeilen.
Und was hat DirectX damit zu tun? :bahnhof:
 

Moonlight1234

Bekanntes Mitglied
Wildcard hat gesagt.:
Wie kommst du denn auf den Käse?
Ein Thread der die ganze Zeit läuft und mehr nicht.
Das ist auch kein 'Häck meck' sondern eine Sache von ein paar Zeilen.
Und was hat DirectX damit zu tun? :bahnhof:


DirectX hat insofer etwas damit zu tun, weil mit DirectInput eine Schnittstelle existiert welche genau, präzise Tastatureingaben verabeiten kann.

Wenn das eine sache von ein paar Zeilen ist warum hast du nicht etwas Code gepostet?
 

Wildcard

Top Contributor
Moonlight1234 hat gesagt.:
DirectX hat insofer etwas damit zu tun, weil mit DirectInput eine Schnittstelle existiert welche genau, präzise Tastatureingaben verabeiten kann.
Kannst du dir ja auch in Java schreiben

Moonlight1234 hat gesagt.:
Wenn das eine sache von ein paar Zeilen ist warum hast du nicht etwas Code gepostet?
Weil ich der Meinung war das ich dir einige zukünftige Fehler ersparen kann wenn ich dir an etwas funktionierendem zeige wie man mit Threads, Listenern und KlassenDesign in einem solchen Fall umgeht...
 

Moonlight1234

Bekanntes Mitglied
@Wildcard


Dann bedanke ich mich für dein Engagement.

Ich lerne am besten durch Beispielcode.
Vielleicht finde ich noch irgendwo welchen zu diesem Thema, so hat das hier keinen Sinn.

Geht nicht gegen dich.
Ich hatte schon mal einen Bildschirmschoner programmiert, mit Kollisionsabfragen, Animationen usw.
Ich wollte mich jetzt mal an ein etwas größeres Projekt wagen
Ich hätte nie gedacht das es an so einer s$$$$ tastatureingabe scheitert.
 

Wildcard

Top Contributor
... was ist denn daran jetzt so schwer zu verstehen?
keyPressed/keyReleased -> variable verändern
Code:
            public void keyTyped(KeyEvent e)
            {
                if(e.getKeyChar()=='a')
                    direction=LEFT;
                else if(e.getKeyChar()=='d')
                    direction=RIGHT;


            }

            public void keyReleased(KeyEvent e)
            {
                if(e.getKeyChar()=='a' || e.getKeyChar()=='d')
                    direction=0;

            }

und ein Thread der immer läuft
Code:
public void run
{
    while (true)
    {
            //varibale benutzen
            bewegeIrgendwas(direction)
            repaint();

            //schlafen legen
            try
            {
                Thread.sleep(8);
            } catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
     }
}
 

Griffin

Bekanntes Mitglied
Irgendwie redet ihr aneinander vorbei.
Schalt mich mal dazwischen und probier das Problem zu lösen:
Moonlight, dein Ansatz war bzw. ist vielleicht immer noch, dass falls eine Taste gedrückt wird, du eine Methode aufrufst, die dein Sprite um paar Pixel verschiebt. Das geht dir aber zu langsam, da das KeyEvent nicht häufig genug hintereinander "gefeuert" wird.
Wildcards Lösung (siehste ja in seinem Post oben) ist deshalb:
Wird die Taste gedrückt (keyTyped) wird eine Variable umgestellt und im Thread dann die Bewegungsmethode kontinuirlich (!!) ausgeführt. Das heißt: In einem Thread wird die Methode viel öfter ausgeführt (durch die Sleep-Time kannst du Geschwindigkeit regeln).
Wird nun die Taste losgelassen (KeyReleased) so wird die Variable wieder auf standard (bei Wildcard ist es 0) gesetzt. Der Thread läuft zwar immer noch im Hintergrund aber die Methode wird mit der Bewegung in Richtung 0 gestartet. Worauf die einfach gar nichts tut.
Um bischen Performence zu sparen kannst du ja den Thread immer anhalten (aber bitte nicht per stop() ).


Ich hoffe ich habe es erklären können. Wenn nicht, dann frag einfach nochmal nach ;)
 

Moonlight1234

Bekanntes Mitglied
@all

Danke. Jetzt habe ich es verstanden.
Wenn ich das richtig verstanden habe macht man das ganze damit das Sprite auch zwischen den einzelnen tastaurimpulsen in Bewegung bleibt.

Schwere Geburt.

Kann es passieren das ein keyReleased() "verschluckt" wird?

Ist bei meinem Testlauf zwar nie passiert, hätte aber zur Folge daß das Sprite aus dem, Bild laufen würde.


Noch eine Verständnisfrage zu den Threads.

Durch das starten eines Threads wird ja das was in der run()-Methode steht paralellel zum restlichen Programm ausgeführt.

Zumindest wird das simuliert.

Wenn ich die sleep()-Methode in der run()-Methode aufrufe, bleibt also auch nur die run()-Methode an der Stelle die angegebene Zeit stehen das restliche Programm läuft weiter
Oder ist sleep() höherwertiger als der Thread?
Bleibt dann das ganze Programm die angegebe Zeit stehen.
 

Wildcard

Top Contributor
Moonlight1234 hat gesagt.:
@all

Danke. Jetzt habe ich es verstanden.
Wenn ich das richtig verstanden habe macht man das ganze damit das Sprite auch zwischen den einzelnen tastaurimpulsen in Bewegung bleibt.
ganz genau :applaus:

Moonlight1234 hat gesagt.:
Kann es passieren das ein keyReleased() "verschluckt" wird?
Ist bei meinem Testlauf zwar nie passiert, hätte aber zur Folge daß das Sprite aus dem, Bild laufen würde.
Ich will das jetzt nicht kategorisch ausschließen, aber ich hab noch nie davon gehört.
Mach dir darüber keine Gedanken.
Auf das 'aus dem Bild' laufen' musst du trotzdem aufpassen, weil der Benutzer ja auch auf der tastatur einschlafen könnte :wink:
 

Moonlight1234

Bekanntes Mitglied
Noch eine Verständnisfrage zu den Threads.

Durch das starten eines Threads wird ja das was in der run()-Methode steht paralellel zum restlichen Programm ausgeführt.

Zumindest wird das simuliert.

Wenn ich die sleep()-Methode in der run()-Methode aufrufe, bleibt also auch nur die run()-Methode an der Stelle die angegebene Zeit stehen das restliche Programm läuft weiter
Oder ist sleep() höherwertiger als der Thread?
Bleibt dann das ganze Programm die angegebe Zeit stehen.
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben