keylistener在活动渲染时不工作

时间:2016-05-29 14:28:54

标签: java swing graphics

我正在尝试用Java编写一个非常简单的平台游戏。我有部分工作与被动渲染(Timer对象调用repaint()revalidate()等。但我一直在尝试实现主动渲染。它有点工作 - 它呈现,动画有效,但它似乎阻止了关键的Listener(以前工作正常)由于某种原因,我真的不明白。

我在下面尽可能少地重新创建了这个问题。当你按一个键时,应该有终端输出,但没有。如果有人能告诉我为什么keyPressed等方法没有解雇,那将非常感激。

修改 - 根据请求将修改后的演示代码整理为一个副本/粘贴

Edit2 - 正如Andrew Thompson所建议的那样,我删除了所有的全屏代码,并且keylistener仍无法正常工作

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;

class FullScreenRenderWithListener implements KeyListener {

   private JFrame frame;
   private World  world;

   public static void main(String[] args)
   {
      FullScreenRenderWithListener main = new FullScreenRenderWithListener();
      SwingUtilities.invokeLater(main::run);
   }

   private void run()
   {
      initWindow();
      setupWorld();
      frame.setIgnoreRepaint(true);
      frame.pack();
      frame.createBufferStrategy(2);
      frame.setVisible(true);
      world.startActive(frame.getBufferStrategy());
   }

   private void initWindow()
   {
      frame = new JFrame();
      frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
      frame.setLocationByPlatform(true);
   }

   private void setupWorld()
   {
      world = new World();
      frame.addKeyListener(this);
      frame.add(world);
      world.addKeyListener(this);
   }

   @Override
   public void keyPressed(KeyEvent event)
   {
      System.out.println("Pressed");
   }

   @Override
   public void keyReleased(KeyEvent event)
   {
      System.out.println("Released");
   }

   @Override
   public void keyTyped(KeyEvent event)
   {
      System.out.println("Typed");
   }
}

class World extends JPanel {

   private static final int FRAMES_PER_SEC = 60;
   private static final int MILL_IN_SEC    = 1000;
   private static final int TICK_LENGTH    =
      MILL_IN_SEC / FRAMES_PER_SEC;
   private BufferStrategy strategy;

   private void sleepUntilEndOfFrame()
   {
      try {
         long used = System.currentTimeMillis() % TICK_LENGTH;
         long left = TICK_LENGTH - used;
         Thread.sleep(left);
      } catch(InterruptedException e) {
         // ... Handle this error
      }
   }

   public void startActive(BufferStrategy strategy)
   {
      this.strategy = strategy;
      setIgnoreRepaint(true);
      while(true) {
         doFrame();
      }
   }

   private void doFrame()
   {
      updateGameState();
      activeRenderFrame();
   }

   private void updateGameState()
   {
      // ..
   }

   private void activeRenderFrame()
   {
      Graphics2D graphicsContext = (Graphics2D)strategy
         .getDrawGraphics();
      paintComponent(graphicsContext);
      strategy.show();
      Toolkit.getDefaultToolkit().sync();
      graphicsContext.dispose();
      sleepUntilEndOfFrame();
   }

   @Override
   public Dimension getPreferredSize()
   {
      return new Dimension(500, 500);
   }


   // Have overridden this method because the class
   // also implements passive rendering if active is
   // not supported
   @Override
   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      // .. drawing code
   }
}

1 个答案:

答案 0 :(得分:1)

首要问题是,当您使用KeyBinding时,不要考虑使用KeyListener策略而不是JPanel。您可以通过注释无限while循环(禁用活动渲染)来检查这一点。

当您使用KeyListener时,不会使用有效渲染过程触发{或者至少我们可以说我们的侦听器未调用)。

使用KeyEvent可以解决此问题。

但是当您取消注释无限keyBinding循环时,问题会再次出现。那么什么能解决这个问题呢?用于更新框架的新while是关键!

检查由Thread提升的程序以及使用有效呈现策略更新框架的新KeyBinding

Thread

此示例仅为箭头键绑定了一些import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.image.BufferStrategy; import java.util.HashMap; import java.util.Map; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; public class FullScreenRenderWithListener implements Runnable { private JFrame frame; private World world; public static void main ( String[] args ) { FullScreenRenderWithListener main = new FullScreenRenderWithListener (); SwingUtilities.invokeLater ( main ); } public void run () { initWindow (); setupWorld (); frame.setIgnoreRepaint ( true ); frame.pack (); frame.createBufferStrategy ( 2 ); frame.setVisible ( true ); world.startActive ( frame.getBufferStrategy () ); } private void initWindow () { frame = new JFrame (); frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE ); frame.setLocationByPlatform ( true ); } private void setupWorld () { world = new World (); frame.add ( world ); frame.setFocusable ( true ); world.setFocusable ( true ); } } class World extends JPanel { private static final int FRAMES_PER_SEC = 10; private static final int MILL_IN_SEC = 1000; private static final int TICK_LENGTH = MILL_IN_SEC / FRAMES_PER_SEC; private BufferStrategy strategy; // private static final String PRESSED = "Pressed"; private static final String RELEASED = "Released"; private Map < Direction , Boolean > directionMap = new HashMap < Direction , Boolean > (); private void sleepUntilEndOfFrame () { try { long used = System.currentTimeMillis () % TICK_LENGTH; long left = TICK_LENGTH - used; Thread.sleep ( left ); } catch ( InterruptedException e ) { // ... Handle this error e.printStackTrace (); } } private void setBindings() { int context = JComponent.WHEN_IN_FOCUSED_WINDOW; InputMap inputMap = getInputMap(context); ActionMap actionMap = getActionMap(); for (Direction direction : Direction.values()) { inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, false), direction.getName() + PRESSED); inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, true), direction.getName() + RELEASED); // set corresponding actions for the key presses and releases above actionMap.put(direction.getName() + PRESSED, new ArrowKeyAction(true, direction)); actionMap.put(direction.getName() + RELEASED, new ArrowKeyAction(false, direction)); } } public void startActive ( BufferStrategy strategy ) { for ( Direction direction : Direction.values () ) { directionMap.put ( direction , Boolean.FALSE ); } setBindings (); // this.strategy = strategy; setIgnoreRepaint ( true ); Thread t = new Thread (){ @Override public void run () { while ( true ) { doFrame (); } } }; t.start (); } private void doFrame () { updateGameState (); activeRenderFrame (); } private void updateGameState () { // .. } private void activeRenderFrame () { Graphics2D graphicsContext = (Graphics2D) strategy.getDrawGraphics (); paintComponent ( graphicsContext ); strategy.show (); Toolkit.getDefaultToolkit ().sync (); graphicsContext.dispose (); sleepUntilEndOfFrame (); } @Override public Dimension getPreferredSize () { return new Dimension ( 500 , 500 ); } // Have overridden this method because the class // also implements passive rendering if active is // not supported @Override public void paintComponent ( Graphics g ) { super.paintComponent ( g ); // .. drawing code } private class ArrowKeyAction extends AbstractAction { private Boolean pressed; private Direction direction; public ArrowKeyAction ( boolean pressed , Direction direction ) { this.pressed = Boolean.valueOf ( pressed ); this.direction = direction; } @Override public void actionPerformed ( ActionEvent arg0 ) { directionMap.put ( direction , pressed ); System.out.println ("Direction: "+ direction + ", State: " + pressed); } } } enum Direction { UP("Up", KeyEvent.VK_UP, new Point(0, -1)), DOWN("Down", KeyEvent.VK_DOWN, new Point(0, 1)), LEFT("Left", KeyEvent.VK_LEFT, new Point(-1, 0)), Right("Right", KeyEvent.VK_RIGHT, new Point(1, 0)); private String name; private int keyCode; private Point vector; private Direction(String name, int keyCode, Point vector) { this.name = name; this.keyCode = keyCode; this.vector = vector; } public String getName() { return name; } public int getKeyCode() { return keyCode; } public Point getVector() { return vector; } @Override public String toString() { return name; } } 。您也可以通过更改KeyBinding方法查看其他键。此外,您可能希望为其他键定义更多setBindings s和另一个Event

希望这有帮助。