LoginSignup
8
5

More than 1 year has passed since last update.

JavaFXでWindowsアプリを作るまでに学んだこと

Posted at

GitHubリポジトリ

customizable-clock

JavaFXとは

JavaのGUI開発フレームワークの1つで、AWTSwingに比べ比較的新しく、.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

JavaFXとマルチスレッド

クラス パッケージ
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コンポーネントのレイアウトを構成するコンテナ

JavaFX Scene Graph

各ファイルのディレクトリ構成は以下の通りとする。

  • src/
    • main/java/application/
      • SampleApp.java(アプリケーションのMainクラス)
      • SampleController.java(.fxmlで定義したコンポーネントを制御するクラス)
      • window.fxml(コンポーネントを定義するファイル)
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の種類

JavaFX-Pane.png

.fxmlファイルのidとfx:id

属性 概要
id CSSで用いるID
fx:id JavaFXで用いるID

UI部品をコードで操作する場合は、UI部品を特定する際に.fxmlファイルのfx:id属性を用いる。
Scene Builderfx:id属性を定義する場合は、

ドキュメント > 階層の表示 > fx:id

から階層グループで入力するか、

インスペクタ > Code > fx:id

に入力する。

<!--> window.fxml <-->
<ChoiceBox fx:id="sampleChoiceBox">...</ChoiceBox>

イベント処理の記述

JavaFX 8 Event Handling Examples

UI部品をイベントリスナとして設定しイベント処理を実行する場合は、.fxmlファイルでonAction属性にコールバックメソッドを記述する。
また、コントローラでコールバック処理を記述する際は@FXMLアノテーションを付与する。

なお、ComboBoxChoiceBoxScene BuilderonAction属性を設定できないため、.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:
    }
  }
}

また、DatePickerSliderSpinnerなどonAction属性がないものについては、
Applicationstart(Stage:)や、Initializableインタフェースを実装したControllerinitialize(URL:ResourceBundle:)でイベントリスナとしてセットする必要がある。

ただし、SlideronActionはドラッグと連動して実行されるため、
ドラッグ後にイベント処理を実行する場合は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

SpinnerValueFactory

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アプリケーションのプロファイルデータの保存(永続化)方法

Javaで永続化

カテゴリ 拡張子 概要
テキスト .ini Windows初期から利用されるKey-Value形式
^ .xml 多くの言語の標準ライブラリでサポートされるKey-Value形式
^ .json 多くの言語の標準ライブラリでサポートされるKey-Value形式
^ .yaml コメントが記述できるKey-Value形式
バイナリ .bin ユーザによる変更を防止する2進数形式
データベース レジストリ OSのシステム情報を格納するKey-Value形式
^ RDB 2次元の表でデータを管理するDB
^ OODB オブジェクト指向でデータを管理するDB

データベースの利点

データの保存先としてデータベースを採用するメリットは、主に以下の3つ

  1. アルゴリズムを駆使した高速処理が可能
  2. 複数のプログラムからの同時アクセスが可能
  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 on Windows
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:
8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5