あなたの目的は:
既存のSWTアプリのUIをHTMLで置き換えつつ、完全ローカルでJavaFXを使って表示する構成
ということなので、以下のような構成の 最小サンプルコード を用意しました:
✅ サンプルの構成概要
- UI →
HTML + JavaScript
- 表示 →
JavaFX WebView
- ロジック → Javaで受け取り(
JavaBridge
) - ネットワークなし・完全ローカル
📁 プロジェクト構成(例)
your-project/
├─ src/
│ └─ App.java
├─ resources/
│ └─ ui.html
🖥️ App.java
(JavaFX + HTML連携)
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class App extends Application {
@Override
public void start(Stage stage) {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
// HTML読み込み(ローカルファイル)
String url = getClass().getResource("/ui.html").toExternalForm();
engine.load(url);
// JSからJavaを呼び出すためのブリッジ設定
engine.getLoadWorker().stateProperty().addListener((obs, old, newState) -> {
if (newState == javafx.concurrent.Worker.State.SUCCEEDED) {
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("javaBridge", new JavaBridge());
}
});
stage.setTitle("JavaFX HTML UI Sample");
stage.setScene(new Scene(webView, 400, 300));
stage.show();
}
// JavaScriptから呼び出されるクラス
public class JavaBridge {
public void onButtonClicked(String message) {
System.out.println("JavaScriptから呼ばれた: " + message);
// → ここにSWTアプリの既存処理とつなげるロジックを追加可
}
}
public static void main(String[] args) {
launch(args);
}
}
🌐 ui.html
(resourcesフォルダに置く)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML UI</title>
</head>
<body>
<h2>JavaFX HTML UI</h2>
<button onclick="notifyJava()">Javaに伝える</button>
<script>
function notifyJava() {
if (window.javaBridge) {
window.javaBridge.onButtonClicked("ボタンが押されたよ!");
} else {
console.log("JavaBridgeが見つかりません");
}
}
</script>
</body>
</html>
✅ 実行結果
-
JavaFX
のウィンドウが立ち上がる - HTMLが表示され、ボタンを押すと Java の
onButtonClicked
が呼ばれる -
System.out.println(...)
で受信確認できる
🧠 ポイント解説
機能 | 実装場所 | 解説 |
---|---|---|
HTML表示 | WebView |
ローカルのHTMLファイルを読み込み |
JSからJavaを呼ぶ | JSObject.setMember() |
JavaのメソッドをJSで使えるようにする |
完全ローカル動作 | file:///... |
ネットワーク不要、セキュア |
SWTアプリとの連携 |
JavaBridge クラス |
SWTのAPI呼び出しを組み込めばOK |
💬 より発展的な応用も可能
-
Java → JavaScript
の呼び出し(engine.executeScript(...)
) - テキスト入力/テーブル/画面遷移など複雑なUI構成もHTML/JSで制御
- CSS/Bootstrap/Vue.jsなどの導入(軽量ならOK)
もしこのサンプルをベースに、**「既存SWTの処理を移植したい」「UIをもっと複雑にしたい」**などあれば、それに合わせて発展版も作れますよ!
どう使っていきたいか、教えてください!
さらに質問!
engine.getLoadWorker().stateProperty().addListener((obs, old, newState) -> {これはどのタイミングで呼び出されるものですか?
めちゃくちゃ鋭いところ聞いてくれました!
この部分の理解は、JavaFXで WebView
を使う上でとても重要です。
🔍 engine.getLoadWorker().stateProperty().addListener(...)
の意味
これは、
HTMLの読み込み処理(=Webページのロード)の状態が変わったら実行される処理を定義するもの
です。
🧠 もう少し具体的に言うと:
engine.getLoadWorker().stateProperty().addListener((obs, old, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
// ページの読み込みが完了したときに呼ばれる処理
}
});
というのは、
-
engine.load(url)
でHTMLの読み込み開始 - 読み込み進行中は
Worker.State.RUNNING
- 完了したら
Worker.State.SUCCEEDED
になる - そのときにだけ、
newState == SUCCEEDED
の中身が実行される!
✅ なぜこれが必要か?
HTMLがまだ完全にロードされていない状態で window.setMember("javaBridge", ...)
を実行すると、JavaScript側の window
が未定義だったり、html
にアクセスできなかったりして うまくブリッジできない。
→ なので、**「HTMLが完全に読み込まれてから」**JavaとJSを繋ぐのが大事!
💬 例えると…
HTMLの読み込みを「料理」にたとえるなら:
-
engine.load(url)
→ 料理を始める(オーブンに入れる) -
addListener(...)
→ 焼き上がったかを監視してる人 -
newState == SUCCEEDED
→ 焼き上がった瞬間! - → そのときに「できたて料理を取り出して、テーブルに出す」= JavaとJSの接続を確立
🧪 もしこれが無いとどうなるか?
// 読み込み前にブリッジを設定しようとすると…
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("javaBridge", new JavaBridge()); // ← ここでNullPointerになることも
上記のように HTML側がまだロードされていないと window
が取得できずエラーになります。
🟢 安心して使ってOK
この LoadWorker
監視は JavaFXのWebView連携での「お約束」です。
JSとのブリッジや、JavaScriptからJavaへイベントを受け取るには必須の処理になります。
✨まとめ:このリスナーは何のため?
項目 | 内容 |
---|---|
何をしている? | HTMLの読み込み完了(SUCCEEDED)を監視してる |
いつ呼ばれる? |
engine.load() の読み込みが完了した直後 |
何のために? | JavaScript と Java を正しくブリッジするため |
無くても動く? | タイミングによっては動くけど、不安定・バグの元! |
もっと知りたい機能(例えばJavaからJSの関数を呼ぶとか)があれば、続けて聞いてくれてOKです!