2011-11-10 14 views
2

私のプロジェクトでデフォルトのJava KeyListenerに問題があります。 KeyListenerは、開始時に転送されるKeyEventsを取得しないように見えます。JPanelのKeyListenerが無作為に応答しない

問題の症状: アプリケーションの起動時にキー入力が処理されません。これはときどき起こるだけです。ときには、これを表示するまでアプリを終了して7〜8回起動する必要があります。時にはそれが最初の試みです。それが起こると、私は再びアプリケーションを再起動するまで動作しません。

私が使っているもの: 最新のEclipseとJDKのバージョン。 私はデバッグモードでブレークポイントを入れて、JPanelのインスタンスをチェックアウトしました:私はすでに見つけた何

。 KeyListenerは常に正常に追加されます。 また、MouseListenerとMouseMotionListenerは常にうまく動作します。

最小限のコード:

public class Player implements KeyListener 
{ 
    public void keyTyped(KeyEvent e){} 
    public void keyReleased(KeyEvent e){ } 

    public void keyPressed(KeyEvent e){ 
     System.out.println("Key Pressed!"); 
    } 

} 

public class Game { 

    public static void main(String[] args) { 
     new Game(); 
    } 

    public Game(){ 
     JFrame window = new JFrame(); 
     window.setVisible(true); 

     //Now set the window size correctly 
     window.setSize(800, 600); 
     //Set-up the rest of the window 
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     window.setResizable(true); 


     //Create our panel 
     JPanel canvas = new JPanel(); 
     canvas.setFocusable(true); 
     window.add(canvas); //Add it to our window 

     Player k = new Player(); 
     canvas.addKeyListener(k); 
    } 
} 

はお時間をいただき、ありがとうございます!

PS: [OK]を、自分の質問に答える:

私がウィンドウのサイズを設定後のsetVisible(true)をを呼び出すために持っていることを思わ:

JFrame window = new JFrame(); 


    Now set the window size correctly 
    window.setSize(800, 600); 
    window.setVisible(true); 

はのsetSizeを切り替えます( )とsetVisible()はこのように動作するようです。問題なく何十回も試してみました。

サイズが0x0の場合、setVisibleはフォーカスをウィンドウに与えたくないかもしれないと思います。 問題は次のとおりです。なぜ、これが原因で問題が発生するのはなぜですか?

+1

のKeyListenerを使用しないでくださいではなく、[キーバインディング](のhttp:// download.oracle.com/javase/tutorial/uiswing/misc/keybinding.html)。それでは、焦点はそれほど大きなものではありません。 –

+1

断続的な問題は、[初期スレッド](http://download.oracle.com/javase/tutorial/uiswing/concurrency/initial.html)を常に思い出させます。 – trashgod

答えて

2

"キャンバス" JPanelにJButtonを追加し、ボタンを押して、KeyListenerに何が起こっているかを確認してください.JPanelがフォーカスを失ったために失敗します。これが起こらないようにするには、代わりにKey Bindingsを使用してください(上の私のコメントのリンクを参照してください)。これはあなたの問題に関連している場合、例えば、

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

@SuppressWarnings("serial") 
public class Game2 { 

    private static final String UP = "up"; 

    public static void main(String[] args) { 
     new Game2(); 
    } 

    public Game2() { 
     JFrame window = new JFrame("Press up-arrow key"); 
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     JPanel canvas = new JPanel(); 
     canvas.setPreferredSize(new Dimension(400, 300)); 
     window.add(canvas); 

     canvas.add(new JButton(new AbstractAction("Press space-bar") { 
     public void actionPerformed(ActionEvent e) { 
      System.out.println("Button or space-bar pressed"); 
     } 
     })); 
     ActionMap actionMap = canvas.getActionMap(); 
     int condition = JComponent.WHEN_IN_FOCUSED_WINDOW; 
     InputMap inputMap = canvas.getInputMap(condition); 

     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP); 
     actionMap.put(UP, new UpAction()); 

     window.pack(); 
     window.setLocationRelativeTo(null); 
     window.setVisible(true); 
    } 
} 

@SuppressWarnings("serial") 
class UpAction extends AbstractAction { 
    @Override 
    public void actionPerformed(ActionEvent arg0) { 
     System.out.println("Up Arrow pressed!"); 
    } 
} 
+0

サンプルコードをありがとう。私はすでにあなたのリンクを読んでいます。それはなぜエラーがランダムに発生するのかという疑問を残します。 – s3rius

1

が分からないのですが、原因それの断続的な性質のために、おそらくそれがあるために...あなたはのsetVisible()の最後とスイングスレッドで実行する必要があります。あなたが望むならsetVisibleの後にsetSizeを呼び出すことができますが、ユーザはフリッカーを見るかもしれませんし、同様にスイングスレッドで行うべきです。あなたの最後のステップとしてこれを行います。

SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
     window.setVisible(true); 
    } 
}); 

はこれを行うには、あなたはまた、ウィンドウの宣言は、最終的にする必要があります。

... 
final JFrame window = new JFrame(); 
... 
+0

最初のsetSize()の後にsetVisible()を呼び出すと問題が解決するので、これもうまくいくはずです。タイトルバー/枠線のサイズを取得するためにFrames Insetsを取得したかったからです。これは事前にsetVisible()を呼び出すときにのみ機能します。 – s3rius