Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

キーイベントがうまく動きません

awtを利用してのGUIプログラミングで○×ゲームのようなものを作っています。
3×3のボタンを作り、それをマウスでクリックするか対応するテンキーを押せえばボタンの色が変わる、というような感じで作っているのですが、マウスには反応してもキーボードには反応してくれません。
いろいろ調べたのですが原因がわからなかったのでここで質問させてもらいました。
分かる人がいたらよろしくお願いします
以下がソースになります。

import java.awt.*;
import java.awt.event.*;

class OXButton extends Button{
    private static int count;
    boolean pushable;
    private int numButton;
    
    public OXButton(int _numButton){
        super(Integer.toString(_numButton));
        this.addActionListener(new OXButtonListener());
        this.setBackground(Color.white);
        this.pushable = true;
        this.numButton = _numButton;
    }

    public int getNumButton(){
        return numButton; 
    }
    
    public static void countPlus(){count++;}
    public static int getCount(){return count;}
    
    public class OXButtonListener implements ActionListener{
        public void actionPerformed(ActionEvent e){
            OXButton b = (OXButton)e.getSource();
            if(pushable){
                pushable = false;
                if(count % 2 == 0){
                    b.setBackground(Color.red);
                }else{
                    b.setBackground(Color.blue);
                }
                count++;
                //System.out.println("pushed");
            }
        }
    }
}

class OXGame extends Frame{
    OXButton[] btn;
    private static int num;
    
    public OXGame(){
        super("OXGame");
        btn = new OXButton[9];
        
        for(num = 0;num<9;num++){
            btn[num] = new OXButton(num+1);
        }
            
        this.setLayout(new GridLayout(3,3));
        
        
        for(num=6;num<9;num++)
            add(btn[num]);
        for(num=3;num<6;num++)
            add(btn[num]);
        for(num=0;num<3;num++)
            add(btn[num]);
        
        this.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e){
                //System.out.println("exit");
                System.exit(1);
            }
        });
        this.addKeyListener(new KeyAdapter(){
            public void keyReleased(KeyEvent e){
                //int keyCode; 
                //OXButton b = (OXButton)e.getSource();
                
                System.out.println("key press");
                
                switch(e.getKeyCode()){
                case KeyEvent.VK_1:
                    buttonPushed(0);
                    break;
                case KeyEvent.VK_2:
                    buttonPushed(1);
                    break;
                case KeyEvent.VK_3:
                    buttonPushed(2);
                    break;
                case KeyEvent.VK_4:
                    buttonPushed(3);
                    break;
                case KeyEvent.VK_5:
                    buttonPushed(4);
                    break;
                case KeyEvent.VK_6:
                    buttonPushed(5);
                    break;
                case KeyEvent.VK_7:
                    buttonPushed(6);
                    break;
                case KeyEvent.VK_8:
                    buttonPushed(7);
                    break;
                case KeyEvent.VK_9:
                    buttonPushed(8);
                    break;
                }
            }
        });
    }

    public Dimension getPreferredSize(){
        return new Dimension(180+0,220+0);
    }
    
    public void buttonPushed(int num){
        if(btn[num].pushable){
            if(OXButton.getCount() % 2 == 0)
                btn[num].setBackground(Color.red);
            else btn[num].setBackground(Color.blue);
        }
        btn[num].pushable=false;
        OXButton.countPlus();
    }
    
    public static void main(String[] args){
        OXGame ox = new OXGame();
        ox.pack();
        ox.show();
        
    }
}

12

回答

5377

閲覧

12件の回答

評価

0

>いろいろ調べた
どこを…?

評価

0

KeyAdapterの使い方などです
あとソース中KeyReleasedとなっていますが、Pressedから変更したものを直し忘れてました。

評価

0

>switch(e.getKeyCode())
この箇所が意図したように動作していないと予想。

評価

0

http://www.infoaomori.ne.jp/~sekiai/applet-page/applet22.html

ここを見ると「switch(e.getKeyCode())」を使っているので多分大丈夫かと思います。
デバッグ用に入れている「System.out.println("key press");」がコンソールに表示されないのでそもそもkeyPressed自体が動いてないみたいです。

評価

0

ざっと見たら、そもそもリスナーを登録してないじゃん。。。

評価

0

リスナーは登録してるよ。
でも、キーイベントがフォーカスのあるボタンにとられてる?から、以下のようにするといいかもしれない。

for(num = 0;num<9;num++){
  btn[num] = new OXButton(num+1);
  btn[num].setFocusable(false); // <-------------
}

評価

0

>リスナーは登録してるよ。
いやいや。。。
Frameに登録してるけど、ボタンに登録してないがね。
この文脈からは、focusableプロパティを設定する必要などないと思うが。
その後、focusableプロパティを設定する必要が出て来るかどうかは知らん。

評価

0

aaaさんの1行を追加したらできました。
フォーカスについて勉強しようと思います。
リスナに関してはFrameに登録し、押されたキーを判別してボタンに対して操作を行っています。
皆さんありがとうございました。

評価

30

蛇足かもしれんけど、以下のようにKeyboardFocusManagerとKeyEventDispatcherを使うサンプルもよく見かける。

import java.awt.*;
import java.awt.event.*;
class OXButton extends Button implements ActionListener {
  private static int count;
  public  static int getCount() { return count; }
  public  static void countPlus() { count++; }
  private final int numButton;
  public OXButton(int _numButton) {
    super(Integer.toString(_numButton));
    this.numButton = _numButton;
    this.addActionListener(this);
    this.setBackground(Color.WHITE);
  }
  public int getNumButton() {
    return numButton;
  }
  private boolean pushable = true;
  public void actionPerformed(ActionEvent e) {
    if(pushable){
      //System.out.println("pushed");
      pushable = false;
      setBackground((count%2==0)?Color.RED:Color.BLUE);
      count++;
    }
  }
}
public class OXGame extends Frame{
  private final OXButton[] btn = new OXButton[9];
  private static int num;
  public OXGame(){
    super("OXGame");
    for(num=0;num<9;num++) {
      btn[num] = new OXButton(num+1);
      //btn[num].setFocusable(false);
    }
    KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
      public boolean dispatchKeyEvent(KeyEvent e) {
        if(e.getID()==KeyEvent.KEY_PRESSED) {
          switch(e.getKeyCode()) {
          case KeyEvent.VK_1: btn[0].actionPerformed(null); break;
          case KeyEvent.VK_2: btn[1].actionPerformed(null); break;
          case KeyEvent.VK_3: btn[2].actionPerformed(null); break;
          case KeyEvent.VK_4: btn[3].actionPerformed(null); break;
          case KeyEvent.VK_5: btn[4].actionPerformed(null); break;
          case KeyEvent.VK_6: btn[5].actionPerformed(null); break;
          case KeyEvent.VK_7: btn[6].actionPerformed(null); break;
          case KeyEvent.VK_8: btn[7].actionPerformed(null); break;
          case KeyEvent.VK_9: btn[8].actionPerformed(null); break;
          }
        }
        return false;
      }
    });
    this.setLayout(new GridLayout(3,3));
    for(num=6;num<9;num++) add(btn[num]);
    for(num=3;num<6;num++) add(btn[num]);
    for(num=0;num<3;num++) add(btn[num]);
    this.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(1);
      }
    });
  }
  public Dimension getPreferredSize() {
    return new Dimension(180+0,220+0);
  }
  public static void main(String[] args) {
    OXGame ox = new OXGame();
    ox.pack();
    ox.show();
  }
}

評価

0

>蛇足かもしれんけど、以下のようにKeyboardFocusManagerとKeyEventDispatcherを使うサンプルもよく見かける。
「よく見かける」?本気で言ってるんですか。

単純なKeyListenerで済むことをわざわざ、
KeyboardFocusManagerなんて使う意味がない。
KeyboardFocusManagerは、主にフォーカス制御に使用すべきものです。

本当に、本気でこんなコードを書いてる人がいるんなら、
センスもないうえに、コードの保守性、拡張性について、想像力が無さすぎ。

特に質問者が初心者みたいなのに、こんなコードを示すべきじゃないと思う。

評価

0

じゃぁ、そのお手本とやらを君が書いてくれ

評価

0

>>蛇足かもしれんけど、以下のようにKeyboardFocusManagerとKeyEventDispatcherを使うサンプルもよく見かける。
>「よく見かける」?本気で言ってるんですか。
以下、SunのDeveloper Forumsなどで見かけたものの一部を順不同で貼っておく。
Global keylistener?
ttp://forum.java.sun.com/thread.jspa?threadID=788247

KeyAdapters and Focus
ttp://forum.java.sun.com/thread.jspa?forumID=57&threadID=635837

Listening to All Key Events Before Delivery to Focused Component
ttp://exampledepot.com/egs/java.awt/DispatchKey.html

JTabbedPane setFocus trouble KeyListener & MouseListener
ttp://forum.java.sun.com/thread.jspa?threadID=625027

How to Write a Key Listener
ttp://java.sun.com/docs/books/tutorial/uiswing/events/keylistener.html

catching KeyEvents from all components
ttp://forum.java.sun.com/thread.jspa?threadID=723287

FocusEvents and Event Masks
ttp://forum.java.sun.com/thread.jspa?threadID=5211905

> 単純なKeyListenerで済むことをわざわざ、
> KeyboardFocusManagerなんて使う意味がない。
単純で済めばね。1-8のButtonしか使わないなら、最初に上げた方法でいいかもしれないが、別のコンポーネント、例えば、入力欄としてTextFieldとか評価Buttonなどを追加する場合、これらすべてをsetFocusable(false)としておかないと、そちらにフォーカスが移ってしまう。
このため、Frameに追加したKeyListenerではイベントが拾えない。
各コンポーネントで一々FrameにdispatchEventしても構わないが、これは非常に手間がかかる。
Tab traversal
ttp://forum.java.sun.com/thread.jspa?forumID=57&threadID=5189347

また、setFocusable(false)すると、Buttonをクリックしたときの表示も微妙になるし、TextFieldに至ってはsetFocusable(false)してしまうと入力不可になって意味がない。

> KeyboardFocusManagerは、主にフォーカス制御に使用すべきものです。
まさにフォーカス制御に絡む問題であり、質問主は「フォーカスについて勉強しようと思う」と書かれている。よって蛇足かもしれぬがと断った上でKeyboardFocusManagerを使うサンプルを紹介した。

蛇足ついでに、その他の方法も紹介しておく。

KeyboardFocusManagerを使うのが気に入らないと言うなら、他にもToolkitにEventQueueやAWTEventListenerを追加することで同様のことを行う方法もある。
KeyEvents without beeing in a textfield
ttp://forum.java.sun.com/thread.jspa?forumID=57&threadID=573691

ただし、どちらも基本的にはswitch文かif else文を並べて使うので、面倒と言えば面倒だ。
このため、AWTではなく、SwingでいいならActionMap や InputMap を使うことが推奨されている。
以下の質問では、KeyboardFocusManagerを使う方法と、ActionMap、InputMapを使う方法が紹介されているので比較してみると分りやすいだろう。
Adding a KeyListener to a JPanel
ttp://forum.java.sun.com/thread.jspa?threadID=633379

> 本当に、本気でこんなコードを書いてる人がいるんなら、
> センスもないうえに、コードの保守性、拡張性について、想像力が無さすぎ。
だから、上に書いたようなActionMap、InputMapが導入されたと記憶しているが、AWTのサンプルなんだから仕方ない。

> 特に質問者が初心者みたいなのに、こんなコードを示すべきじゃないと思う。
センスあふれる初心者向けのコードが""から提示されることを期待している。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。