Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine〜

イントロダクション

前回は、Paneクラスを切り替えて画面の切り替え処理ができるようになりました。

これは、GUIツールで画面を作成したものです。全部プログラムで書かなくても画面作成ができることを紹介するものです。

今回は切り替えたあとに画面を表示する処理を実装します。

HTMLをロードする

単純に指定したURLのHTMLをダウンロードして表示するというものです。

HTMLのダウンロード〜表示までは「WebEngine」クラスがやってくれているので実装する側としては気にする必要がありません。

そして今まで作成していたソースに改変を大きめというほどではないですが、入れました。下のはGitでソースの差分を出したものです。

実際エラーが下の方に出ています。がそれは気にしなくても良いもののようです。→調べてみたらWebKit(ブラウザ)の履いているエラーらしい。。。

https://www.youtube.com/watch?v=YPuaUUvCdMg&feature=youtu.be

とりあえずはこんな感じでロードできました。

ソース

package jp.zenryoku.fx;

import java.util.ArrayList;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

/**
 * JavaFXでのハローワールド〜OpenCVなどの
 * 作成したアプリをテストするための、スタンドアロンアプリ。
 * 
 * @author takunoji
 * 2019/01/23
 */
public class RootFxMain2 extends Application {
    /** 画面の縦幅 */
    private static final double VIEW_HEIGHT = 500.0;
    /** 画面の横幅 */
    private static final double VIEW_WIDTH = 500.0;
    /** コントロールボタンのリスト */
    private ArrayList\<Button\> buttonList; // ポイント1
    /** startメソッドから引っ越ししてフィールド変数にします */
    private BorderPane baseLayout; // ポイント2

    /**
     * 親クラスのメソッドをオーバーライドする。
     * 画面を作成したり、シーンを作成したり、色々。。。
     * 
     * @see javafx.application.Application#start(javafx.stage.Stage)
     */
    @Override
    public void start(Stage primaryStage) throws Exception {
        // JavaBasic画面用のコントロールボタンを作成する
        this.cretateControllButtonList();
        // 画面部分とコントロールボタン部分にレイアウト(表示領域を分ける)
        baseLayout = new BorderPane();

        // Stageの設定
        primaryStage.setHeight(VIEW_HEIGHT);
        primaryStage.setWidth(VIEW_WIDTH);

        // このクラスにあるメソッドなので名前だけで呼び出せる
        baseLayout.setCenter(createJavaBasicPane());
        // このクラスのメソッドであることを明示的に示すのに「this」を使用する
        baseLayout.setBottom(this.createFooterPanel());
        // 土台になるレイアウト(ペイン)をステージに追加する
        primaryStage.setScene(new Scene(baseLayout, VIEW_WIDTH, VIEW_HEIGHT));
        primaryStage.show();
    }

    /**
     * シーンの作成部分を切り出ししました。
     * このシーンはJavaの基本を実行する時用にします。
     * 
     * @see http://zenryokuservice.com/wp/2019/01/25/java-stepupprogr…avafxで画面切り替えを作る〜/
     * @return JavaBasic用のPane
     */
    private Pane createJavaBasicPane() {
        // レイアウトたて
        VBox vBox = new VBox(5);
        // レイアウト横
        HBox hBox = new HBox(8);
        // ラベルの設定
        Label label = new Label();
        // ハローワールドを出力する
        label.setText(myFirstProgram());
        label.setFont(new Font("RobotRegular", 24));
        vBox.getChildren().add(label);

        // 1個目の数値、テキストフィールド
        TextField text1 = new TextField();
        text1.setPrefColumnCount(3);
        text1.setAlignment(Pos.BASELINE_CENTER);
        hBox.getChildren().add(text1);
        // 計算式のラベル
        Label ope = new Label("+");
        hBox.getChildren().add(ope);

        // 2個目の数値、テキストフィールド
        TextField text2 = new TextField();
        text1.setPrefColumnCount(3);
        text1.setAlignment(Pos.BASELINE_CENTER);
        hBox.getChildren().add(text2);

        // 縦のレイアウトに追加する
        vBox.getChildren().add(hBox);

        // シーンの作成
        return vBox;
    }

    /**
     * HTMLローダーの画面(シーン)を作成します。
     * 
     * @return HTンLローダー画面
     */
    private Pane createHtmlLoaderPane() {
        StackPane pane = new StackPane();
        WebView web = new WebView();
        web.setPrefWidth(VIEW_WIDTH);
        web.setPrefHeight(VIEW_HEIGHT - 20);
        WebEngine engine = web.getEngine();
        engine.getLoadWorker().stateProperty()
            .addListener((observer, oldValue, newValue) -> {
                if (newValue == State.SUCCEEDED) {
                    System.out.println("*** Load is finished! ***");
                }
            });
        engine.load("http://zenryokuservice.com/wp/");
        pane.getChildren().add(web);
        System.out.println("非同期ロード処理開始");
        return pane;
    }

    /**
     * 画面のフッター部分にコントロール用のボタンを配置する。
     * 
     * @return Pane レイアウトコンテナ
     */
    private Pane createFooterPanel() {
        HBox hBox = new HBox(buttonList.size());
        for(Button ctlBtn : buttonList) {
            hBox.getChildren().add(ctlBtn);
        }
        return hBox;
    }

    /**
     * コントロールボタンを作成する。
     * 
     */
    private void cretateControllButtonList() {
        // デザインパターン:シングルトンの実装
        if (buttonList == null) {
            buttonList = new ArrayList\<Button\>();
        }
        Button viewChangeBtn = new Button("画面切り替え");
        viewChangeBtn.setOnAction(event -> {
            baseLayout.getChildren().remove(0);
            baseLayout.setCenter(createHtmlLoaderPane());
        });
        buttonList.add(viewChangeBtn);
        Button closeBtn = new Button("閉じる");
        buttonList.add(closeBtn);
    }
    /**
     * メインメソッド
     * @param args プログラム引数
     */
    public static void main(String[] args) {
        // 親クラスのメソッドを呼び出す、これは上のstart()を呼び出す。
        launch();
    }

    /**
     * JavaFX版のハローワールド実装用のメソッドになります。
     * @return 画面に出力する文字列
     */
    public String myFirstProgram() {
        // この「hyoji = ""」を「"hyoji = "Hello World"」と修正してください。
        String hyoji = "Hello World";
        long num = 12345678901L;
        float shosu = 123.09876543f;
        return hyoji;
    }
}

ソース中赤い字で記載している部分が、HTMLをロードする部分のコードになります。

ソースが長くなって来たので、まぁみづらい感じですが。。。以下の順番で処理は走っています。

  1.  mainメソッド
  2.  start()
  3.  cretateControllButtonList()
  4.  createJavaBasicPane()
  5.  createFooterPanel()
  6.    myFirstProgram()

赤い字の「ポイント1」

フィールド変数のボタンクラスのリスト(ArrayList)にボタンを作成して追加します。その後「createFooterPanel()」でリストからボタンを取得してPaneに登録しています。

赤い字の「ポイント2」

今回のJavaFX画面は「BorderLayout」の①「Center」と②「Bottom」を使用しています。

①は入力するとかWebの画面など「View」の部分です。

②は画面の下にあるボタンを配置する部分です。

おめでとうございます

なんやかんやと、JavaBasic画面とHTMLロード画面の(とりあえずの)作成が完了しました。

「初めてJavaをやった方」へ
よく頑張ったと思います。自分にご褒美をあげてください(笑)

「久しぶりやった方」へ
ネットワークのアクセス部分は新鮮だったのではないでしょうか?

「普段からコーディングしている方」へ
ネットワークのアクセス部分は新鮮だったのではないでしょうか?

「Java歴〜年の方」へ
まだまだ序の口なので、ご安心ください。そのうちにデザインパターンなども触れていきます。※まだ準備ができていません。。。

体制を整えようと思っています。

ちょっとソースが汚くなって来たのと、OpenCVでのチュートリアルを行うために、一度ソースを綺麗に(リファクタリング)しようと思います。

それは次回行いますが、目的としては以下の通り

  • FXMLをロードして画面コンポーネントとして画面に表示する
  • 今まで作成したものも使えるようにする
  • OpenCVを使うときの設定(プロジェクト)も改めてやる

というわけで、作成したものを移動してEclipseの1つのプロジェクトに整理しようと思います。※現状(2019/01/27)はPracticeJava1というプロジェクトに入っていますが、それを別プロジェクトを作成します。

でわでわ。。。

<<< 前回 次回 >>>

Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜

イントロダクション

前回は、イベント(アクション)の実装方法についてやりました。

画面的には「ボタンを作成して、押下した時に何かの処理を行う」というところまで来ました。※ボタンを押すとコンソールにACTIONと出力(イベントタイプ出力)する処理です。

 

画面切り替えの実装

そもそもの目的は「画面の切り替え」を目的にしています。なので画面を切り替えるのですが、現状のままだと切り替えた後の画面がありません。

なので切り替えた後の画面も作成します。HTMLをダウンロードして表示するというものです。

今まで、話題に出していませんでしたが、密かにHTMLロード画面を作成するためのメソッドを作っておきました。createHtmlLoaderPane()メソッドです。Gitにアップロード済みですので、必要に応じて使用してください。

現状(2019/01/27より前)のコード

/**
 * HTMLローダーの画面(シーン)を作成します。
 * 
 * @return HTンLローダー画面
 */
private Pane createHtmlLoaderPane() {
	
	return null;
}

初めは「シーン(Scene)クラス」が必要だと思っていたのですが、Paneクラスでやったほうが無難だと判断したのでPaneクラスを使用します。

参考にしたサイトはこちらです。

<実装してみたコード>

/**
 * HTMLローダーの画面(シーン)を作成します。
 * 
 * @return HTンLローダー画面
 */
private Pane createHtmlLoaderPane() {
	StackPane pane = new StackPane();
	WebView web = new WebView();
	web.getEngine().load("https://docs.oracle.com/javafx/2/get_started/jfxpub-get_started.htm");
	pane.getChildren().add(web);
	System.out.println("ロード完了");
	return pane;
}

<実行結果>

画面の切り替えはうまくいったけど、HTMLのロードがうまくいっていないようです。。。

これは、デバックするしかなさそうだ。。。この時点のソースはアップロードしておきます。Gitなのでダウンロードできます。

この問題をなんとかしてどうにかしなくては。。。今回はここまでにします。

でわでわ。。。

[rakuten ids="yukamimimi:10001634"]









Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜

イントロダクション

前回は、画面切り替え用のボタンを作成しました。

実行結果はこんな感じ。。。

現状(2019/01/27)としては、ボタンを押下しても何も動きません。なのでこの動き「イベント処理」を実装するというのが今回の趣旨です。

イベントの実装方法

イベント処理の実装方法としては、細かい話をすると結構な量になるので「やり方」から入ろうと思います。今後、その細かいところも記載いたします。

[参考サイト]

Oracleのチュートリアル

イベント(アクション)実装

ズバリこんな風に作りました。説明が足りませんで。。。

  1. 画面上に、ボタンを作成します。これが「viewChangeBtn」変数にセットされています。
  2. このボタンに「キーが推されたときの処理をセットする」メソッド「setOnKeyPressed」をしようしてその処理を書きます。
  3. 「XXXされたとき」のような処理のことを「イベント処理」といい、EventHandlerインターフェースを実装します。
  4. EventHandlerインターフェースは、処理の内容が実装されていないのでそれを実装する必要があります。この時に実装しなくてはいけないのがインターフェースに定義されているメソッドです。
  5. インタフェースは処理内容が定義されていませんが。implements(実装)するときに定義されているメソッドをオーバーライドしてやる必要があります。「@Override」がついているメソッドがオーバーライドしているメソッドになります。
  6. そして、作成したボタンをPrimaryステージクラスに追加してやれば表示できます。
Button viewChangeBtn = new Button("画面切り替え");
viewChangeBtn.setOnKeyPressed(new EventHandler() {
    @Override
    public void handle(KeyEvent event) {
                // テスト用のコード
        System.out.println(event.getText());
    }
});

そして実行

ボタンを押下すると「ボタンの文字」がコンソールに出力されるはずなのですが、なにもでない。。。

ちょっと画面をいじってみると「ボタンを選択してからPCのキーボードを叩くと」コンソールに文字が出力されました。

KeyEventではなく、ActionEventの方を使うのが正しい実装でした。

<ソースの修正>

Button viewChangeBtn = new Button("画面切り替え");
viewChangeBtn.setOnAction(event -> {
    System.out.println(event.getEventType());
});

KeyEventと ActionEventで少し実装方法が違います。そして動かしてみる!

こんな感じでコンソールに出力されました。これでボタンに対するイベント(アクション)処理は実装できました。次回は、ボタン押下時に画面を切り替える方向に実装部分を修正します。

Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜

イントロダクション

前回は、リファクタリングを行いました。これで追加の実装を行う準備ができた状態です。

ちなみに、このページは以下の順序で進んできています。

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜

※「四則計算」の部分で基本的なプログラムに関する記載を止めています。2019/01/26現在(クイズの答えを2019/02/01に出すのでそれまでストップします)

そして、前回は「リファクタリング」を行いました。大したことはしていませんが、小さくてもプロジェクト的に自分のアプリケーションを作るならちょくちょくと「リファクタリング」をやったほうが、スキルアップできます。

画面にボタンを追加する

前回、整理をしたので機能追加などが、しやすくなっています。

Gitで差分を比較して見ることができます。やり方はこちら

ボタンの追加方法

単純にボタンを追加すればOKです。

// ボタンの作成
Button viewChangeBtn = new Button("画面切り替え");
Button closeBtn = new Button("閉じる");

そして、ペイン(レイアウト)に追加

hBox.getChildren().add(ctlBtn);

これを、自分なりにまとめて追加すると以下のように表示されました。

現状ではボタンを押下しても何も起きません。イベント処理を実装する必要があります。

「イベント処理」というのは

  • 「ボタンが押下された」
  • 「マウスが乗っかった」

などのイベントがあった時に動く処理を実装するための「イベントリスナー」のことを言っています。

具体的には次回、記載しますが「クリック」「ダブルクリック」「マウスオーバー」「キーダウン」などこれらのイベントを受け取る仕組み(フレームワーク)が実装済みです(JavaFXで実装)ので、各イベントに対する処理はイベントリスナーを実装してやれば良いのです。

「実装する」とは

単純に処理(コード)を書くことです。が上での意味は「インターフェースを実装する」という意味です。

細かいことは次回にします。でわでわ。。。

  1. Java Basic インターフェース・抽象クラスの作り方
  2. Java Basic クラスとは〜Step2_1

Java StepUpPrograming〜JavaFXで画面切り替え1リファクタ〜

イントロダクション

前回は、JavaFXで四則計算の入力部分を作成しました。しかし、答えは2019/02/01に公開する予定なのでJavaFXでのJava基本編は一時停止になります。

駄菓子菓子、時間は待ってくれないので方向を分けて画面を切り替えられるように追加修正します。

画面切り替え?

そう!画面切り替えです。以前のブログで今回のプログラム概要図を作成しました。

JavaFXのフレームワーク上にシーンを複数作成して切り替えるイメージです。

そこで使用するのが「コンテナ」です。Webアプリケーションでよく「アプリケーションコンテナ」などと呼ばれています。このコンテナにはシーンを登録していつでも呼び出せるようにしようと思います。さしずめ「シーンコンテナ」ですね(笑)

ソースを改造(リファクタリング)する

色々と追加してくるとソースが汚くなります。部屋と一緒で整理整頓する必要があるので、そのようにします。ちなみにソースの整理整頓は「リファクタリング」と呼び、綺麗に、みやすく、改修しやすく。。。と理想を追いかけるとキリがないような感じですが、やっておくと今後「あ!」と思ったときに役に立ちますし、仕事でも喜ばれます。「リーダブルコード」は、自分的に、とてもわかりやすいものでしたし、気がつくこともたくさんありました。例え話が面白かったです。

ちなみにツイッターで「リーダブルコード」を聖典としてよみ、その布教に努めております(笑)

<元のソース:ソースを株分けしました>

※初めのクラス名は「RootFxMain」「2」がついていません。。。

package jp.zenryoku.fx;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 * JavaFXでのハローワールド〜OpenCVなどの
 * 作成したアプリをテストするための、スタンドアロンアプリ。
 * 
 * @author takunoji
 * 2019/01/23
 */
public class RootFxMain2 extends Application {
    /** 画面の縦幅 */
    private double VIEW_HEIGHT;
    /** 画面の横幅 */
    private double VIEW_WIDTH;
    /**
     * 親クラスのメソッドをオーバーライドする。
     * 画面を作成したり、シーンを作成したり、色々。。。
     * 
     * @see javafx.application.Application#start(javafx.stage.Stage)
     */
    @Override
    public void start(Stage primaryStage) throws Exception {
        // Stageの設定
        primaryStage.setHeight(VIEW_HEIGHT);
        primaryStage.setWidth(VIEW_WIDTH);
        // レイアウトたて
        VBox vBox = new VBox(5);
        // レイアウト横
        HBox hBox = new HBox(8);
        // ラベルの設定
        Label label = new Label();
        // ハローワールドを出力する
        label.setText(myFirstProgram());
        label.setFont(new Font("RobotRegular", 24));
        vBox.getChildren().add(label);

        // 1個目の数値、テキストフィールド
        TextField text1 = new TextField();
        text1.setPrefColumnCount(3);
        text1.setAlignment(Pos.BASELINE_CENTER);
        hBox.getChildren().add(text1);
        // 計算式のラベル
        Label ope = new Label("+");
        hBox.getChildren().add(ope);

        // 2個目の数値、テキストフィールド
        TextField text2 = new TextField();
        text1.setPrefColumnCount(3);
        text1.setAlignment(Pos.BASELINE_CENTER);
        hBox.getChildren().add(text2);

        // 縦のレイアウトに追加する
        vBox.getChildren().add(hBox);
        // ペインの作成
        Group root = new Group();
        root.getChildren().add(vBox);

        // シーンの作成
        Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * メインメソッド
     * @param args プログラム引数
     */
    public static void main(String[] args) {
        // 親クラスのメソッドを呼び出す、これは上のstart()を呼び出す。
        launch();
    }

    /**
     * JavaFX版のハローワールド実装用のメソッドになります。
     * @return 画面に出力する文字列
     */
    public String myFirstProgram() {
        // この「hyoji = ""」を「"hyoji = "Hello World"」と修正してください。
        String hyoji = "Hello World";
        long num = 12345678901L;
        float shosu = 123.09876543f;
        return hyoji;
    }
}

ちなみに「リーダブルコード」では変数、メソッド名のネーミングにも言及しています。が、今回は仕事でもないし、プログラムも一人で作れるレベルの規模なので細かいところは勘弁していただきたく。。。

そして、修正するポイントは上のソースの緑字の部分をメソッドに切り分けます。元ソースの「startメソッド」を整理しました。

<リファクタリング1>

/**
 * 親クラスのメソッドをオーバーライドする。
 * 画面を作成したり、シーンを作成したり、色々。。。
 * 
 * @see javafx.application.Application#start(javafx.stage.Stage)
 */
@Override
public void start(Stage primaryStage) throws Exception {
    // Stageの設定
    primaryStage.setHeight(VIEW_HEIGHT);
    primaryStage.setWidth(VIEW_WIDTH);
    primaryStage.setScene(createJavaBasicScene());
    primaryStage.show();
}

/**
 * シーンの作成部分を切り出ししました。
 * このシーンはJavaの基本を実行する時用にします。
 * 
 * @see http://zenryokuservice.com/wp/2019/01/25/java-stepupprogr…avafxで画面切り替えを作る〜/
 * @return JavaBasic用のシーン
 */
private Scene createJavaBasicScene() {
    // レイアウトたて
    VBox vBox = new VBox(5);
    // レイアウト横
    HBox hBox = new HBox(8);
    // ラベルの設定
    Label label = new Label();
    // ハローワールドを出力する
    label.setText(myFirstProgram());
    label.setFont(new Font("RobotRegular", 24));
    vBox.getChildren().add(label);

    // 1個目の数値、テキストフィールド
    TextField text1 = new TextField();
    text1.setPrefColumnCount(3);
    text1.setAlignment(Pos.BASELINE_CENTER);
    hBox.getChildren().add(text1);
    // 計算式のラベル
    Label ope = new Label("+");
    hBox.getChildren().add(ope);

    // 2個目の数値、テキストフィールド
    TextField text2 = new TextField();
    text1.setPrefColumnCount(3);
    text1.setAlignment(Pos.BASELINE_CENTER);
    hBox.getChildren().add(text2);

    // 縦のレイアウトに追加する
    vBox.getChildren().add(hBox);
    // ペインの作成
    Group root = new Group();
    root.getChildren().add(vBox);

    // シーンの作成
    return new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
}

リファクタリングしたら即テストを行い、実行内容が変わっていないことを確認します。作成したコードはこちらです(GIT)

ふー。。。リファクタリング成功のようです。

ここでクイズです。

上の画像にあるテキストフィールドには「問題」があります。それはなんでしょうか?

<ヒント>

アプリケーションとして、他の人が使用するときにこのままの入力(テキストフィールド)では足りない機能がたくさんあります。

ちょっと長くなったので続きは次回。。。

でわでわ。。。

<<< 前へ 次へ >>>