1. はじめに
今回は、JavaFXで学んだことをアウトプット、備忘録としてここに記します。
使用環境
windows10
Java - 17.0.2
Eclipse - 2021-12 (4.22.0)
JavaFX - 17.0.3(2022年4月)
Scene Builder - JavaFX SceneBuilder1.1
2. JavaFXの導入
◆JavaFXの安定バージョンをダウンロードします。
2022/5/23時点では、17.0.3がサポート対象でした。
ダウンロードしたものを展開する場所は分かりやすい作業フォルダに置く
◆Windowsのシステム環境変数とEclipseにパスを通しましょう
Windowsシステム環境変数に追加
変数名は適当に、JavaFX_pathドライブ名:\保存先\javafx-sdk-18.0.1\lib
のように/libファイルの中身を見れるようにシステムに教えてあげましょう。
システムにパスを通さないとEclipseからパスを通せません。
※EcelipseはJavaFXプロジェクトを作ってから外部jarファイルとして追加します。
3. Scene Builderをインストール
Oracle - Scene Builder ダウンロードページ
上記のページから一番下のあたりにある
[JavaFX SceneBuilder1.1ダウンロード]
から各自OSのバージョンをダウンロードしてください
4. JavaFX Projectを作成
4.1. JavaFXを作る前に
JavaFXは画面を見た目を構築する .fxmlファイル
とその画面をコントロールする .javaのコントローラーファイル
の2つのセットで構築されています。
Scene Builderはその.fxmlをGUI表示して直感的に画面構成を変えることでScene Builderが.fxmlを書き換えてくれるツールです。
以下のようにEclipseからMain.javaを実行すると、新しいウインドウでアプリが起動する状態を目指します。
では、実際に作っていきます。
4.2. Eclipseにて、JavaFXプロジェクトを作る
Eclipseのプロジェクト作成から、JavaFX/JavaFXプロジェクトを選択します。
-
Eclipse画面上部のリボンにある
ウインドウ > 設定 > Java > ビルド・パス > ユーザー・ライブラリー > 新規 -
新規作成ボタンで JavaFX と入力し、フォルダを作成
-
外部jarファイルの追加
-
システム環境変数で設定したパスと同じ場所 /lib の中にある すべての.jarファイルを選択して、適用ボタンを押す。
以下のような状態になっていればok
-
ロジェクトの作成 > その他 > JavaFX > JavaFXプロジェクト
-
プロジェクト名を決めて、JREがJavaSE-17になっていれば、次へ
-
ライブラリータブ > クラスパスを選択した状態で > 外部jarファイルの追加(先ほどEclipseでパスを通した手順と同じことをします)、次へ
-
宣言的UI > 言語を[FXML]にする
ルートタイプ: 変更しない
ファイル名: Main
コントローラー名: MainController
完了ボタンでプロジェクトが作成される
参考ページ
【超初心者向け】JavaFX超入門
5. 画面を作ろう
src/application/内の○○Controller.javaと○○.fxmlをパッケージ化します。
src/application/main/MainScreen.fxml
src/application/main/MainController.java
Screen.fxmlはそのままの階層においてください
Main.javaは実行ファイルなのでそのままの階層においてください
5.1. Main.java
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
//FXMLからのシーングラフの読み込み
FXMLLoader loader = new FXMLLoader(getClass().getResource("main/MainScreen.fxml"));
Parent root = loader.load();
//シーングラフのルートノードを設定したシーンの作成
Scene scene = new Scene(root, 1000, 600);
//ステージへのシーンの設定
primaryStage.setScene(scene);
primaryStage.setTitle("[ウィンドウの名称を変更できます]");
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
5.2. Scene Builderでログイン画面の見た目を作る
- MainScreen.fxmlを右クリックしてScene Builderで開く
このような画面を作ります。
- Containers / vBoxを黒い画面上に置くと、真っ白な画面ができると思います、
赤①
Containers / Text
- Properties: 好きな文章をいれてください
- Code: fx:idはつけなくてもいいです
橙②
Containers / TextField
- Properties: Prompt Text - にuser_nameを入れると、Text Fieldの背後にうっすらと文字が表示されます。
- Code - [user_name] というidを付けます。
黄③
Containers / Button
- Properties: Text - [System exit]を入力
- Code: fx:id - に[closeButton]
- Code: On Action - に[OnClickedCloseButton]を入力
Containers / Button
- Properties - Text [login]を入力
- Code: fx:id - [nextButton]
- Code: On Action - [OnClickedNextButton]
これで更新を書けると注意マークが上部にでます
⇒ Controllerでこれらの動作について定義すればこの警告は消えます。
5.3. MainScreen.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.main.MainController">
<children>
<Button fx:id="nextButton" layoutX="411.0" layoutY="323.0" mnemonicParsing="false" onAction="#OnclickedNextButton" prefHeight="33.0" prefWidth="91.0" text="login" />
<Button fx:id="closeButton" layoutX="109.0" layoutY="323.0" mnemonicParsing="false" onAction="#OnclickedCloseButton" prefHeight="33.0" prefWidth="91.0" text="system exit" />
<Label alignment="CENTER" layoutX="200.0" layoutY="75.0" prefHeight="33.0" prefWidth="200.0" text="Question-Maker">
<font>
<Font size="20.0" />
</font>
</Label>
<TextField fx:id="user_name" layoutX="226.0" layoutY="168.0" promptText="user name" />
<TextField fx:id="password" layoutX="226.0" layoutY="213.0" promptText="password" />
<Text layoutX="142.0" layoutY="185.0" strokeType="OUTSIDE" strokeWidth="0.0" text="User Name: " />
<Text layoutX="146.0" layoutY="230.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Password: " />
<TextField fx:id="again_pass" layoutX="226.0" layoutY="258.0" promptText="again_pass" />
<Text layoutX="136.0" layoutY="275.0" strokeType="OUTSIDE" strokeWidth="0.0" text="again_pass: " />
</children>
</Pane>
5.4. コントローラーに処理を書いていく
MainController.javaを編集します。
その前に、Scene Builderにて上部のタブから、
表示 > サンプル・コントローラー・スケルトンの表示を押すと
MainController.javaに書くべき各コンテナの定義情報が記載されますので丸ごとコピーしてこの状態から書き始めます。
Controllerで、fxmlの各要素を参照しているわけです.
以下のようにTextFieldにある文字列を受け取って、データベースの情報と照合する処理を
書けば、ログイン機能のような画面遷移ができます。
5.5. MainController.java
package application.main;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.ResourceBundle;
import application.Screen;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
public class MainController {
@FXML
private ResourceBundle resources;
@FXML
private URL location;
@FXML
private Button nextButton;
@FXML
private Button closeButton;
@FXML
private TextField user_name;
@FXML
private TextField password;
@FXML
private TextField again_pass;
@FXML
void OnclickedCloseButton(ActionEvent event) {
closeButton.getScene().getWindow().hide(); //システム終了
}
@FXML
void OnclickedNextButton(ActionEvent event) throws SQLException, ClassNotFoundException {
// データベースから情報を持ってくる処理
if (1回目のパスワード入力と2回目のパスワード入力の文字列が同じか) {
if (データベースの情報と合っているか) {
// 画面遷移処理
nextButton.getScene().getWindow().hide();
Screen screen = new Screen();
// 引数 (次の画面の.fxml, "画面名");
screen.transitionScreen("home/SubScreen.fxml", "HOME");
}
} else {
System.out.println("user login missed");
}
}
@FXML
void initialize() {
assert nextButton != null : "fx:id=\"nextButton\" was not injected: check your FXML file 'screen.fxml'.";
assert closeButton != null : "fx:id=\"closeButton\" was not injected: check your FXML file 'screen.fxml'.";
}
}
5.5. 遷移先の画面
遷移先の画面も作っておきます。
5.6. SubScreen.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-border-radius: 20;" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.home.SubController">
<children>
<Button fx:id="backButton" layoutX="458.0" layoutY="21.0" mnemonicParsing="false" onAction="#OnclickedBackButton" prefHeight="33.0" prefWidth="110.0" text="Back to Login">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding></Button>
<Label alignment="CENTER" layoutX="39.0" layoutY="6.0" prefHeight="25.0" prefWidth="200.0" text="Question-Maker">
<font>
<Font size="20.0" />
</font>
</Label>
<TextArea layoutX="64.0" layoutY="81.0" prefHeight="279.0" prefWidth="503.0" text="*** このアプリについて *** 主に、問題の作成、編集、削除、コピー を行うアプリです。 ぜひ、あなたの勉強に活用してみてください。 This app is Beta ver 1.0 © Powered by hoge.net ">
<font>
<Font size="18.0" />
</font>
</TextArea>
<Label fx:id="displayName" layoutX="357.0" layoutY="31.0" text="ようこそ、○○さん" />
<Button fx:id="myList" layoutX="64.0" layoutY="46.0" mnemonicParsing="false" onAction="#onClickedMyList" text="myList" />
<Button fx:id="latestShow" layoutX="128.0" layoutY="46.0" mnemonicParsing="false" onAction="#onClickedLatestShow" text="latestShow" />
<Button fx:id="doTest" layoutX="213.0" layoutY="46.0" mnemonicParsing="false" onAction="#OnClickedDoTest" text="DoTest" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</Pane>
5.7. SubController.java
package application.home;
import application.Screen;
import application.main.MainController;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
public class SubController {
@FXML
private Button backButton;
@FXML
private Label displayName;
@FXML
private Button doTest;
@FXML
private Button latestShow;
@FXML
private Button myList;
// hold user
String current_user_name;
@FXML
void OnclickedBackButton(ActionEvent event) {
backButton.getScene().getWindow().hide(); //画面を閉じる
Screen screen = new Screen(); //画面を開く(メソッド呼び出し)の準備
screen.transitionScreen("main/MainScreen.fxml", "Login Form"); //画面を開く
}
public void getUserName() {
MainController mainC = new MainController();
String name = mainC.getCurrent_user_name();
current_user_name = name;
}
@FXML
void onClickedLatestShow(ActionEvent event) {
latestShow.getScene().getWindow().hide(); //画面を閉じる
Screen screen = new Screen(); //画面を開く(メソッド呼び出し)の準備
screen.transitionScreen("aaa/aaa.fxml", "toAAA"); //画面を開く
}
@FXML
void OnClickedDoTest(ActionEvent event) {
doTest.getScene().getWindow().hide(); //画面を閉じる
Screen screen = new Screen(); //画面を開く(メソッド呼び出し)の準備
screen.transitionScreen("bbb/bbb.fxml", "toBBB"); //画面を開く
}
@FXML
void onClickedMyList(ActionEvent event) {
myList.getScene().getWindow().hide(); //画面を閉じる
Screen screen = new Screen(); //画面を開く(メソッド呼び出し)の準備
screen.transitionScreen("ccc/ccc.fxml", "toCCC"); //画面を開く
}
@FXML
void initialize() {
assert backButton != null : "fx:id=\"backButton\" was not injected: check your FXML file 'subScreen.fxml'.";
assert doTest != null : "fx:id=\"doTest\" was not injected: check your FXML file 'subScreen.fxml'.";
assert myList != null : "fx:id=\"myList\" was not injected: check your FXML file 'subScreen.fxml'.";
assert latestShow != null : "fx:id=\"latestShow\" was not injected: check your FXML file 'subScreen.fxml'.";
assert doTest != null : "fx:id=\"doTest\" was not injected: check your FXML file 'subScreen.fxml'.";
}
}
5.8. Screen.java
自分で作るファイルです
package application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Screen {
public void transitionScreen(String fxmlName, String fxmlTitle) {
try {
//FXMLからのシーングラフの読み込み
FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlName));
Parent root = loader.load();
//シーングラフのルートノードを設定したシーンの作成
Scene scene = new Scene(root, 1000, 600);
//ステージへのシーンの設定
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle(fxmlTitle);
stage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.9. Java Application として実行
VM引数に
--module-path "(ダウンロードしたJavaFXのlibフォルダへのフルパス)" --add-modules javafx.controls,javafx.fxml
を追加して実行してください
MainController.javaのOnClickedNextButtonの処理を書いて、
画面遷移できたと思います。
.fxmlを作る > Scene Builderで画面を作って、コンテナにidやActionをつける > Controllerで制御メソッドやフィールドを追加して処理を書く
のサイクルでどんどん画面ができていくと思います。
6. おわり
以上で記事を終了しますが、初学者ゆえとりあえず動く状態でこの記事を書いてますので
誤った情報や重複した内容がありましたら申し訳ありません。
以降のTableViewなど機能を追加するにあたりよさげな資料をここに挙げます。
RandomCode - TableView-TableColumn
thenewboston - JavaFX Java GUI Tutorial - 12 - ChoiceBox (Drop Down Menu)