【问题标题】:KeyListener doesn't work at all but my code worked fine on my friend's computerKeyListener 根本不起作用,但我的代码在我朋友的计算机上运行良好
【发布时间】:2020-03-27 03:29:27
【问题描述】:

KeyListener 根本不起作用就像它不存在一样,它显示带有桨的框架,但是当按下箭头键时它不会移动,但是 我的代码在我的朋友的电脑,我删除并安装了最新版本的JDK和eclipse,没有任何变化,我什至用cmd编译它也不起作用
编辑: 100 次尝试中的一次它可以正常工作,然后下次它返回不工作 代码是关于用箭头键移动的桨 桨类:

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;
    }
}

【问题讨论】:

  • KeyListener 要求组件被聚焦。如果您使用侦听器单击或关闭组件,您将一无所获,这可能是您发生的事情。使用key bindings 来避免此类问题。
  • 我认为在构造函数中请求焦点可能会失败。

标签: java eclipse swing keylistener


【解决方案1】:

您违反了一些自定义绘画规则。事实上,它的工作主要是运气。

首先,删除您对repaint() 的呼叫。它导致paintComponent 被再次调用,它调用repaint,它调用paintComponent,它调用repaint 等等。你正在创建一个非常快速的无限循环,它会占用Swing 的大部分资源。相反,每当您更改绘图所依赖的数据时,请致电 repaint()

其次,你没有考虑到绘画的发生有很多原因。你不能控制他们中的大多数。 paintComponent 可能会在您移动或调整窗口大小时调用,甚至当鼠标移到窗口上方时,或出于许多其他原因。

由于无法预测系统何时会请求您的类绘制其内容,因此您不得在paintComponent 中更改对象的状态。您不能直接或间接地从paintComponent 调用您的update() 方法。

定期更新状态的正确方法是从Timer 调用更新方法。例如:

// Update every 250 milliseconds, that is, 4 times per second.
Timer timer = new Timer(250, e -> update());
timer.start();

最后,无论何时重写paintComponent,第一行代码都需要调用super.paintComponent(g);。如果你不这样做,你最终会看到奇怪的绘画文物。这在Performing Custom Painting 教程中进行了讨论。

【讨论】:

    【解决方案2】:

    您的问题似乎与 KeyListener 和 Focus 有关。我将建议一种替代技术。为面板使用 InputMap/ActionMap。

    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
       }
    });
    

    当我这样做时,我不必请求焦点,我有一个 JFrame 和一个 JPanel,只要 JFrame 是焦点,那么相应的动作就会被按键触发。

    这是一个围绕 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 );
        }
    
    }
    

    查看 api,因为您可以调整它以捕获修饰符以及何时触发动作。如果您想监视何时按下键以及何时释放等。

    【讨论】:

      猜你喜欢
      • 2021-12-27
      • 1970-01-01
      • 2020-02-11
      • 2014-11-12
      • 2017-06-16
      • 1970-01-01
      • 2018-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多