KeyListener не работает вообще, но мой код работал нормально на компьютере моего друга - PullRequest
2 голосов
/ 27 марта 2020

KeyListener вообще не работает похоже, что его там нет, он показывает рамку с веслом, но не перемещается при нажатии клавиши со стрелкой, НО мой код работал правильно на моем друге компьютер , я удалил и установил последнюю версию JDK и Eclipse, и ничего не изменилось, я даже скомпилировал его с помощью cmd, и он не работает
edit: один из 100 пытается работать правильно, а затем в следующий раз возвращается к неработающему коду, речь идет о весле, которое перемещается с помощью стрелок класса Paddle:

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

Ответы [ 2 ]

2 голосов
/ 27 марта 2020

Вы нарушаете некоторые правила пользовательской росписи. Тот факт, что это сработало, был в основном удачей.

Сначала удалите ваш звонок на repaint(). Это вызывает повторный вызов paintComponent, который вызывает repaint, который вызывает paintComponent, который вызывает repaint, et c. Вы создаете очень быстрый бесконечный l oop, который использует большую часть ресурсов Swing. Вместо этого вызывайте repaint() всякий раз, когда вы изменяете данные, на которые опирается ваш чертеж.

Во-вторых, вы не учитываете тот факт, что рисование происходит по многим причинам. Вы не контролируете большинство из них. paintComponent может вызываться при перемещении или изменении размера окна, или даже когда мышь перемещается над окном, или по ряду других причин.

Поскольку невозможно предсказать, когда система запросит ваш класс рисовать его содержимое, вы не должны изменять состояние вашего объекта в paintComponent. Вы не должны вызывать ваш метод update() из paintComponent, прямо или косвенно.

Правильный способ регулярно обновлять ваше состояние - вызывать ваш метод обновления из Timer . Например:

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

Наконец, всякий раз, когда вы переопределяете paintComponent, первой строкой кода должен быть вызов super.paintComponent(g);. Если вы этого не сделаете, вы в конечном итоге увидите странные артефакты рисования. Это обсуждается в учебнике Выполнение пользовательской живописи .

1 голос
/ 27 марта 2020

Ваша проблема, по-видимому, связана с 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, хотя вы можете настроить его, чтобы ловить модификаторы и когда для запуска действия. Если вы хотите контролировать, когда клавиша нажата и когда она отпущена, et c.

...