问题
KeyListener doesn't work at all it's like it's not there, it shows the frame with the paddle but it doesn't move when arrowkey pressed , BUT my code worked properly on my friend's computer , i deleted and installed the last version of JDK and eclipse and nothing changed , i even compilated it with cmd and it doesn't work
edit : one in a 100 tries it works properly then the next time it returns to not working
the code is about a paddle that moves with arrowkeys
the Paddle class :
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
public class Paddle extends JPanel implements KeyListener{
private int x=900,y=280 ;
private int sx=20,sy=20 ;
private int valY=0;
public Paddle() {
setFocusable(true);
requestFocus();
addKeyListener(this);
}
public void paintComponent(Graphics g) {
draw(g);
update();
repaint();
}
public void draw(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, 1000, 1000);
g.setColor(Color.ORANGE);
g.fillRect(x, y, sx, sy);
}
public void update() {
this.y+=this.valY;
}
public void keyTyped(KeyEvent e) {
System.out.println("typed");
}
public void keyPressed(KeyEvent e) {
System.out.println("typed");
int c=e.getKeyCode();
if (c==KeyEvent.VK_UP){
this.valY=-1;
}
if(c==KeyEvent.VK_DOWN){
this.valY=1;
}
}
public void keyReleased(KeyEvent e) {
valY=0;
}
}
回答1:
You are violating some rules of custom painting. The fact that it worked at all was mostly luck.
First, remove your call to repaint()
. It is causing paintComponent to be called again, which calls repaint, which calls paintComponent, which calls repaint, etc. You are creating a very fast infinite loop which uses up most of Swing’s resources. Instead, call repaint()
whenever you change the data on which your drawing relies.
Second, you are not accounting for the fact that painting occurs for many reasons. You don’t control most of them. paintComponent may be called when you move or resize the window, or even when the mouse moves over the window, or for a number of other reasons.
Since it is impossible to predict when the system will request that your class paint its contents, you must not change the state of your object in paintComponent. You must not call your update()
method from paintComponent, either directly or indirectly.
The correct way to regularly update your state is to call your updating method from a Timer. For instance:
// Update every 250 milliseconds, that is, 4 times per second.
Timer timer = new Timer(250, e -> update());
timer.start();
Finally, whenever you override paintComponent, the first line of code needs to be a call to super.paintComponent(g);
. If you don’t do that, you will eventually see strange painting artifacts. This is discussed in the Performing Custom Painting tutorial.
回答2:
Your issue appears to have to do with the KeyListener and Focus. I am going to suggest an alternative technique. Use the InputMap/ActionMap for the panel.
KeyStroke us = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
panel.getInputMap().put(us, "UP");
panel.getActionMap().put("UP", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
//call what ever
}
});
When I do this, I don't have to request focus, I have a JFrame and a JPanel, as long as the JFrame is focus, then the respective actions get triggered by the keys.
Here is a complete example that moves a circle around a JPanel.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.EventQueue;
import java.awt.Color;
import javax.swing.KeyStroke;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
public class BallGame{
int x;
int y;
JPanel panel = new JPanel(){
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.drawOval(x-5, y-5, 10, 10);
}
};
public void start(){
JFrame frame = new JFrame();
frame.add(panel);
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
KeyStroke us = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
KeyStroke ds = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false);
KeyStroke ls = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false);
KeyStroke rs = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);
panel.getInputMap().put(us, "UP");
panel.getInputMap().put(ds, "DOWN");
panel.getInputMap().put(ls, "LEFT");
panel.getInputMap().put(rs, "RIGHT");
panel.getActionMap().put("UP", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
up();
}
});
panel.getActionMap().put("DOWN", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
down();
}
});
panel.getActionMap().put("LEFT", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
left();
}
});
panel.getActionMap().put("RIGHT", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
right();
}
});
}
public void up(){
y = y - 5;
y = y<0? panel.getHeight() : y;
panel.repaint();
}
public void down(){
y = y + 5;
y = y>panel.getHeight() ? 0 : y;
panel.repaint();
}
public void left(){
x = x - 5;
x = x<0 ? panel.getWidth() : x;
panel.repaint();
}
public void right(){
x = x + 5;
x = x>panel.getWidth() ? 0 : x;
panel.repaint();
}
public static void main(String[] args){
BallGame bg = new BallGame();
EventQueue.invokeLater( bg::start );
}
}
Check out the api though because you can tune it to catch modifiers and when to trigger the action. In case you want to monitor when the key is pressed and when it is released etc.
来源:https://stackoverflow.com/questions/60879613/keylistener-doesnt-work-at-all-but-my-code-worked-fine-on-my-friends-computer