如何强制Java处理事件?

时间:2019-02-06 13:20:23

标签: java events

我正在尝试用Java 8创建一个简单的游戏,但我遇到了Swing线程处理问题。

我已经决定编写自己的游戏循环,但是Swing很难理解我想要达到的目标。

下面,我包括程序的精简版本。只是一些初始化和我的游戏循环。

public class Main extends JFrame {
    App app;

    public Main () {
        createApp ();
        add ( app );
        pack ();
    }

    private void createApp () {
        app = new App ();
    }

    public void start () {
        setVisible ( true );

        SwingUtilities.invokeLater ( new Runnable () {
            public void run () {
                app.run ();
            }
        });
    }

    public static void main ( String [] args ) {
        SwingUtilities.invokeLater ( new Runnable () {
            public void run () {
                Main main = new Main ();
                main.start ();
            }
        });
    }
}

public class App extends JPanel {
    private boolean _running;
    private int _maxFPS = 1;
    private int _draw_dt;

    public App () {
        setFocusable ( true );
        requestFocus ();
        addKeyListener ( new _KeyAdapter () );
    }

    public void run () {
        /*
         * enter the game loop
         */
        long nextUpdateTime = System.currentTimeMillis ();
        long nextRenderTime = nextUpdateTime;
        long lastUpdateTime = nextUpdateTime;

        int TPF = 1000 / _maxFPS;
        int TPU = 1000 / 60;

        _running = false;
        while ( _running ) {
            /*
             * update till the game catches up
             */
            while ( nextUpdateTime <= System.currentTimeMillis () ) {
                _update ();
                lastUpdateTime = nextUpdateTime;
                nextUpdateTime += TPU;
            }

            /*
             * draw, if it won't exceed _maxFPS
             */
            long currentTime = System.currentTimeMillis ();
            if ( nextRenderTime <= currentTime ) {
                paintImmediately (0, 0, getWidth (), getHeight ());
                nextRenderTime = currentTime + TPF;
                _draw_dt = (int) (currentTime - lastUpdateTime);
            }

            /*
             * don't burn cycles unneccessary
             */
            long waitTime = Math.min ( nextUpdateTime, nextRenderTime ) - System.currentTimeMillis ();
            if ( waitTime > 0 )
                try {
                    Thread.sleep ( waitTime );
                } catch ( Exception e ) {
                    e.printStackTrace ();
                }
        }
    }

    private void _update () {
    }

    public void paintComponent ( Graphics g_ ) {
    }

    private class _KeyAdapter extends KeyAdapter {
        public void keyPressed ( KeyEvent e ) {
            System.out.println ( "genetating an event" );
        }
    }   
}

问题是,java忙于运行我的循环(即使Thread.sleep()),以至于它从不处理事件。

如果我关闭游戏循环,它将按预期工作。

我实际上在渲染上也遇到了类似的问题,因此我正在使用renderImmediately()。我实际上正在寻找一种对Java说的方式:“停止!我在这里等待,直到您在每个循环周期内处理所有事件为止,但是到目前为止我还没有运气...

1 个答案:

答案 0 :(得分:0)

不确定程序打算做什么(因为_update方法为空)。

无论如何,App.run方法当前由摆动线程执行。您不应占用过多的摆动线程(否则,您的窗口不会被重新绘制,事件不会被处理等)。而且此方法永远不会返回,因此摆动线程始终被占用。

作为解决方法,我们可以打破大循环并使用执行程序服务定期运行它:

public class App extends JPanel {
  private static final long serialVersionUID = 1L;

  public App() {
    setFocusable(true);
    requestFocus();
    addKeyListener(new _KeyAdapter());
  }

  ScheduledExecutorService es = Executors.newScheduledThreadPool(4);

  public void run() {
    es.scheduleAtFixedRate(this::appLoop, 100, 100, TimeUnit.MILLISECONDS);
  }

  private void appLoop() {
    /*
     * draw, if it won't exceed _maxFPS
     */
    paintImmediately(0, 0, getWidth(), getHeight());
  }

  private void _update() {}

  public void paintComponent(Graphics g_) {}

  private class _KeyAdapter extends KeyAdapter {
    public void keyPressed(KeyEvent e) {
      System.out.println("genetating an event");
    }
  }
}