とにかく書く

日々の雑感や知り得たことを、とにかく書いています

Stage のサイズをキーイベントで変える

画像ビューアーで、キーを押すと次の画像を表示させ、ウィンドウのサイズを画像に合わせて変えたいと思った。
Scene の setOnKeyPressed メソッドでイベントハンドラを登録した場合、Stage にアクセスできない…と悩んだので解決法をメモする。
2つ事例を挙げる。ひとまず後者でなんとかできているため、後者で進める。


[2021年1月24日 追記]
以下では setOnKeyPressed イベントによって処理をしているが、ショートカットキーとして判定する場合は setOnKeyTyped を使う方が良い。後日、記事にしました。
キーの入力を検知するには onKeyTyped を使う - とにかく書く

start メソッドの中で Stage に無名関数をイベントハンドラとして登録

以下のソースコードのようにした。
スペースキーを押すごとにウィンドウサイズが 100 px ずつ大きくなる。
ただ、機能が増えてくると start の中が長大になることが容易に予想される。
[参考] JavaFX Stage

package application;
	
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;

public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			BorderPane root = new BorderPane();
			Scene scene = new Scene(root,400,400);
			primaryStage.setScene(scene);
			// stage にキー入力のイベントハンドラを登録する. 無名関数を使っている。
			primaryStage.addEventHandler(KeyEvent.KEY_PRESSED,  (event) -> {
			    switch(event.getCode()) {
			        case SPACE :
			        	primaryStage.setWidth( primaryStage.getWidth() + 100);
			        	break;
			        default:
			        	System.out.println("Unrecognized key");
			        	break;
			    }
			});

			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}

Stage インスタンスをクラス変数として保持してイベントハンドラからアクセスする

比較的容易。
クラス変数として保持してもメモリ使用量や動作速度に影響しないかが懸念点。Java の動きがよくわかっていない。
インスタンスのコピーを作成してクラス変数として保持しているのか、単にポインタをクラス変数として保持しているのか、区別がつかない。

package application;
	
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;

public class Main extends Application {
	Stage stage;
	@Override
	public void start(Stage primaryStage) {
		try {
			stage = primaryStage;
			BorderPane root = new BorderPane();
			Scene scene = new Scene(root,400,400);
			primaryStage.setScene(scene);
			// scene の setOnKeyPressed でイベントハンドラを登録する. Stage はクラス変数で保持。
			scene.setOnKeyPressed(this::keyPressed);

			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	//キー押し下げを検出
	private void keyPressed(KeyEvent e) {
 		switch(e.getCode()) {
 		case SPACE:
        		stage.setWidth( stage.getWidth() + 100);
			break;
		default:
        	System.out.println("Unrecognized key");
			break;
		}
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}