Java Basic GUI作成〜今までのまとめ〜

イントロダクション

前回は、Javaアプリからgoogleのホームページ(検索画面)にアクセスして開く為の設計を行い、コマンドを実行する為のプロパティファイルを参照してコマンドに対応したクラス名を取得する為の実装を行いました。

Introduction

Last time we designed to access google home page.And create a property file to execute command to get class for each functions.

途中、クローリングなど実装しようと思ったのでクローリングについて調べました。
今回は、コマンドを実行するところをやります。

前回までの実装内容

画面全体をテキストエリアとして表示する
入力画面の入力チェック部分を作成する
画面の入力制御(上下のボタンを無効にする)
コマンドの取得を行う
プロパティファイルを読む

設計

コマンドの文字列をキーにして完全クラス名を取得します。この「完全クラス名」というのは、パッケージ名を含む全体のクラス名のことです。
作成中の「CmdView」クラスの完全クラス名は「jp.zenryoku.game.gui.CmdView」になります。

そして、ちょっとややこしいのですがコマンドを取得して

String command = getCommand(allText);

コマンドの実行を行うときに

executeCmd(command);

プロパティファイルを取得しておきたいのでテキストエリアを作成するときに一緒に読み込みを行います。※読み込み確認用にコンソール出力します。

// プロパティファイルのロード
bndle = ResourceBundle.getBundle(CMD_PROPERTY);
System.out.println("Properties: " + bndle.getString("acc"));

上記のResourceBundleクラスはビルドパス上にあるgetBundle(XXXX);にある「XXXX」のファイル名を検索して取得します。※XXXX.propertiesを検索

筆者はプロジェクトにリソースフォルダ「resources」を追加して「resources/CmdCls.properties」のように作成いたしました。

前回までのソース

public class CmdView extends Application {
    /** 画面の横サイズ */
    private static final int VIEW_WIDTH = 300;
    /** 画面のたてサイズ */
    private static final int VIEW_HEIGHT = 300;
    /** コマンドの入力開始文字 */
    private static final String CMD_START = "Cmd $ >";
    /** 改行コード */
    private static final String LINE_SEPARETOR = System.getProperty("line.separator");
    /** プロパティファイル名 */
    private static final String CMD_PROPERTY = "CmdCls";
    /** 入力前のカーソル位置 */
    private int cursorPos;
    /** リソースバンドル */
    private ResourceBundle bndle;

    @Override
    public void start(Stage primary) {
        TextArea area = createTextArea();
        Group root = new Group();
        root.getChildren().add(area);
        Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
        primary.setScene(scene);
        primary.show();

        // プロパティファイルのロード
        bndle = ResourceBundle.getBundle(CMD_PROPERTY);
        System.out.println("Properties: " + bndle.getString("acc"));
    }

    /**
     * TextAreaを作成して返却する
     * @return TextArea
     */
    private TextArea createTextArea() {
        TextArea area = new TextArea();
        // 縦横の幅を設定する
        area.setPrefWidth(VIEW_WIDTH);
        area.setPrefHeight(VIEW_HEIGHT);
        area.setOnKeyPressed(createKeyPressEvent());
        // 初期表示文字を設定する
        area.setText("Hello user please input command!" + LINE_SEPARETOR + CMD_START);
        // テキストエリアの文字列数
        int textLen = area.getText().length();
        // 初期カーソル位置
        cursorPos = textLen;
        area.positionCaret(textLen);

        return area;
    }

    /**
     * イベント処理を行うクラスを生成<BR/>
     * ・入力チェックを行い、禁止入力があった場合はカーソルを元の位置に戻す。
     * @return キー入力のイベント処理クラス
     */
    private EventHandler<KeyEvent> createKeyPressEvent() {
        return new EventHandler<KeyEvent>() {
            public void handle(KeyEvent evt) {
                // テキストエリアを取得する
                TextArea src = (TextArea) evt.getSource();
                // 入力を無効にする
                if (isDisabledInput(evt)) {
                    System.out.println("*** isDisable ***");
                    resetCursor(src);
                    return;
                }
                if (KeyCode.ENTER.equals(evt.getCode())) {
                    // テキストエリア内の文字列を全て取得
                    String allText = src.getText();
                    String command = getCommand(allText);
                    src.setText(allText + CMD_START);
                    // "Cmd $ "の文字列の位置を取得
                    System.out.println("Command: " + command);
                    // コマンドの実行
                    executeCmd(command);
                    cursorPos = allText.length() + CMD_START.length();
                    src.positionCaret(cursorPos);
                }
                if (KeyCode.LEFT.equals(evt.getCode())) {
                    // 左の矢印が押下された時
                    src.positionCaret(cursorPos);
                }
                // チェック用のコンソール出力処理
                System.out.println("EventType: " + evt.getCode());
            }
        };
    }

    /**
     * キーボードより入力したキーで受け付けないものを<BR/>
     * 判定する
     * @param evt
     * @return true: 受け付けない入力  /  false: 受け付ける入力
     */
    private boolean isDisabledInput(KeyEvent evt) {
        boolean isDisable = false;
        // 入力許可キーのKeyCodeリスト
        List<KeyCode> acList = createAcceptList();

        // チェック処理: 入力禁止するキーの有無をチェック
        return acList.contains(evt.getCode());
    }
    /**
     * プロパティファイル、キーを指定して対象のプロパティを<BR/>
     * 取得する
     *
     * @param propNane プロパティファイル名
     * @param key プロパティのキー
     * @return プロパティの値
     */
    @Deprecated // 使用しないメソッド
    private String getTargetProperty(String propNane, String key) {
        String propStr = null;
        return propStr;
    }

    /**
     * チェック用のリストを作成して返却します<BR/>
     * 入力禁止のKeyCodeを追加
     * @return チェック用のリスト
     */
    private List<KeyCode> createAcceptList() {
        List<KeyCode> acList = new ArrayList<KeyCode>();
        acList.add(KeyCode.UP);
        acList.add(KeyCode.DOWN);

        return acList;
    }

    /**
     * カーソルの移動をしないようにします。
     * @param src
     */
    private void resetCursor(TextArea src) {
        // 始めのカーソル位置を設定する
        src.positionCaret(cursorPos);
    }

    /**
     * コマンドを取得します<BR/>
     * @param text テキストエリアにある文字列全部
     * @return 入力した文字列部分のみ
     */
    private String getCommand(String text) {
        String[] lines = text.split(LINE_SEPARETOR);
        String target = lines[lines.length - 1];
        return target.substring(CMD_START.length());
    }

    /**
     * コマンドを実行します<BR/>
     * 登録したコマンドにない入力の時は<BR/>
     * エラーメッセージをテキストエリアに出力します。
     * @param command コマンド文字列
     */
    private void executeCmd(String command) {
        try {
            String className = bndle.getString(command);
            System.out.println("ClassName: " + className);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    /** メインメソッド */
    public static void main(String[] args) {
        launch();
    }
}

だんだん長くなってきましたが、慣れれば長いのも気になくなります。

※悪いことも気にならなくなるので気をつけましょう→筆者は特に!!

ポイントとしては、メソッドの中身が長くならないことです。筆者の理想としてはメソッドは20行以上にしたくありません。→努力いたします。

<処理概要>
1. メインメソッド: (親クラス)Application.start()を実行
2.start(): 親クラスのメソッドをオーバーライドします。テキストエリアを作成しコンテナ(javaFxの表示用格納庫)にテキストエリアを追加
3. createTextArea(): テキストエリアを作成し、カーソルの位置を最後尾に移動します。
4. createKeyPressEvent(): テキストエリアの入力時の操作を実装
5. resetCursor(): カーソルを元の位置に戻します。※元の位置は、最後にキーを押した時の位置です。
6. getCommand(): テキストエリアから全テキストを取得して最後の行にある「Cmd $ >」の文字列以降の部分を取得します。(コマンド)
7. executeCommand(): 今回実装します。

executeCommandの実装

前回は、以下のような形で、入力文字を表示するところまで実装しました。

/**
 * コマンドを実行します<BR/>
 * 登録したコマンドにない入力の時は<BR/>
 * エラーメッセージをテキストエリアに出力します。
 * @param command コマンド文字列
 */
private void executeCmd(String command) {
    try {
        String className = bndle.getString(command);
        System.out.println("ClassName: " + className);
    } catch(Exception e) {
        e.printStackTrace();
    }
}

影に隠れて見づらいですが、「Properties: test」という文言が見えると思います。プロパティファイル上の方です。

余談ですが、バグを発見 ※他にもあります。

矢印キーでのカーソル移動は禁止しているのですが「バックスペース」削除ボタンは何もしていないので、下のように削除できてしまい。これ以降はコマンドを取得できなくなってしまいます。

なので追加設計を行います。

追加設計

「削除ボタン押下時にカーソルの位置が『Cmd $ >』に重なるような位置にいるか判定してから削除する。」の処理を追加します。
そして、コマンド実行後のカーソル位置を追加して、現在のカーソル位置とフィールド変数を二つ使用します。

/** 入力前のカーソル位置 */
private int currentPos;
/** 改行した時のカーソル位置 */
private int startCursorPos;

そして、修正した箇所になります。コンソール出力は気にしないでください。

if (KeyCode.LEFT.equals(evt.getCode())) {
    System.out.println("Sart: " + startCursorPos + " Current: " + currentPos + " getCaret: " + src.getCaretPosition());
    if (startCursorPos > src.getCaretPosition()) {
        // 左の矢印が押下された時
        src.positionCaret(currentPos);
    }
}
currentPos = src.getCaretPosition();

コマンドからクラスを取得する、準備1

コマンドで呼び出すクラスにCommandIFクラス(インターフェース)を実装します。

【インターフェース】

public interface CommandIF {
    public void execute();
}

【実装クラス】

public class UrlAccessor implements CommandIF {
    @Override
    public void execute() {
        System.out.println("Hello Command Interface!!");
    }
}

コマンドの実行部分

/**
 * コマンドを実行します<BR/>
 * 登録したコマンドにない入力の時は<BR/>
 * エラーメッセージをテキストエリアに出力します。
 * @param command コマンド文字列
 */
private void executeCmd(String command) {
    try {
        String className = bndle.getString(command);
        System.out.println("ClassName: " + className);
        // 完全クラス名よりクラスのインスタンスを取得する
        Class<?> cls = Class.forName(className);
        Constructor<?> cons = cls.getConstructor();
        CommandIF exe = (CommandIF) cons.newInstance();
        exe.execute();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

【プロパティファイル】文字だけだとわかりづらいので。。。

acc=jp.zenryoku.apps.UrlAccessor

【実行結果】

「Hello Command Interface!!」が表示されています。

長くなってしまいましたが。。。
以上、お疲れ様でした。



Java GUI作成 〜プロパティファイルを読む〜

イントロダクション

前回、クローリングについて学びました。
今回は、フレームワークなどを使用しないでウェブにアクセスしてみようと思います。

やってみること

・フレームワーク(外部のJar)などを使用せずにJDKに含まれているパッケージを使用して実装する。
・作成中のGUIの「CmdView」でコマンドを入力して起動するように追加修正する

設計

<要件>
・指定したURLにアクセスする実装は「UrlAccessor」クラスに任せる
・起動と結果の表示は「CmdView」クラスで行う

<実装部分>
・新規で「UrlAccessor」クラスを作成する
・「CmdView」クラスに「acc」コマンドが入力された時にgoogleの検索画面にアクセスする

追加修正する場所

CmdView

コマンドを実行する為のメソッドを追加

if (KeyCode.ENTER.equals(evt.getCode())) {
    // テキストエリア内の文字列を全て取得
    String allText = src.getText();
    String command = getCommand(allText);
    src.setText(allText + CMD_START);
    // "Cmd $ "の文字列の位置を取得
    System.out.println("Command: " + command);
    // コマンドの実行
    executeCmd(command);
    cursorPos = allText.length() + CMD_START.length();
    src.positionCaret(cursorPos);
}

コマンドを実行する為のキーとプロパティを作成
<フィールドにプロパティファイル名(パス)>

/** プロパティファイル名 */
private static final String CMD_PROPERTY = "CmdCls";
/** リソースバンドル */
private ResourceBundle bndle;

<プロパティファイルのロード>

// プロパティファイルのロード
bndle = ResourceBundle.getBundle(CMD_PROPERTY);
System.out.println("Properties: " + bndle.getString("acc"));
/**
 * コマンドを実行します<BR/>
 * 登録したコマンドにない入力の時は<BR/>
 * エラーメッセージをテキストエリアに出力します。
 * @param command コマンド文字列
 */
private void executeCmd(String command) {
     // この部分は次回作成します。
}

コマンドの実装部分は次回ということで
でわでわ。。。


Java Basic GUI作成〜JavaFXを使用して画面を作る〜

イントロダクション

スタンドアロンでのJavaアプリケーションを作成します。
理由は、ウェブアプリケーションだとでかくなってしまい。Javaコードに集中できないからです。実際にJSPとかHTMLとか。。。作成することになるからです。
シンプルに、Javaのみで画面を作成し起動できるJavaFXでの実装を行います。

プログラムを作成する

コードはいたってシンプル ※作成物はこちら

public class CmdView extends Application {
    /** 画面の横サイズ */
    private static final int VIEW_WIDTH = 300;
    /** 画面のたてサイズ */
    private static final int VIEW_HEIGHT = 300;

    @Override
    public void start(Stage primary) {
        TextArea area = createTextArea();
        Group root = new Group();
        root.getChildren().add(area);
        Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
        primary.setScene(scene);
        primary.show();
    }

    /**
     * TextAreaを作成して返却する
     * @return TextArea
     */
    private TextArea createTextArea() {
        TextArea area = new TextArea();
        // 縦横の幅を設定する
        area.setPrefWidth(VIEW_WIDTH);
        area.setPrefHeight(VIEW_HEIGHT);
        area.setOnKeyPressed(createKeyPressEvent());

        return area;
    }

    private EventHandler<KeyEvent> createKeyPressEvent() {
        return new EventHandler<KeyEvent>() {
            public void handle(KeyEvent evt) {
                if (KeyCode.ENTER.equals(evt.getCode())) {
                    // Enter キーを謳歌した時の処理、テキストエリアを取得する
                    TextArea src = (TextArea) evt.getSource();
                    System.out.println("Press Enter: " + src.getText());
                }
                // チェック用のコンソール出力処理
                System.out.println("EventType: " + evt.getCode());
                System.out.println("Input: " + evt.getCharacter());
            }
        };
    }

    /** メインメソッド */
    public static void main(String[] args) {
        launch();
    }
}

Applicationクラスを拡張して作成します。

public class CmdView extends Application

メインメソッドは一番下で、親クラスのlaunchメソッドを呼び出すだけです。

/** メインメソッド */
public static void main(String[] args) {
    launch();
}

プログラムを起動したらメインメソッドが走ります。
その次に「launch()」が走るのですが、これは下のメソッド
start()を呼び出します。オーバーライドしてやるのでこのクラスの
処理が走ります。
ちなみに、フレームワークなどを作りたいときはこのような
「〜継承して〜オーバーライドすればOK」の形で作成します。
※手法の一つです。

@Override
public void start(Stage primary) {
    TextArea area = createTextArea();
    Group root = new Group();
    root.getChildren().add(area);
    Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
    primary.setScene(scene);
    primary.show();
}

TextAreaは下のprivateメソッドで作成しています。

/**
 * TextAreaを作成して返却する
 * @return TextArea
 */
private TextArea createTextArea() {
    TextArea area = new TextArea();
    // 縦横の幅を設定する
    area.setPrefWidth(VIEW_WIDTH);
    area.setPrefHeight(VIEW_HEIGHT);
    area.setOnKeyPressed(createKeyPressEvent());

    return area;
}

「public」は、外から呼べるメソッド
「private」は、このクラス内でのみ使用できる
こんな感じです。

ここから、画面の入力(コマンド)に対して処理を実行するように
修正していこうと思います。



Java network 〜クローリング〜

イントロダクション

前回作成した、コマンド画面で入力した文字を…
つまり、コマンドを取得することこまで実装しました。
現状何をするのか決まっていませんが、インターネット検索を行い必要な情報を取得する機能が欲しいと思っている所ですので、クローリングに挑戦したいと思います。

クローリングって何?

クローリング…筆者もよくわかっていないので調べます。
以下のステップで検索して、結果を出します。

1. Googleの検索テキストボックスに文字列を入力する
2. 適当なサイトの中身を読み記載内容を自分の中でまとめます。
3. まとめた内容から理解します。
※「理解する」というのが抽象的ですので「〜はXXXをする○○○である」というふうに情報を
  整理することを指し示す事とします。

そして、自分が調べてみた所

「クローリングとは、ウェブサイトに辿り着く→ 解析 →リンクを辿る処理を繰り返し行うプログラムのこと」という結果が出ました。

参考にしたサイトは以下のサイトです。
https://nandemo-nobiru.com/3661/#0102

理想と現実

なんでも「こーだったらいいな」っていう事と「実際ここまでだよね」っていう事があると思います。
その通りだと思います。ならば「こーだったらいいな」に近づけるために「実際こーだよね」っていうことを掘り下げます。
つまり、理想と現実を並べてみて現状、どの部分からなら着手できるかを探します。

やってみましょう(プログラム初心者の場合)

理想は、クローリングを実装してウェブ上から欲しい情報を取得、まとめた形でレポートを作成し、それを出力して自分が確認できる事。
現状は、すでにあるフレームワーク(ライブラリやツール)を使う為の勉強と実装を行っていく事が一番の早道になると思います。
でわ、ライブラリやフレームワークを探します。
そして、Javaをメインにやっているので以下の4点を見つけました。
参照サイトはこちらになります。
・jsourp
・crowler4j
・Apache Tika
・Apache Nutch

フレームワークは何を使う?

ぶっちゃけてなんでも良いと思います。筆者は自分で作成しようかと思っていました。が書いている最中に「初心者向けに。。。」と考えたらフレームワークの方が良いのではないかと思った次第です。
しかし、フレームワークだろうが、なんだろうがJavaを使用している限りはJDKを使用してるので自分で作る方向で行きましょう。というわけで

結論、corwler4jを使用しよう

Gitにありました。「corwler4j

次回は、このページを勉強してみようと思います。
次回は、JDKに含まれているjavaパッケージを使用しようと思います。
でわでわ。。。

Java Basic GUI作成〜コマンドを入力する〜

イントロダクション

前回は、カーソルを上下に移動しないように修正しました。
今回は、入力した文字を取得します。
入力した文字はコマンドとして使用したいので
入力した文字列は「コマンド」と呼ぶことにします。

・テキストエリアからコマンドを取得する
・カーソルが「Cmd $ >」に被らないようにする

実装しているコードはGITにあります。

設計〜修正する場所〜

エンターキーを押下した時にコマンドを取得、実行する想定
なので、エンターキーを押下した時の処理を修正します。
下のコードでは赤くしている部分です。

前回までのコード

public class CmdView extends Application {
    /** 画面の横サイズ */
    private static final int VIEW_WIDTH = 300;
    /** 画面のたてサイズ */
    private static final int VIEW_HEIGHT = 300;
    /** コマンドの入力開始文字 */
    private static final String CMD_START = "Cmd $ ";
    /** 改行コード */
    private static final String LINE_SEPARETOR = System.getProperty("line.separator");
    /** 入力前のカーソル位置 */
    private int cursorPos;

    @Override
    public void start(Stage primary) {
        TextArea area = createTextArea();
        Group root = new Group();
        root.getChildren().add(area);
        Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
        primary.setScene(scene);
        primary.show();
    }

    /**
     * TextAreaを作成して返却する
     * @return TextArea
     */
    private TextArea createTextArea() {
        TextArea area = new TextArea();
        // 縦横の幅を設定する
        area.setPrefWidth(VIEW_WIDTH);
        area.setPrefHeight(VIEW_HEIGHT);
        area.setOnKeyPressed(createKeyPressEvent());
        // 初期表示文字を設定する
        area.setText("Hello user please input command!" + LINE_SEPARETOR + CMD_START);
        // テキストエリアの文字列数
        int textLen = area.getText().length();
        // 初期カーソル位置
        cursorPos = textLen;
        area.positionCaret(textLen);

        return area;
    }

    private EventHandler<KeyEvent> createKeyPressEvent() {
        return new EventHandler<KeyEvent>() {
            public void handle(KeyEvent evt) {
                // テキストエリアを取得する
                TextArea src = (TextArea) evt.getSource();
                // 入力を無効にする
                if (isDisabledInput(evt)) {
                    System.out.println("*** isDisable ***");
                    resetCursor(src);
                    return;
                }
                                
                if (KeyCode.ENTER.equals(evt.getCode())) {
                    // テキストエリア内の文字列を全て取得
                    String allText = src.getText();
                    // "Cmd $ "の文字列の位置を取得
                    int startPoint = allText.indexOf(CMD_START);
                }
                
                cursorPos = src.getCaretPosition();
                // チェック用のコンソール出力処理
                System.out.println("EventType: " + evt.getCode());
                System.out.println("Input: " + evt.getCharacter());
            }
        };
    }

    /**
     * キーボードより入力したキーで受け付けないものを<BR/>
     * 判定する
     * @param evt
     * @return true: 受け付けない入力  /  false: 受け付ける入力
     */
    private boolean isDisabledInput(KeyEvent evt) {
        boolean isDisable = false;
        // 入力許可キーのKeyCodeリスト
        List<KeyCode> acList = createAcceptList();

        // チェック処理: 入力禁止するキーの有無をチェック
        return acList.contains(evt.getCode());
    }
    /**
     * プロパティファイル、キーを指定して対象のプロパティを<BR/>
     * 取得する
     *
     * @param propNane プロパティファイル名
     * @param key プロパティのキー
     * @return プロパティの値
     */
    @Deprecated // 使用しないメソッド
    private String getTargetProperty(String propNane, String key) {
        String propStr = null;
        return propStr;
    }

    /**
     * チェック用のリストを作成して返却します<BR/>
     * 入力禁止のKeyCodeを追加
     * @return チェック用のリスト
     */
    private List<KeyCode> createAcceptList() {
        List<KeyCode> acList = new ArrayList<KeyCode>();
        acList.add(KeyCode.UP);
        acList.add(KeyCode.DOWN);

        return acList;
    }

    /**
     * カーソルの移動をしないようにします。
     * @param src
     */
    private void resetCursor(TextArea src) {
        // 始めのカーソル位置を設定する
        src.positionCaret(cursorPos);
    }


    /** メインメソッド */
    public static void main(String[] args) {
        launch();
    }
}

今回の追加修正する場所

・エンターキーを押下した時に入力した文字列を取得する
・エンターキーを押下した後に「Cmd $ >」を追加する
※実装済みなので修正しないが範囲に入るので。。。
・カーソルを横に動かした時に「Cmd $ >」に入らないようにする

追加したコード(抜粋)

修正した部分になりますが、テキストエリアの取得位置を変更

// テキストエリアを取得する
TextArea src = (TextArea) evt.getSource();

エントーキーを押下した時の処理を変更

if (KeyCode.ENTER.equals(evt.getCode())) {
    // テキストエリア内の文字列を全て取得
    String allText = src.getText();
    String command = getCommand(allText);
    src.setText(allText + CMD_START);
    // "Cmd $ "の文字列の位置を取得
    System.out.println("Command: " + command);
    cursorPos = allText.length() + CMD_START.length();
    src.positionCaret(cursorPos);
}

余計な処理になったので以下の処理を削除

// テキストエリアのカーソル位置をフィールド変数にセット
cursorPos = src.getCaretPosition();

左の矢印を入力した時のハンドル
(どのような振る舞いをするか?)をする処理を修正

if (KeyCode.LEFT.equals(evt.getCode())) {
    // 左の矢印が押下された時
    src.positionCaret(cursorPos);
}

最終的なコード

public class CmdView extends Application {
    /** 画面の横サイズ */
    private static final int VIEW_WIDTH = 300;
    /** 画面のたてサイズ */
    private static final int VIEW_HEIGHT = 300;
    /** コマンドの入力開始文字 */
    private static final String CMD_START = "Cmd $ >";
    /** 改行コード */
    private static final String LINE_SEPARETOR = System.getProperty("line.separator");
    /** 入力前のカーソル位置 */
    private int cursorPos;

    @Override
    public void start(Stage primary) {
        TextArea area = createTextArea();
        Group root = new Group();
        root.getChildren().add(area);
        Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
        primary.setScene(scene);
        primary.show();
    }

    /**
     * TextAreaを作成して返却する
     * @return TextArea
     */
    private TextArea createTextArea() {
        TextArea area = new TextArea();
        // 縦横の幅を設定する
        area.setPrefWidth(VIEW_WIDTH);
        area.setPrefHeight(VIEW_HEIGHT);
        area.setOnKeyPressed(createKeyPressEvent());
        // 初期表示文字を設定する
        area.setText("Hello user please input command!" + LINE_SEPARETOR + CMD_START);
        // テキストエリアの文字列数
        int textLen = area.getText().length();
        // 初期カーソル位置
        cursorPos = textLen;
        area.positionCaret(textLen);

        return area;
    }

    private EventHandler<KeyEvent> createKeyPressEvent() {
        return new EventHandler<KeyEvent>() {
            public void handle(KeyEvent evt) {
                // テキストエリアを取得する
                TextArea src = (TextArea) evt.getSource();
                // 入力を無効にする
                if (isDisabledInput(evt)) {
                    System.out.println("*** isDisable ***");
                    resetCursor(src);
                    return;
                }
                if (KeyCode.ENTER.equals(evt.getCode())) {
                    // テキストエリア内の文字列を全て取得
                    String allText = src.getText();
                    String command = getCommand(allText);
                    src.setText(allText + CMD_START);
                    // "Cmd $ "の文字列の位置を取得
                    System.out.println("Command: " + command);
                    cursorPos = allText.length() + CMD_START.length();
                    src.positionCaret(cursorPos);
                }
                if (KeyCode.LEFT.equals(evt.getCode())) {
                    // 左の矢印が押下された時
                    src.positionCaret(cursorPos);
                }
                // チェック用のコンソール出力処理
                System.out.println("EventType: " + evt.getCode());
            }
        };
    }

    /**
     * キーボードより入力したキーで受け付けないものを<BR/>
     * 判定する
     * @param evt
     * @return true: 受け付けない入力  /  false: 受け付ける入力
     */
    private boolean isDisabledInput(KeyEvent evt) {
        boolean isDisable = false;
        // 入力許可キーのKeyCodeリスト
        List<KeyCode> acList = createAcceptList();

        // チェック処理: 入力禁止するキーの有無をチェック
        return acList.contains(evt.getCode());
    }
    /**
     * プロパティファイル、キーを指定して対象のプロパティを<BR/>
     * 取得する
     *
     * @param propNane プロパティファイル名
     * @param key プロパティのキー
     * @return プロパティの値
     */
    @Deprecated // 使用しないメソッド
    private String getTargetProperty(String propNane, String key) {
        String propStr = null;
        return propStr;
    }

    /**
     * チェック用のリストを作成して返却します<BR/>
     * 入力禁止のKeyCodeを追加
     * @return チェック用のリスト
     */
    private List<KeyCode> createAcceptList() {
        List<KeyCode> acList = new ArrayList<KeyCode>();
        acList.add(KeyCode.UP);
        acList.add(KeyCode.DOWN);

        return acList;
    }

    /**
     * カーソルの移動をしないようにします。
     * @param src
     */
    private void resetCursor(TextArea src) {
        // 始めのカーソル位置を設定する
        src.positionCaret(cursorPos);
    }

    private String getCommand(String text) {
        String[] lines = text.split(LINE_SEPARETOR);
        String target = lines[lines.length - 1];
        return target.substring(CMD_START.length());
    }
    /** メインメソッド */
    public static void main(String[] args) {
        launch();
    }
}

以上のような形で実装してみました。
現状では、以下のような感じでコマンドの入力途中で
エンターキーを押下すると文字が中途半端に切れてしまいます。

そこの部分は次回修正したいともいます。

でわでわ。。。


Java Basic インターフェース・抽象クラスの作り方

やってみた!CommandIFを作る

余計な音が入っています。

インターフェース・クラスの作成方法

/** インターフェースの作成 */
public interface A {
   // 抽象メソッドを定義します。
   public abstract void test01();
   // 上と同様
   public void test02();
   // 引数など書き方は普通のメソッドと一緒
   public String test03(int i);
}

抽象クラスの作成方法

/** 抽象クラスの作成 */
public abstract class A {
    // 抽象メソッドはインターフェースと同じ
    public abstract void test01();
    // 通常のメソッドの実装もOK
    public void test02() {
       System.out.println("Hello");
    }
    public A() {
       // コンストラクタ
    }
}

上の抽象クラスは、親クラスとして定義して、こクラスで似た様な処理
なんども同じ処理を呼び出したいときに使用します。

/** 子クラスサンプル */
public B extends A {
    // 親クラスの抽象メソッドをオーバーライドする必要がある
        @Override
    public void test01() {
                // 親クラスのメソッドを呼び出す
        test02();
    }
    // そのほかのメソッドなど
}

上記の様に親子関係を作成し、「A家」でtest01()の伝統を引き継いでいく・・・
みたいな感じです。
GOFのデザインパターン」などを見ると参考になると思います。

関連ページ一覧

<Java Basic>

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜「四則計算」
  3. Java Basic Level3 〜About String class〜「Stringクラス」
  4. Java Basic Level 4〜Boolean〜「TrueとFalse」
  5. Java Basic Level 5〜If Statement〜「IF文の書き方など」
  6. Java Basic Summary from Level1 to 5「Level1〜5までの複合技」
  7. Java Basic Level 6 〜Traning of If statement〜「IF文の練習」
  8. Java Basic Level8 〜How to use for statement〜「For文の使い方」
  9. Java Basic Level 8.5 〜Array〜「配列について」
  10. Java Basic Level 10 〜While statement 〜「While文について」
  11. Java Basic Swing〜オブジェクト指向〜「オブジェクト指向の考え方1」
  12. Java Basic Swing Level 2〜オブジェクト指向2〜「同じく、考え方2」

<クラスの種類>

http://zenryokuservice.com/wp/2018/05/14/java-basic-%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%A8%E3%81%AF-inputsreamreader%E3%80%9Cstep2_1%E3%80%9C/

<インターフェース>

http://zenryokuservice.com/wp/2018/06/01/java-basic-%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E3%83%BB%E6%8A%BD%E8%B1%A1%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9/

<実装サンプル>

http://zenryokuservice.com/wp/2018/06/16/java-bassic-%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91-%E3%80%9C%E3%82%B5%E3%83%B3%E3%83%97%E3%83%ABrpgmain%E3%82%AF%E3%83%A9%E3%82%B9%E3%80%9C/

http://zenryokuservice.com/wp/2018/05/20/java-basic-%E3%83%9F%E3%83%8B%E3%82%B2%E3%83%BC%E3%83%A0%E4%BD%9C%E6%88%90-%E3%80%9C%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%82%B2%E3%83%BC%E3%83%A0%E3%80%9C/

Java Basic ミニゲーム作成 〜Step3_2〜

前回は、中途半端な感じでした。
とりあえずで"bye"と入力すると終了するコンソールアプリを作成しました。
今回は、タイトル表示までやりました。
ただし、クラス単体では動きません。。。
必要なクラスは以下になります。
RpgMain
ViewStatus
TitleView

RPGMainでゲームの処理をstaticで作成しています。
1.初期化 #init
RpgMainクラスを生成(new)して
メンバメソッドinitialize()で初期画面の
・標準入力を受け付ける
・ファイルの読み込み&出力
※ラムダ式を使用してみました(笑)
・初めの画面管理オブジェクト生成
2.ゲームループ #gameLoop
・無限ループ開始
・コマンド実行処理(Mainクラス)
※画面管理オブジェクトのexecuteを実行
・更新後の画面を表示
3.終了処理 #terminated
・リソース(クラス)のメモリ解放

「static」をつけているのは、Mainメソッドから
直接呼ぶ様にしたかったからです。
→メインメソッドとクラスの
メンバメソッドを分ける

そして、初めの画面管理オブジェクトのTitleView
は「ViewStatus」という抽象クラスを実装しています。
抽象クラスについてはのちに説明いたしますが、
インターフェースとクラスの中間にいるクラスです。
具体的に、抽象メソッドと実装するメソッド
両方を持っております。
インターフェースと違いimplemensではなく
「extends」(継承)する必要があります。

さらにちょっと厄介なインナークラスに
インターフェースを作成しています。

ViewStatus以外で、使用することのないインターフェース
なのでそうしたのですが、普通は外部に作成します。
クラスが増えない様に、インナークラスにしたのですが
やっぱり微妙でした、なんかのタイミングで修正しようと思います。
インポートするときはxxxxViewStatus.ViewCommandの様に
やります。

とりあえず、今回はここまでにします。

次回は

Java Basic ミニゲーム作成 〜コンソールゲーム〜

関連ページ

前回

Java Basic ミニゲーム作成 〜コンソールゲーム〜

インターフェースについて

Java Basic インターフェース・抽象クラスの作り方

ページ一覧

Mapping of Java Bassic etc …~Java Basicなど記事一覧~



Java Basic インターフェース 〜Step2_3 〜

インターフェース・クラス、
ポリモーフィズムについて学習していきます。
ポリモーフィズムは、日本語で「多様性」と言う意味です。
よく聞く「デザインパターン」と言うのはこのポリモーフィズムを応用した設計手法のことです。

余談

JavaAPIの中にはすでに実装されています。
Listインターフェース・クラスにある。iterate()はイテレートパターンと言うデザインパターンの実装になります。

インターフェース・クラス

インターフェース・クラスは前回使用したListインターフェースがこれにあたります。

List<String> list = new ArrayList<String>();

List<String> list = new LinkedList<String>();

上のように、別クラスを同じ型(クラス)変数として使用することができます。

これがまずは、基本的な考え方になります。

自作のインターフェースを使う

似たような形で、インターフェースを使ってみます。
概要としては以下のようなクラスを用意します。

  1. TestIF(インターフェース)
  2. TestCls1(インターフェースの実装クラス)
  3. TestCls2(インターフェースの実装クラス)

これを、変数testに格納して起動してみます。コードは下のようなものです。

public static void main(String[] args) {
    // インターフェースクラスを宣言する
    TestIF test1 = new TestCls1();
    test1.hello();
    TestIF test2 = new TestCls2();
    test2.hello();
}

作成するクラスなどは、Githubにアップしてあるのでそちらを参照ください。ルートになるフォルダはこちらになります。

インターフェースの書き方

public interface インターフェース名 {
   /** 抽象メソッドの定義 */
   // implementsするクラスで処理内容を記述
   public abstract void execute();
      // 上のメソッドと同じ(メソッド名は違う)
   public void setName();
}

クラスへの実装(implements)方法

public class クラス名 implements インターフェース {
   // クラスの記述
   // 上記の抽象メソッドを実装する
     @Orverride
   public 抽象メソッド() {
      //処理
     }
}

インターフェースを使用した。ポリモーフィズム
サンプルコードには上記の実装方法を使用しています。
実際の使用の仕方はサンプルを見てください。

インターフェースを実装したクラスは、そのインターフェース型の
変数として使用することができます。
つまり、同じ名前のメソッドを呼び出した時に違う処理を
実行することがでいます。
下の「action()」の実行結果が以下になります。
listにはPlayer型のクラスが設定されています。
処理詳細は、サンプルコードをご覧ください。

次回、これだけではわかりづらいかもしれないので
他もパターンも記載いたします。

Java Basic API Listの使い方 〜Step2_2〜

Listと配列の違い

よく世間では「リスト」と言う言葉を使用します。「〜のリスト作っておいて!」などといったりします。

まずは実装してみたので、こんな感じかな?と言うのをみてもらうのが早いと思います。

このリストはJavaでのプログラムでも存在していて完全クラス名はjava.util.Listです。
クラスと言いましたが、これは「インターフェース・クラス」実態のないクラスです。これは実態のあるクラスを格納できる変数だと思ってもらえれば、ある程度はわかりやすいと思います。

List<String> list1 = new ArrayList<String>();

他にも下のような実装もできます。

List<String> list1 = new LinkedList<String>();

JavaDocにある既知の全ての実装クラスと言う部分に記載のあるクラスは同じように扱うことができます。

【配列の扱いあれこれ】

配列を使用して様々なデータを検証、編集など
色々な処理を行いますが何かと不便なこともあります。
String[] args = new String[5];
の様に初期化した場合→test01();

サンプルソースのダウンロードができます。

この場合は、配列の数が決まるので困る時があります。
例:標準入力を受けるとき
byte[] b = new byte[5];
System.in.read(b);

上記の場合は、5文字までを受け取ることができます。
少なかったり多かったりすると上手くないのです。。。
なので前回はBufferedReaderを使用してそこを解消しました。

そこで、初めの配列(byte[] b)をString[], int[]などに変更した場合
かつ標準入力出ない場合はどうしたら良いでしょうか?

【Listクラスを使用する】

ここで、Listが出てきます。完全修飾名(完全クラス名)は
「java.util.List」クラスです。正しくはインターフェースクラスになります。
このインターフェースは以下のクラスに実装されています。
他にもあるけれど、使用頻度の高いものを記載します。

java.util.ArrayListクラス(完全修飾名)
java.util.LinckedListクラス(完全修飾名)
java.util.Vectorクラス(完全修飾名)

これらのクラスにはclass名の後に「implements java.util.List」
が記載されています。

これが「実装する」という意味です。
// インターフェースの定義
public interface List { ....}の様に記載します。
実際のjava.util.Listインターフェースの内容は
Eclipseを使用しているならListの文字の上で「F3」を押下すると
ソースを見ることができます。
実際のインターフェース定義は以下になります。

public interface List<E> extends Collection<E> {
    // Query Operations

インターフェース定義でも「extends」とありますが
とりあえず置いておきます。

ではインターフェースって何?となると思います。
インターフェースはクラスに実装(implements)することにより
インターフェースで複数のクラスを一つの変数で扱えます。

例として、ListはArrayListとLickedListをListの変数で使用できます。
List<String> list = new ArrayList<String>();
// OK牧場(笑)
List<String> list1 = new LinkedList<String>();
の様に別のクラスでも同じ変数で使用することができます。
【追伸】
List<変数の型>の「変数の型」の部分は、ジェネリクスと言います。
コードが長くなってくるとこのリストの中身はなんだった?
とわからなくなってしまいます。それを解消したのがこの
「ジェネリクス」です。
その他Map, Set, Vectorなどで使用します。

でわでわ

Java Basic クラスとは〜Step2_1〜

イントロダクション

Javaでの文法をちょっとやると「クラス」という言葉が出てきます。「インスタンス」とか、「オブジェクト」なんて言葉も一緒に出てきます。

クラスとは

今までに、書いてきた、プログラム(クラス)は下のようにmainメソッドだけでした。

public class AAA {
   public static void main(String[] args) {
   }
 }

なので、クラスをクラスとして使用していませんでした。

具体的にはクラスには以下の要素があり、それぞれの機能を持たせることができます。

1:フィールド変数
2:メソッド

これらを使用して現実にある様々なものを表現できます。

例えば人間を表現してみます。※ほんのさわり部分のみです

public class Human {
   /** 年齢 */
   private int age;
   /** 性別 */
   private int sex;
   /** 挨拶する */
   public void greet() {
       System.out.println("Hello!");
   }
}

人間にはその人の年齢があり、性別他にもたくさんありますが、それぞれ「人間」と言う生き物に共通する要素があります。
それを「フィールド変数」として定義してやります。
そして、取りうる行動を「メソッド」として表現することができます。

例えば自転車ならば。。。

public class Bicycle {
    /** ハンドルのサイズ */
    private double handleSize;
    /** 車輪のサイズ */
    private double wheelSize;
    /** スピード */
    private double speed;
    /** 停止しているフラグ */
    private boolean isStop;
    /** 自転車をこぐ */
    public double start(int power) {
       speed = power * wheelSize;
       isStop = false;
    }
    /** 自転車の動き */
    public void bicybleState() {
        // 何かしらの処理。。。
    }
}

とまぁキリがなくなってきたので、ここら辺で自転車の実装を終わりにしますが、つまるところは。。。

「リアルにあるもの」を「クラス」として表現できる

と言うところがクラスの存在意義です。
そして、クラスがオブジェクト指向の考え方の基本になります。
そして、実行してみました。コードはこちらにあります

インスタンスとは

クラス(ファイルに記述したもの)の「コンストラクタ」の処理を通った後に出来る、オブジェクト。

<例>

ホームページにログインするとインスタンスが1個作られます。→ログイン処理でユーザーをあらわすクラスのコンストラクタでDBから取得した情報を保持します。この保持するためのオブジェクトの事をインスタンスと呼びます。

オブジェクトとは

構造体、クラスの事。データをセットしたり、ゲットしたり、何かの処理を行ったりします。構造体はクラスと同じ様な意味です。細かい所は混乱するので省きます。

オブジェクトはインスタンス化出来る。→コンストラクタを通らなければオブジェクトで、通ればインスタンス。

<サンプルコード>

public class MyCls {
   //コンストラクタ
   public MyCls() {
   this.age = 3;
   }

   //フィールド変数
   private String name;
   private int age;
   //メソッド
   public void setName(String name) {
  this.name = name;
   }
}

カプセル化とは

上記の様にフィールドへのアクセス(name)にはクラスの外からアクセス出来なくする事MyCls.name = “”;はエラーになる。

ちなみにフィールドをpublic String name;と書くと外部からアクセス出来る。MyCls.name = “”;はエラーにならない

クラスの構成のコメントをつけております。

サンプルはこちら

/** 外部の提供されているクラスをインポートする */
package jp.zenryoku.sample.cls;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
* javaAPIの使い方
* @author takunoji
*/
// クラス定義
public class Step2_1 {
// フィールド変数:クラスの全てのメソッドからアクセスできる
private String FIELD_HENSU="クラスの外からはアクセスできません。";
public String FIELD_HENSU2="クラスの外からはアクセスできます。";

// メインメソッド(必ずこの書き方になる)
public static void main(String[] args) {
    Step2_1 step = new Step2_1();
    // 入力を受け取り切らない場合は次のStreamに読み込まれる
    //123456step.arrayTest1();
    step.arrayTest2();
}
// 自作のメソッド(メンバメソッドともいう)
public void arrayTest1() {
   System.out.println("test1 入力開始");
   // バイト型の配列をサイズ5で作成する
   byte[] moji = new byte[5];
 // エラーハンドル用のくくり
   try {
    // 標準入力から入力を受け取る
         System.in.read(moji);
   } catch(Exception e) {
         e.printStackTrace();
   }
 // 入力は「バイト型」のデータなのでString型(参照型)を生成する
   System.out.println("入力じた文字:" + new String(moji));
}

public void arrayTest2() {
    System.out.println("test2 入力開始");
    // 読み込み用のクラスを宣言する
    BufferedReader read;
  // InputSreamReaderからBufferedReaderを作成する
  // System.in→標準入力、読み込むために上のクラスでラッップ(包む)して
  // 使用する。ラップとは System.inをInputSreamReaderで包む(拡張)する
  // ことを言います。
    read = new BufferedReader(new InputStreamReader(System.in));
    String line = "";
    try {
     // BufferedReader.readLineメソッドで1行読む。
     // Fileなどを読み込む時にも使用する
           line = read.readLine();
    }catch(IOException e) {
            e.printStackTrace();
    }
         System.out.println("入力じた文字:" + line);
    }
}

「public class クラス名」全ての人がアクセスできるクラスですよ、と定義する
「private class クラス名」クラスの中からのみアクセスできるクラスと定義する

「public 返却値 メソッド名」クラスの外からもアクセスできるメソッド
「private 返却値 メソッド名」クラスの中からのみアクセスできるメソッド

フィールド変数に関して、今回は使用していません。

Systemクラスについて
標準入力、出力、Javaの強制終了などJavaシステムの
基盤的なアプリケーションの機能を実装している。

クラス 変数名 = new クラス名();という書き方では
メソッドを使用できません。→その様に実装しているからです。

このクラスにあるメソッドはスタティックメソッドと呼ばれます。
public static out; // フィールド変数です。
プログラム上では「System.out.println();」と使用してます。
Systemクラスのフィールドout(PrintSream)のメソッド
「println()」メソッドを使用して標準出力に文字を表示しています。
逆に、「in」は標準入力です。

スタティックメソッドはクラスをnewしないで直接
クラス名.メソッド名の形で呼び出します。