読者です 読者をやめる 読者になる 読者になる

kiyo_hikoのブログ

メモ+日記?

Javaでクイズ暗記ツール作成(13)

自分のPCはタッチ対応だからこの作りかけの「きよツール(仮称)」はとても使いやすいのだけど、普通のPCからマウスで操作する分には、(特に並べ替えが) ものすごくめんどくさくて不愉快だった。
キーボード操作に対応したいと願っていたけど知識がなかったので、イベントについて学んだ。


キーボード操作への対応方法がわかったので対応を始めた。
やったことや、今の画面の状態をメモ:

Actionオブジェクトの追加

いままでに作った機能画面は基本的にマウス操作に反応し、キーボード操作には反応しない。
ザックリ書くと以下のようなイメージ:
(即興で雰囲気だけ書いたので誤字とかで動かないかも)

Outer.java

public class Outer extends JPanel implements ActionListener {
    public Outer() {
        JToggleButton b = new JButton("o_o");
        b.addActionListener(this);
    }
    @override
    public void actionPerformed(ActionEvent e) {
        System.out.println("hello,world");
    }
}

これをキーボード操作に対応させるにはキーストロークとアクションをひもづける必要があって、そのためにはActionMap・InputMapといったクラスを使えばいいらしい。


基本的には、

  • inputMapにキーストロークと識別用オブジェクトXを登録し、
  • ActionMapにキーXから↑の識別用オブジェクトと起爆するActionオブジェクトを登録

するという。
この2段階の登録操作によって、画面上でキーストロークに指定されたキーをクリックすれば、Xに紐付けられたActionのActionPerformedが呼ばれ、イベントが処理できるようになる。


で、Actionを書く必要があるが、これはOuterクラスの中にInnerクラスとして書くことにした。
おおまかに方針として、

  • InnerのActionPerformedには、キーボード操作のときだけやらなきゃならない処理を書く。
    • 例えば、OuterではイベントのJToggleButtonで、マウス操作ならボタンが膨らむか凹むかするが、キーボード操作だとそれはない。なのでInnerのActionPerformedでマウスの真似してボタン状態を切り替える。
  • あとはInnerもOuterもやりたいことは一緒だから、InnerからOuterのActionPerformedを呼び出す。内側から外側のクラスのメンバーを呼ぶには、「Outer.this.メンバー名」でいいらしい。


上記をまとめて、だいたいこうなった:

Outer.java

public class Outer extends JPanel implements ActionListener {
    public Outer() {
        JToggleButton b = new JButton("o_o");
        b.addActionListener(this);
        // どのコンポーネントにフォーカスがあっても反応できるようにする
        b.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
            .put(KeyStroke.getKeyStroke("X"), "hello");
        b.getActionMap().put("hello", new Inner());
    }
    @override
    public void actionPerformed(ActionEvent e) {
        System.out.println("hello,world");
    }
    class Inner extends AbstractAction() {
        @override
        public void actionPerformed(ActionEvent e) {
            JToggleButton b = (JToggleButton) e.getSource();
            b.setSelected(!b.getSelected());
            Outer.this.actionPerformed(e);
        }
    }
}

工夫の余地はありそうだし、将来的にかえるかもしれないが今のところこんな感じのコードを今まで作ったクイズパネルに順次適用していって、キーボード操作出来る内容を増やしてく。

画面表示部品を作る

せっかくだし、Enter=OKなどなんとなく自明なもの以外は、画面に「どのキーはどの操作」というのを表示するようにする。


キーボードアイコンをExcelで作った。InkScapeとかならもっといろいろできそうだけど、正直めんどくさいからオートシェイプで十分すぎる。

f:id:kiyo_hiko:20130913030608p:plain:w240

そのあとExcelから透明化PNGが出力できないことに思い至って、クリスタで透明化PNGに加工した。


画像の通り、通常キーと、ホームポジションでデザインを分けた。
なんのことはないちっぽけな工夫だが、そういうのを考慮しておくと、あとからじわじわと効いてくる。

できたもの

ボタン近隣に対応したキーが表示される。
キーアサインを考えるのに以前とは変えて、できるだけホームポジション中心で選ぶようにした。このほうがモーパイしやすくて入力がぐっと楽になる。


とりあえずいくつか組み込んだ結果がこれ:

f:id:kiyo_hiko:20130913030925p:plain:w240

f:id:kiyo_hiko:20130913031117p:plain:w240

操作感はそこそこで、たぶんそのうち慣れる。