Вывод Java Key Bindings на консоль при нажатии клавиши

Я пытаюсь сделать программу, которая перемещает прямоугольник по экрану при нажатии клавиш со стрелками. На данный момент я работаю над привязками клавиш после того, как KeyListeners оказались ненадежными и довольно бесполезными. Прежде чем пытаться заставить прямоугольник двигаться, я просто пытаюсь заставить нажатие клавиши со стрелкой вверх вызвать System.out.println("Up key pressed!"), просто чтобы убедиться, что мои KeyBindings действительно работают. Проблема в том, что это не так. Я следую этому учебник, который немного отличается от того, что я пытаюсь достичь, но все же должен научить меня, как использовать привязки клавиш. Почему KeyBinding не работает?

Код:

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


public class GamePanel extends JPanel implements Runnable{

    boolean isRunning = true;
    int count = 0;
    Thread t;
    static int rectX = 250;
    static int rectY = 250;
    Action upAction;
    Action downAction;
    Action leftAction;
    Action rightAction;

    public GamePanel()
    {
        upAction = new UpAction();
        t = new Thread(this);
        t.run();
        /*downAction = new DownAction();
        leftAction = new LeftAction();
        rightAction = new RightAction();*/
        this.getInputMap().put(KeyStroke.getKeyStroke("UP"), "upMotion");
        this.getActionMap().put("upMotion",upAction);

    }
    public void run()
    {
        loop();
    }
    public void loop()
    {
        if(isRunning)
        {
            Thread t = Thread.currentThread();
            try
            {
            t.sleep(5);
            }
            catch(InterruptedException e)
            {
                e.printStackTrace();
            }
            repaint();
        }

    }
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        count += 1;
        g.drawString(Integer.toString(count), 10, 10);
        g.drawRect(rectX, rectY, 50, 50);
        loop();
    }
    static class UpAction extends AbstractAction
    {
        public void actionPerformed(ActionEvent e)
        {
            System.out.println("Up key pressed!");
            rectY++;
        }
    }
}

Основной код JFrame:

import javax.swing.*;

public class MainFrame{

    JFrame frame = new JFrame("Space Invaders");
    GamePanel gamepanel = new GamePanel();

    public MainFrame()
    {
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setSize(500,500);
        frame.setLocationRelativeTo(null);
        frame.add(gamepanel);
    }
    public static void main(String[] args)
    {
        new MainFrame();
    }


}

person imulsion    schedule 28.07.2014    source источник
comment
где твоя главная? не могу запустить этот код.   -  person kai    schedule 28.07.2014
comment
@kai Мой основной код просто создает JFrame и добавляет к нему этот класс как JPanel   -  person imulsion    schedule 28.07.2014
comment
Этот цикл плохой. Это остановит текущий поток, вызвавший конструктор, поэтому у вас не может быть запущенной панели (кроме случаев, когда вы экспортируете this из конструктора). Попробуйте запустить метод loop в новом потоке.   -  person kajacx    schedule 28.07.2014
comment
добавьте свой основной код, чтобы я мог его запустить.   -  person kai    schedule 28.07.2014
comment
Рамку хоть видно? вы создаете new GamePanel(); в своем фрейме (и эта инициализация будет вызываться непосредственно перед конструктором фрейма), но ваш конструктор GamePanel останавливает текущий поток, поэтому вы ничего не увидите. Я прав?   -  person kajacx    schedule 28.07.2014
comment
@kajacx Я отредактировал свой код. И нет, даже до того, как я отредактировал, я все еще видел быстро увеличивающееся число и нарисованный прямоугольник   -  person imulsion    schedule 28.07.2014
comment
1. Thread.sleep(5); находится под задержкой для большинства современных ОС, 2. Thread.sleep(5); блокировать EDT до тех пор, пока if(isRunning) не закончится   -  person mKorbel    schedule 28.07.2014
comment
@mKorbel Я не понимаю. Можете ли вы объяснить дальше?   -  person imulsion    schedule 28.07.2014
comment
петля(); вызывается из 1. всех событий мыши и клавиш, 2. методов, реализованных в API, 3. наиболее важного из бесконечного клонирования, вызываемого repaint() внутри if(isRunning)   -  person mKorbel    schedule 28.07.2014
comment
@mKorbel Да, я хочу, чтобы он вызывался бесконечно; который работает как игровой цикл   -  person imulsion    schedule 28.07.2014
comment
короткий ответ 1. используйте Swing Timer, забыл по идее вызвать recrusive loop(); == создание бесконечного, неуправляемого цикла, 3. задержка (минимальное значение) должна быть 25/33/50 миллисекунд, зависит от родной ОС и графического процессора   -  person mKorbel    schedule 28.07.2014
comment
Да, я хочу, чтобы его вызывали бесконечно; == по этой причине есть цикл, но вызов loop(); from public void paintComponent(Graphics g) умножьте эту безумную идею :-)   -  person mKorbel    schedule 28.07.2014
comment
@mKorbel Изменение задержки на 25 сработало! Спасибо!   -  person imulsion    schedule 28.07.2014
comment
@mKorbel И ... после того, как я запустил его, а затем закрыл, я снова запустил его, и он перестал работать.   -  person imulsion    schedule 28.07.2014
comment
похожие вопросы задают 3-5 раз в день, вы можете увеличить свои шансы, нажав на тег paintComponent или KeyBindings   -  person mKorbel    schedule 28.07.2014


Ответы (1)


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

public GamePanel() {
    ...
    setFocusable(true); //add this anywhere in this constructor 
}

public MainFrame() {
    ...
    frame.add(gamepanel);
    gamepanel.requestFocusInWindow();
    //add this after adding the panel to your frame and making it visible
}

ИЗМЕНИТЬ:

Кроме того, ваш код имеет несколько ошибок:

  • Движение вверх должно быть y--, так как верхний левый угол имеет координаты [0,0], ось x направлена ​​вправо, а ось y направлена ​​вниз (в отличие от урока математики).
  • Вы не должны никогда вызывать Thread.sleep() внутри метода paint(), так как этот метод должен быть максимально быстрым.
  • Вы «запускаете» новый поток, используя thread.run(), вместо этого используйте thread.start(), который фактически запустит новый поток, а не просто вызов метода run в текущем потоке.
  • Измените if на while в методе loop, а также удалите вызов loop из метода paint, чтобы устранить две предыдущие ошибки.

Это не для того, чтобы критиковать вас (все когда-то начинали), а для того, чтобы помочь вам.

person kajacx    schedule 28.07.2014
comment
После предложения mKorbel изменить задержку Thread.sleep() на 25, привязки клавиш работали без этого. Однако они несовместимы - person imulsion; 28.07.2014
comment
Должен ли я использовать public void start(){...} или вызов run() запустит поток? - person imulsion; 28.07.2014
comment
Google Java thread run vs start и выберите любую ссылку, которую хотите...: 3 - person kajacx; 28.07.2014
comment
KeyBindings имеет настройку для Focus, реализованную в API по умолчанию, тогда все, что касается Focus, не является ответом на вопрос OP. - person mKorbel; 28.07.2014
comment
Спасибо за вашу помощь. Теперь я могу перемещать прямоугольник по экрану!! Достижения усиливаются - person imulsion; 28.07.2014