質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

1回答

6379閲覧

JavaFXで複数のキーイベントを同時に受け取るにはどうしたらいいでしょうか?

nuiri1343

総合スコア54

JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2016/06/16 07:43

###前提・実現したいこと
javafxで、キーイベントを同時に複数受け取りたい。

###該当のソースコード

java

1AnchorPane root = new AnchorPane(); 2root.setOnKeyPressed(event -> moveImage(event));

java

1public void moveImage(KeyEvent event){ 2 if(event.getCode()==KeyCode.UP){} 3 if(event.getCode()==KeyCode.DOWN){} 4 if(event.getCode()==KeyCode.RIGHT){} 5 if(event.getCode()==KeyCode.LEFT){} 6}

###試したこと+やりたいこと
上記のソースコードのようにして、キーイベントを受け取り、
矢印キーの上なら画像を少し上に動かし、下なら下に動かし、右なら右に、左なら左に
という風にはできましたが、
これにプラスして、右と上を同時に押したら斜め右上に動かし、左と下なら斜め左下に・・・
という風に、8方向に動かしたいです。
さらに加えて、もしSHIFTが同時に押されていたら動かす量を増やすといったようにしたいのですが、
上記のソースコードだとKeyEventを一つしか受け取ってくれないのです。
どうしたらいいでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

おそらくキーを押している間移動したいものを作りたいのでしょうが、いまの構造では無理があります。

とりあえずヒント的な回答を書いておきます。

  • いまのsetOnKeyPressedだけでは「押しっぱなし」を検知できません。setOnKeyReleasedも使う必要があります。
  • boolean型の変数up,down,left,right,shiftを用意し、setOnKeyPressedで各キーに対応したフラグをtrueにし、setOnKeyReleasedでfalseにします
  • 別スレッドで移動計算を行います。
  • Platform.runLaterを使い、コントロールの座標を計算結果に合わせて移動させます

#キー管理クラスのサンプル
なにもテストしてませんので動作は保証しかねますが、やろうとすることはこういうことだと思います。

Java

1public class KeyManager { 2 private Map<KeyCode, boolean> map = new HashMap<>(); 3 public void handleEvent(KeyEvent e) { 4 switch(e.getEventType()) { 5 case KeyEvent.KEY_PRESSED: 6 map.put(e.getCode(), false); 7 break; 8 case KeyEvent.KEY_RELEASED: 9 map.put(e.getCode(), true); 10 break; 11 } 12 } 13 public boolean isPressed(KeyCode code) { 14 return map.containsKey(code)?map.get(code):false; 15 } 16}

これをsetOnKeyPressed、setOnKeyReleasedそれぞれでKeyManager#handleEventを呼んでやり、Timeline内でisPressed(KeyCode.UP) & isPressed(KeyCode.LEFT)としてやれば「左上」を押していると認識できます。ただし、よくある問題としてフォーカスが外れたときに押しっぱなしになったりするので、そのへんの対処は自分で考えてみてください。

Java

1public static KeyManager keyManager = new KeyManager; 2 3// 中略 4root.setOnKeyPressed(event -> keyManager.handleEvent(event)); 5root.setOnKeyReleased(event -> keyManager.handleEvent(event)); 6 7// Timelineの処理の中 8if(keyManager.isPressed(KeyCode.UP)) { 9 //上を押されている 10} 11if(keyManager.isPressed(KeyCode.LEFT)) { 12 //左を押されている 13}

投稿2016/06/16 08:01

編集2016/06/17 02:11
masaya_ohashi

総合スコア9206

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nuiri1343

2016/06/16 08:52

申し訳ないです。現在は setOnKeyReleasedも使い、boolean型の変数up,down,left,right,shiftを用意し、setOnKeyPressedで各キーに対応したフラグをtrueにし、setOnKeyReleasedでfalseにするというやり方で実装しているのですが、 ちょっと見た目がごちゃごちゃしているので、 こういうことをパパッとできるメソッドとかないかなーと思いまして。。。 ないようなのですね>< そして質問なのですが •別スレッドで移動計算を行います。 •Platform.runLaterを使い、コントロールの座標を計算結果に合わせて移動させます これの必要はあるのでしょうか? 現在、runLaterを使わずに、スレッドも新しいのを作らずに実装しているのですが、 スレッドというのの理解ができていないのでよくわからないのですが 今実装しているのはTimelineで0.05秒毎に画面を更新する感じで CycleCountをTimeline.INDEFINITEにしている感じです。 これも別スレッドで移動計算を行っているということになるのでしょうか? また、runLaterはこの場合いらないのでしょうか?
masaya_ohashi

2016/06/16 09:08

Timelineを使うやり方を知っているならそれが一番JavaFXのアニメーションにふさわしいやり方かと思います。正確には別スレッドではないですが、それで問題無いでしょう。また、TimelineのhandleメソッドはControlへアクセスしても問題ないタイミングのはずなので、runLaterも不要だと思います。 参考までに、キー管理でよくあるパターンのコードを追記しておきました。
nuiri1343

2016/06/16 15:12

public class KeyManager { private Map<KeyCode, boolean> map = new HashMap<>(); public void handleEvent(KeyEvent e) { switch(e.getEventType()) { case KeyEvent.KEY_PRESSED: map.put(e.getCode(), false); break; case KeyEvent.KEY_RELEASED: map.put(e.getCode(), true); break; } } public boolean isPressed(KeyCode code) { return map.containsKey(code)?map.get(code):false; } } このコードを詳しく説明していただけないでしょうか? 特に、最初のMap map = new HashMap(); のところですが、 <>で囲われている部分は何を表すのでしょうか? また、Mapというのは何のクラスなのでしょうか 全然よくわからないです。 public void handleEventというのも何かわからないです。 色々説明していただけるとすごく助かります。
masaya_ohashi

2016/06/16 23:29

説明する前にあなたのプログラミングレベルを知りたいです。 ・自分でクラスファイルを新しく作れますか? ・Javaのコレクションという言葉に聞き覚えはありますか? ・Javaのジェネリクスという言葉に聞き覚えはありますか?
nuiri1343

2016/06/17 01:48

自分でクラスファイルは作れますが、 他二つはわかりません。
masaya_ohashi

2016/06/17 02:06

まずKeyManagerですが、私の自作クラスです。 public void handleEventですが、私が適当につけた名前です。handleには「制御」といった意味合いがあるので、イベントを受け取って制御する、というメソッドになります。 KeyManagerが何をしているかというと、受け取ったイベントが「押された」「離された」際に、各KeyCodeがtrueなのかfalseなのかをmapに格納しています。 Javaのコレクションとは、データの集まりを管理するユーティリティ郡で、Mapはその中で連想配列とか辞書型とか言われるものの一番基底となるインタフェースです。HashMapは連想配列のキーを「ハッシュ値」で管理するMapの実装クラスです。 Javaのジェネリクスとは、「とあるクラスの中で扱いたい値を、後から型を決める」ことができる実装のやり方を指します。ジェネリクスの型の指定方法が<>で囲まれた部分になります。mapという変数は、KeyCodeをキーに、boolean型の値を持つ連想配列ということになります。 本来配列のインデックスは数字でなければならないのですが、連想配列は以下のようなイメージで扱うことができる配列です。 map[KeyCode.UP] = true; map[KeyCode.DOWN] = false; ※イメージであり、実際こんなコードは書けません。 この「キーとなる型」、「代入することができる値の型」を、Map<KeyCode,boolean>で指定しています。Map<String,boolean>にすればmap["AAA"] = trueと扱うことができるのです。実際は代入の際はput、参照の際はgetというメソッドになります。 HashMap側の<>には何も書いていませんが、これはダイヤモンド演算子というもので、左辺の型を見て、勝手に<KeyCode,boolean>であると型推論してくれる演算子です。 より勉強したいのであれば、私の説明に出てきた単語をご自分で検索すればより深い情報が出てくると思います。
nuiri1343

2016/06/25 04:13

すばらしいです。 前々から<>というのが何者なのか分からなくて助かりました。 Javaのコレクションとは、データの集まりを管理するユーティリティ郡で、Mapはその中で連想配列とか辞書型とか言われるものの一番基底となるインタフェースです。HashMapは連想配列のキーを「ハッシュ値」で管理するMapの実装クラスです。 ここを、詳しく教えていただけませんでしょうか 他の部分は調べて色々勉強できたのですが この部分だけはぴったり来る解答を得られませんでした。 もしよろしければ詳しく説明していただけないでしょうか
masaya_ohashi

2016/06/25 06:23

コレクションには代表的な構造に「Array」「Map」などがあります。 Arrayは普通の配列と一緒で0番目から始まる、「要素に順番のある」コレクションです。 Mapは連想配列と言われるもので、map[りんご]=赤、map[バナナ]=黃、のように、「添字に数字ではないもの」を使うことのできる配列です。 そして、Array、Mapともにクラスではなくインタフェースで、実体は持ちません。あくまで「そういった機能」を表すものです。 インタフェースはわかりますか?インタフェースは言ってみれば「規格」のようなもので、「規格」に沿ったものであれば同じもののように扱える、というものです。例えばUSBのマウスとキーボードがあると思いますが、差込口は同じ形ですよね?あれはお互い規格に沿った作りをしているから同じ差込口に刺すことができます。それと同じように、Mapというインタフェースの規格に沿うものであれば、中身がどうなっているかは気にする必要なく扱うことができるわけです。 Mapはput(連想配列への代入)、get(連想配列からの参照)のメソッドを持ちます。HashMapは連想配列のキーとしてObject#hashCode()を使って管理する実装になっています。 なので、キーに文字列を使うときによく使います。KeyCodeもhashCodeがちゃんとついているのでHashMapのキーとして扱うことができるわけです。
nuiri1343

2016/06/25 07:49

map.containsKey これは自作メソッドではないのですか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問