GitHubリポジトリ
JavaFXとは
JavaのGUI開発フレームワークの1つで、AWT
・Swing
に比べ比較的新しく、.fxml
ファイルでGUIコンポーネントの配置を記述できるという特徴がある。
環境構築や大まかな基本知識は【超初心者向け】JavaFX超入門を参照。
GUIアプリケーションの実行スレッド
JavaFX 1.2 非同期処理の概要
JavaFXにおけるスレッドの扱い
GUIフレームワークは基本的に、GUIコンポーネントの描画スレッドはシングルスレッドであり、JavaFXも単一のJavaFX Application Thread(JavaFXアプリケーションスレッド)
で処理される。
そのため、GUIコンポーネントの描画処理に時間がかかる場合は、描画に直接関係しない演算処理は非同期処理
で実装するのが望ましい。
JavaFXにおける主なスレッドは以下の通り。
スレッド | スレッド名 | 概要 |
---|---|---|
メインスレッド | main |
main 関数を実行するスレッド |
JavaFXランチャースレッド | JavaFX-Launcher |
init 関数を実行するスレッド |
JavaFXアプリケーションスレッド | JavaFX Application Thread | イベント処理 / GUIコンポーネントの描画を行うスレッド |
バックグラウンドスレッド | Task / Service / ScheduledService |
Thread::sleep 関数 / 重い処理を行うスレッド |
JavaFXのバックグラウンドスレッドAPI
クラス | パッケージ | |
---|---|---|
Task | javafx.concurrent | 再利用できないWorkerスレッド |
Service | javafx.concurrent | 再利用可能なWorkerスレッド |
ScheduledService | javafx.concurrent | 処理完了後に自動で再起動するService |
アプリケーションを構成するApplication, Stage, Scene, Pane
JavaFX
では基本的に、.fxml
ファイルで定義したコンポーネントをFXMLLoaderを通じてSceneに紐づけて、Javaプログラムから制御する。
クラス | パッケージ | 概要 |
---|---|---|
Application | javafx.application | アプリケーション |
Stage | javafx.stage | トップレベルコンテナ(ウィンドウ) |
Scene | javafx.scene | 単一のPane を持つコンテナ(.fxml ファイルのコンポーネント化) |
Pane | javafx.scene.layout | 各GUIコンポーネントのレイアウトを構成するコンテナ |
各ファイルのディレクトリ構成は以下の通りとする。
- src/
- main/java/application/
- SampleApp.java(アプリケーションのMainクラス)
- SampleController.java(.fxmlで定義したコンポーネントを制御するクラス)
- window.fxml(コンポーネントを定義するファイル)
- main/java/application/
public class SampleApp extends Application {
public static void main(String[] args) {
// アプリケーションの起動
// -> start(Stage)関数が呼び出される
launch();
}
// アプリケーション起動時に呼び出される処理
@Overrride
public void start(Stage stage) {
try {
// .fxmlファイルの読み込み
URL url = SampleApp.class.getResource("window.fxml");
// FXMLLoaderを通じたSceneへの紐づけ
FXMLLoader loader = new FXMLLoader(url);
Scene scene = new Scene(loader.load());
// Stage(ウィンドウ)へのSceneの紐付け
stage.setScene(scene);
}
catch (IOException e) {
e.printStackTrace();
}
// ウィンドウバーに表示するタイトル
stage.setTitle("Sample Window");
// ウィンドウの表示
stage.show();
}
}
もちろん、.fxml
ファイルを用いることなくGUIコンポーネントを表示することもできる。
以下のサンプルコードは、背景が透明なウィンドウを表示するコードである。
// Stage(ウィンドウ)の種類を指定
Stage stage = new Stage(StageStyle.TRANSPARENT);
// GUIコンポーネント群のRootNodeであるPaneとスタイルの指定
StackPane stackPane = new StackPane();
// 角を丸くし、背景色を透明にする
// -> transparentはfxmlで標準定義された「透明」な色
stackPane.setStyle(
"-fx-background-radius: 10; -fx-background-color: transparent"
);
// Scene(コンポーネントをJavaプログラムで制御できるようにするクラス)にPaneをセット
// -> WindowサイズはSceneのサイズに依存するため、ここでウィンドウの幅と高さを指定
Scene scene = new Scene(stackPane, 400, 200);
// Sceneの背景色を設定しないようにする
scene.setFill(null);
// StageにSceneをセット
stage.setScene(scene);
// Stageを常に最前面に表示するようにする
stage.setAlwaysOnTop(true);
// Stageのタイトル
stage.setTitle("Transparent Window");
// Stageの表示
stage.show();
// Paneに入れるコンポーネント
Button button = new Button;
// Paneへのコンポーネントの追加
stackPane.getChildren().add(button);
Paneの種類
.fxmlファイルのidとfx:id
属性 | 概要 |
---|---|
id |
CSSで用いるID |
fx:id |
JavaFXで用いるID |
UI部品
をコードで操作する場合は、UI部品を特定する際に.fxml
ファイルのfx:id
属性を用いる。
Scene Builderでfx:id
属性を定義する場合は、
ドキュメント > 階層の表示 > fx:id
から階層グループで入力するか、
インスペクタ > Code > fx:id
に入力する。
<!--> window.fxml <-->
<ChoiceBox fx:id="sampleChoiceBox">...</ChoiceBox>
イベント処理の記述
JavaFX 8 Event Handling Examples
UI部品
をイベントリスナとして設定しイベント処理を実行する場合は、.fxml
ファイルでonAction
属性にコールバックメソッドを記述する。
また、コントローラでコールバック処理を記述する際は@FXML
アノテーションを付与する。
なお、ComboBox
やChoiceBox
はScene BuilderでonAction
属性を設定できないため、.fxml
ファイルに直接記述する。
<!--> window.fxml <-->
<CheckBox fx:id="sampleCheckButton" onAction="#onCheckBoxClick">
...
</CheckBox>
// SampleController.java
public class SampleController implements Initializable {
@FXML private CheckBox sampleCheckButton;
@FXML protected void onCheckBoxClick(ActionEvent event) {
switch (((CheckBox)event.getSource()).getId()) {
case "sampleCheckButton":
// イベント処理をここに記述
break;
default:
}
}
}
また、DatePicker
・Slider
・Spinner
などonAction
属性がないものについては、
Applicationのstart(Stage:)
や、Initializable
インタフェースを実装したControllerのinitialize(URL:ResourceBundle:)
でイベントリスナとしてセットする必要がある。
ただし、Slider
のonAction
はドラッグと連動して実行されるため、
ドラッグ後にイベント処理を実行する場合はonMouseReleased
属性を利用する。
// SampleController.java
public class SampleController implements Initializable {
@FXML private DatePicker datePicker;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
this.datePicker.valueProperty().addListener((observable, oldValue, newValue) -> {
// イベント処理
});
}
}
/*
Applicationでイベントリスナ定義をする場合は下記参照
*/
// SampleApp.java
public class SampleApp extends Application {
@Override
public void start(Stage stage) throws Exception {
DatePicker datePicker = new DatePicker();
datePicker.valueProperty().addListener((observable, oldValue, newValue) -> {
// イベント処理
});
}
}
Spinner
Spinner
の入力値・型を指定する場合は、valueFactory
タグの内部にSpinnerValueFactory
タグを記述する。
<!--> settings-view.fxml <-->
<?import javafx.util.* ?>
<?import javafx.scene.*?>
<?import javafx.scene.control.* ?>
<?import javafx.scene.layout.* ?>
<Spinner fx:id="spinner" editable="true">
<valueFactory>
<SpinnerValueFactory.DoubleSpinnerValueFactory min="0" max="1" initialValue="0.5" amountToStepBy="0.1"/>
</valueFactory>
</Spinner>
Windowsアプリケーションのプロファイルデータの保存(永続化)方法
カテゴリ | 拡張子 | 概要 |
---|---|---|
テキスト | .ini |
Windows初期から利用されるKey-Value形式 |
^ | .xml |
多くの言語の標準ライブラリでサポートされるKey-Value形式 |
^ | .json |
多くの言語の標準ライブラリでサポートされるKey-Value形式 |
^ | .yaml |
コメントが記述できるKey-Value形式 |
バイナリ | .bin |
ユーザによる変更を防止する2進数形式 |
データベース | レジストリ | OSのシステム情報を格納するKey-Value形式 |
^ | RDB | 2次元の表でデータを管理するDB |
^ | OODB | オブジェクト指向でデータを管理するDB |
データベースの利点
データの保存先としてデータベースを採用するメリットは、主に以下の3つ
- アルゴリズムを駆使した高速処理が可能
- 複数のプログラムからの同時アクセスが可能
- 処理の中断・エラー時のロールバックが可能
組み込みDBMSの選定
方式 | 概要 | DB |
---|---|---|
インプロセス(ライブラリ)型 | データベースをアプリケーションに組み込む方式 |
SQLite (RDB), H2 Database (RDB), Redis (NoSQL) |
クライアント・サーバ型 | DBプロセスがアプリケーションプロセスから独立する方式 |
SQL Server (RDB), PostgreSQL (RDB), MongoDB (NoSQL) |
RDBMS vs. NoSQL
分類 | メリット | デメリット |
---|---|---|
RDBMS | ①データ処理の一貫性が担保 ②複雑なデータ処理が可能 |
スケールアウトが困難 |
NoSQL | ①データ処理が高速 ②拡張性に優れる |
データの一貫性が担保されない |
Redis(Lettuce)への接続
プログラムをRedisクライアントとして動作させるためRedisをPCにインストールし、
Redisを利用するためのライブラリの依存関係をPOMファイルに記述する。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<dependencies>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.5.RELEASE</version>
</dependency>
</dependencies>
</project>
// Redisクライアントの作成
// 事前にRedisのインストールが必要(https://github.com/MicrosoftArchive/redis/releases)
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
try (
// Redis Standaloneサーバへの接続
// → <String, String>型でデータを管理
StatefulRedisConnection<String, String> connection = redisClient.connect();
) {
// 同期実行のコマンドAPIの取得
RedisCommands<String, String> syncCommands = connection.sync();
// 保存されたデータが存在しない場合は初期値をセット
if (syncCommands.get("key") == null) {
syncCommands.set("key", "value");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Redisクライアントの終了
redisClient.shutdown();
}
データベースを利用する場合のJDBCドライバ
DBMS | ドライバクラスのFQCN | JDBC URL |
---|---|---|
SQL Server | com.microsoft.sqlserver.jdbc.SQLServerDriver | jdbc:sqlserver: |
MySQL | com.mysql.cj.jdbc.Driver | jdbc:mysql: |
PostgreSQL | org.postgresql.Driver | jdbc:postgresql: |
SQLite | org.sqlite.JDBC | jdbc:sqlite: |
H2 Database | org.h2.Driver | jdbc:h2: |